Cómo utilizar el grupo de conexiones de Redis en el idioma Go
El servidor de base de datos tiene una cantidad limitada de recursos. Si no utiliza estos recursos por completo, puede aumentar el rendimiento utilizando más conexiones. Una vez que se utilizan todos los recursos, no puede aumentar el rendimiento agregando más conexiones. De hecho, cuando la carga de la conexión es alta, el rendimiento comienza a disminuir. A menudo, puede mejorar la latencia y el rendimiento limitando la cantidad de conexiones de bases de datos para que coincidan con los recursos disponibles.
Cómo usar el grupo de conexiones de Redis en Go
Si no utilizamos el grupo de conexiones, debemos crear una conexión, enviar y recibir datos y cerrar la conexión cada vez que se transfieran los datos. . En escenarios de aplicación donde la cantidad de concurrencia no es alta, básicamente no habrá problemas. Una vez que aumenta la cantidad de concurrencia, generalmente encontrará los siguientes problemas comunes:
El rendimiento generalmente no aumenta
El sistema consume una gran cantidad de recursos de CPU
Una vez que la red tiembla, se generará una gran cantidad de TIME_WAIT y el servicio debe reiniciarse regularmente o la máquina debe reiniciarse regularmente
El servidor funciona de manera inestable y el QPS a veces es alto y a veces low
Para resolver estos problemas, necesitamos utilizar un grupo de conexiones. El grupo de conexiones es una idea muy simple. Durante la inicialización, se crea una cierta cantidad de conexiones y todas las conexiones largas se almacenan primero. Luego, quien necesite usarlas puede tomarlas desde aquí y volver a colocarlas inmediatamente después de terminar el trabajo. Si la cantidad de solicitudes excede la capacidad del grupo de conexiones, se ponen en cola, se degradan a conexiones cortas o se descartan directamente.
Trampas en el uso de grupos de conexiones
Recientemente, en un proyecto, necesitaba implementar un servidor web simple para proporcionar una interfaz HTTP para Redis y proporcionar resultados de retorno JSON. Considere utilizar Go para implementar esta función.
Primero, visité el controlador oficial Go Redis recomendado por Redis, que tiene dos proyectos Star oficiales:
El paquete Radix.v2 está dividido en múltiples subpaquetes, cada subpaquete paquete Cada paquete de software tiene un subpaquete.
El paquete de software Radix.v2 está dividido en múltiples subpaquetes según sus funciones, cada subpaquete está en un subdirectorio separado y la estructura es muy clara.
Como quería mantener este proceso de bifurcación simple y hacer solo una cosa, elegí implementar un grupo de Redis yo mismo antes de sumergirme en la implementación del grupo de Radix.v2. Más tarde, descubrí que mi grupo de Redis se basaba en el mismo principio que el grupo Radix.v2 basado en canales, y también encontré el mismo problema).
Pero durante la prueba, descubrí un problema extraño. Durante el proceso de solicitud, a menudo se informan errores de EOF. Y este tipo de error es probabilístico. Hay un problema en un minuto y todo estará bien al minuto siguiente. A través de pruebas repetidas, descubrí que este error es regular. Cuando el programa está inactivo por un período de tiempo y luego solicita continuamente, fallará tres veces y luego la solicitud tendrá éxito y el tamaño de mi grupo de conexiones se establece en 3. Después de un análisis más detallado, el programa estuvo inactivo durante 300 segundos y luego la solicitud fallaba. Descubrí que mi servidor Redis estaba configurado con un tiempo de espera de 300, por lo que el problema estaba claro. Me di cuenta de que configuré el tiempo de espera del servidor Redis en 300. Cuando se agota el tiempo de conexión, el servidor Redis se desconecta automáticamente. Los clientes reciben errores EOF de solicitudes de tiempo de espera.
Luego miré el código fuente del paquete del grupo Radix.v2 y descubrí que la biblioteca en sí no detecta malas conexiones, así que la reemplacé con un nuevo servidor{location/pool{content_by_lua_block {localredis= require "resty.redis" localred=redis:new()localok,err=red:connect("127.0.0.1",6379)ifnotokthenngx.say("failedtoconnect:",err)returnendok,err=red:set (" hola ", "world")ifnotokthenreturnendred:set_keepalive(10000,100)}}}
Encontré el método set_keepalive, verifique la documentación oficial, el prototipo del método es la sintaxis: ok, err = red:set _keepalive( max_idle_timeout, pool_size) Parece que lo que nos falta es el parámetro max_idle_timeout, luego rastreamos el código fuente más a fondo para ver qué sucede allí y asegurarnos de que la conexión sea válida.
function_M.set_keepalive(self,...) localsock=self.sockifnotsockthenreturnnil, "noinitialized "endifself.subscribedthenreturnnil, "subscribedstate "endreturnsock:. setkeepalive(...) end
En este punto, hemos entendido claramente que TCP utiliza un mecanismo de mantenimiento de latidos.
Entonces, a través de algunas discusiones con los autores de Radix.v2, decidimos usar nuestro propio mecanismo de latido en la capa de Redis para resolver este problema.
4. Solución final
Después de crear el grupo de conexiones, inicie una rutina y envíe PING al servidor Redis cada tiempo de inactividad, donde el tiempo de inactividad es ligeramente menor que la configuración de tiempo de espera del servidor Redis. . La parte de inicialización del grupo de conexiones del código es la siguiente:
p,err:=pool.New("tcp",u.Host,currency)errHndlr(err)gofunc(){for{p. Cmd("PING" )time.Sleep(idelTime*time. Second)}}()
Parte del código para usar Redis para transmitir datos es el siguiente:
funcredisDo( p*pool..interface{})(respuesta *redis.Resp,errerror){respuesta=p.Cmd(cmd,args...)iferr=respuesta.Err;err!=nil{iferr!=io.EOF{ Fatal.Println("redis",cmd,args , "erris",err)}}return}
Entre ellos, el grupo de conexiones Radix.v2 realiza internamente la recuperación de conexiones en el grupo.
El código es el siguiente:
//Cmd obtiene automáticamente un cliente del grupo, ejecuta el comando dado//(devuelve su resultado) y vuelve a colocar el cliente en la función del grupo (p*Pool)Cmd(cmdstring,args..interface{})*redis.Resp{c,err: =p. Get()iferr!
De esta manera, tenemos un mecanismo de retención, no se producirá un tiempo de espera de conexión y todas las conexiones del grupo de conexiones de Redis son conexiones disponibles. Este código aparentemente simple resuelve perfectamente el problema del tiempo de espera de las conexiones en el grupo de conexiones. Al mismo tiempo, la conexión se volverá a conectar automáticamente incluso si se reinicia el servidor Redis.