¿Qué hacer si Redis está bloqueado?
No bloquear en un solo hilo, análisis y respuesta al problema de retraso de Redis
El bucle de eventos de Redis se procesa en un solo hilo. Como programa de un solo hilo, es necesario. para garantizar que el retraso en el procesamiento de eventos sea muy corto, de esta manera, las tareas posteriores en el bucle de eventos no se bloquearán;
Cuando la cantidad de datos en redis alcanza un cierto nivel (por ejemplo, 20G). ), el impacto del bloqueo de operaciones en el rendimiento es particularmente grave;
¿Cuáles son los escenarios que consumen mucho tiempo en redis y cómo lidiar con ellos?
Comandos que consumen mucho tiempo que causan el bloqueo
teclas, ordenación y otros comandos
teclas El comando se utiliza para encontrar todas las claves que coinciden con el patrón de un patrón determinado. Su complejidad temporal es O (N), donde N es el número de claves en la base de datos. N es el número de claves en la base de datos. Cuando el número de claves en la base de datos alcance los 10 millones, este comando hará que los subprocesos de lectura y escritura se bloqueen durante varios segundos;
Cuando el número de claves en la base de datos alcance los 10 millones, este comando provocará que los hilos de lectura y escritura para bloquear Bloquear durante varios segundos.
Los comandos similares incluyen la clasificación Sunion y otras operaciones;
¿Qué debe hacer si los requisitos de su negocio requieren el uso de operaciones de clave, clasificación, etc.?
Solución:?
En términos de diseño arquitectónico, existe un truco para "desviar", que consiste en separar las solicitudes que procesan solicitudes rápidas de aquellas que procesan solicitudes lentas. los lentos afectarán lo rápido y harán que lo rápido no sea rápido; esto es muy obvio en el diseño de redis. La operación de memoria pura de redis y el procesamiento de eventos IO sin bloqueo de epoll se pueden realizar en un hilo, mientras que la persistencia. y AOF Las operaciones que consumen mucho tiempo, como la reescritura y la sincronización de datos maestro-esclavo, se manejan en un solo proceso, lo que no reducirá la velocidad;?
De manera similar, dado que necesitamos utilizar operaciones que consumen mucho tiempo, como como claves, luego los separaremos, como un único nodo esclavo de Redis, que se usa especialmente para operaciones que requieren mucho tiempo, como claves y clasificación. Estas consultas generalmente no son servicios en línea en tiempo real. la consulta. Lo más importante es poder completar la tarea, ¡y no tiene ningún impacto en la velocidad de las tareas en línea que consumen mucho tiempo!
comando smembers
El comando smembers se utiliza para obtener el conjunto completo de conjuntos. Su complejidad temporal es O(N), donde N es el número de conjuntos en el conjunto;
Si la colección contiene millones de dólares en datos, una sola adquisición también provocará que el hilo de procesamiento de eventos se bloquee durante mucho tiempo;
Solución:?
Con clasificación, clave y otros comandos Diferente, miembro puede ser un comando de uso frecuente en escenarios de aplicaciones en línea en tiempo real, y las técnicas de descarga no son adecuadas aquí, debemos pensar más en el nivel de diseño;?
En tiempo de diseño, podemos controlar El número de conjuntos generalmente se controla dentro de 500;?
Por ejemplo, si se usa una clave para almacenar registros durante un año y la cantidad de datos es grande, podemos use 12 claves para almacenar 12 registros mensuales respectivamente, o use 365 claves para almacenar registros diarios, controle el tamaño de la colección dentro de un rango aceptable;
Si no es conveniente dividir la colección en múltiples. subcolecciones e insiste en usar una colección grande para almacenar, entonces puede considerar usar la clave SRANDMEMBER [recuento] al recuperar la colección, devuelve aleatoriamente la cantidad especificada de elementos en la colección. elementos en la colección, este comando no es adecuado;
comando guardar
El comando guardar utiliza el hilo de procesamiento de eventos para conservar datos cuando la cantidad de datos es grande, causará; el hilo se bloquea durante mucho tiempo (en nuestra producción, se guarda en la memoria de Reids. 1 G de datos tarda aproximadamente 12 segundos), lo que provoca que todo el Redis se bloquee;
El comando de guardar utiliza un evento procesar el hilo para conservar datos Cuando la cantidad de datos es grande, el hilo se bloqueará durante mucho tiempo (en nuestra producción, guardar 1 G de datos en la memoria reids toma aproximadamente 12 segundos), lo que hace que todo el redis sea. bloqueado;
El comando guardar utiliza subprocesos de procesamiento de eventos para conservar los datos.
Guardar bloqueará el hilo de procesamiento de eventos. Ni siquiera podemos usar redis-cli para ver el estado actual del sistema, por lo que no podemos saber "cuándo finaliza el guardado y cuánto se guarda"; /p>
Solución Solución:?
No puedo pensar en ningún escenario de aplicación que requiera usar el comando guardar. Siempre que se requiere persistencia, bsave es una opción razonable (por supuesto, este comando también traerá algunos problemas, que discutiremos más adelante);
Bloqueo debido a bifurcación
Cuando redis necesita para realizar operaciones que requieren mucho tiempo, creará un nuevo proceso para realizar estas operaciones, como la persistencia de datos:?
Después de habilitar la persistencia de RDB, cuando se alcance el umbral de persistencia, redis bifurcará un nuevo proceso para realice persistencia y adopte la estrategia de copia en escritura del sistema operativo, es decir, el proceso hijo comparte la página **** del proceso padre. Si se modifica la página del proceso principal (4K por página), el proceso principal creará una copia de la página por sí mismo sin afectar al proceso secundario;
Cuando bifurca un nuevo proceso, no es necesario copiar el contenido de datos ****, pero se copiará la tabla de páginas de memoria del espacio del proceso anterior si el espacio de memoria es 40G (. teniendo en cuenta que las entradas de la tabla de cada página consumen 8 bytes), entonces el tamaño de la tabla de páginas es 80 M. Esta copia lleva tiempo. Si está utilizando una máquina virtual, especialmente un servidor virtual Xen, llevará más tiempo;?
Cuando bifurca un nuevo proceso, debe copiar las tablas de páginas del espacio de proceso anterior, pero debe copiar las tablas de páginas del espacio de proceso anterior.
Probado en los nodos de servidor que poseemos, el bgsave de datos de 35G se bloqueará instantáneamente durante más de 200 ms;
Del mismo modo, las siguientes operaciones también tienen bifurcaciones de proceso;
El principal La primera sincronización de datos del nodo al nodo esclavo: cuando el nodo maestro recibe la solicitud de sincronización del nodo esclavo, se generará un nuevo proceso para sincronizar los datos de la memoria.
Reescritura del registro AOF: utilizando el método de persistencia AOF, se creará un nuevo proceso para reescribir el archivo AOF (el archivo existente no se leerá durante la reescritura, sino que se utilizarán directamente los datos en la memoria para escribir registros de archivo; );
Solución:?
Para hacer frente al impacto de la replicación de tablas de páginas de gran memoria, existen algunas medidas disponibles:
p>
Controlar la cantidad máxima de memoria de cada instancia de Redis;
Controlar la cantidad máxima de memoria de cada instancia de Redis sin afectar la capacidad de la memoria;
Sin afectar la capacidad de la memoria, controlar la cantidad máxima de memoria para cada instancia de Redis si afecta la capacidad de la memoria.
Sin imponer demasiadas restricciones a la bifurcación, puede controlar el retraso de la bifurcación en función de la cantidad de memoria;
Generalmente se recomienda no exceder los 20 G, que se pueden determinar Según su propio servidor, determine el rendimiento (cuanto mayor sea la memoria, mayor será el tiempo de persistencia, más tiempo se tardará en copiar la tabla de páginas y mayor será el tiempo de bloqueo del bucle de eventos).
La recomendación dada por Sina Weibo es no exceder los 20G, y la prueba que realizamos en la máquina virtual, para asegurarnos de que los fallos en la aplicación no sean obvios, puede ser inferior a 10G;
Utilice páginas de memoria grandes, la página de memoria predeterminada usa 4 KB, por lo que cuando use una memoria de 40 G, la tabla de páginas será de 80 M, y si cada página de memoria se expande a 4 M, la tabla de páginas solo será de 80 K; de esta manera, casi no hay bloqueo al copiar la tabla de páginas. También mejorará la tasa de aciertos del búfer rápido de la tabla de páginas TLB (Translation Lookup Buffer); sin embargo, hay un problema con páginas de memoria grandes durante la copia; -proceso de escritura, siempre que cualquier elemento en la página se modifique rápidamente, el bloque Se requiere una copia (la granularidad del mecanismo COW es la página), lo que consumirá más espacio de memoria durante el proceso de copia en escritura; p>
Utilice una máquina física;?
Si puede elegir, y una máquina física es, por supuesto, la mejor solución, que es menos problemática que todos los métodos anteriores;
Por supuesto, hay muchas formas de implementar la virtualización, excepto los sistemas Xen, la mayoría del hardware moderno puede copiar rápidamente tablas de páginas;
Pero la virtualización de la empresa es generalmente un conjunto completo. Lo que está en línea no cambiará debido a nuestro servidor personal. Si solo nos enfrentamos a Xen, solo podemos pensar en cómo usarlo;
Cancelar la creación de nuevos procesos, no usar persistencia y no. proporcionar nodos maestros Consulta sobre; el plan de implementación es el siguiente:
1) Utilice solo una máquina, no utilice persistencia y no cuelgue nodos esclavos. Esta es la más simple y no genera nuevos procesos; sin embargo, dicha solución solo funciona con almacenamiento en caché;
¿Cómo puedo usar esta solución para alta disponibilidad?
Para lograr una alta disponibilidad, puede colgar una cola de mensajes en la parte frontal de Redis de escritura y usar pub-sub en la cola de mensajes para la distribución para garantizar que cada operación de escritura caiga en al menos 2 nodos; porque Los datos de todos los nodos son los mismos, por lo que solo es necesario usar un nodo para la persistencia y este nodo no proporciona consultas externas;?
2) "Maestro-esclavo": habilitar en el maestro nodo Persistencia, el nodo maestro no proporciona consultas al mundo exterior, las consultas las proporcionan los nodos esclavos y los nodos esclavos no proporcionan persistencia, de esta manera, todas las operaciones de bifurcación que consumen mucho tiempo se realizan en el nodo maestro; las solicitudes de consulta son proporcionadas por los nodos esclavos;?
El problema con esta solución es ¿qué sucede cuando falla el nodo maestro?
La solución simple es que el nodo maestro es irreemplazable. Cuando el nodo maestro falla, el clúster de Redis solo podrá proporcionar lecturas al mundo exterior, pero no podrá proporcionar actualizaciones cuando el nodo maestro se reanude con normalidad; operación, la operación de actualización continuará; para las operaciones de actualización anteriores, MQ se puede usar para el almacenamiento en caché. Cuando el nodo maestro vuelva a la operación normal, digiere las solicitudes de escritura durante la falla;
Si el nodo maestro vuelve al funcionamiento normal; El nodo esclavo falla, el clúster de Redis no podrá proporcionar lecturas al mundo exterior, solo puede proporcionar actualizaciones;
Si el nodo esclavo falla, el clúster de Redis no podrá proporcionar lecturas al mundo exterior. mundo exterior, pero sólo puede proporcionar actualizaciones.
Si utiliza el Sentinel oficial para actualizar un nodo esclavo a un nodo maestro, la implementación general es relativamente complicada; necesita cambiar la configuración IP de los nodos esclavos disponibles y eliminarlos de los nodos consultables. para que la carga de consultas de front-end ya no recaiga en el nuevo nodo maestro;
Bloqueo de persistencia
Realizar persistencia
Realizar persistencia (AOF / RDB instantánea) tendrá un impacto negativo en el sistema El impacto en el rendimiento es grande, especialmente cuando hay otras operaciones en el nodo del servidor que leen y escriben en el disco (por ejemplo, leer y escribir discos en el nodo del servidor).
ej., el servicio de aplicación y el servicio Redis se implementan en el mismo nodo, y el servicio de aplicación registra los mensajes entrantes y salientes en tiempo real; debe intentar evitar activar la persistencia de Redis en nodos que ya están muy cargados con IO);
Persistencia del subproceso, la escritura del subproceso entra en conflicto con el fsync del proceso principal, provocando el bloqueo
En el nodo donde está habilitada la persistencia AOF, cuando el subproceso El proceso realiza reescritura AOF o persistencia RDB, Redis La consulta se retrasa o incluso se bloquea durante mucho tiempo, y Redis no puede proporcionar ninguna operación de lectura y escritura en este momento;
Análisis de causa:?
El servicio Redis configura appendfsync cada segundo, es decir, el proceso principal llama a fsync una vez por segundo (), lo que requiere que el kernel escriba "realmente" los datos en el hardware de almacenamiento. Sin embargo, dado que el servidor está realizando muchas E/S, las operaciones fsync()/ del proceso principal se bloquean, lo que eventualmente provoca que el proceso principal de Redis se bloquee.
redis.conf dice esto:?
¿Cuando la política fsync de AOF está configurada en siempre o cada segundo y el proceso de guardado en segundo plano (guardado en segundo plano o reescritura en segundo plano del registro AOF) se está ejecutando?
En algunas configuraciones de Linux, Redis puede bloquearse durante un tiempo excesivamente largo al llamar a fsync(). Tenga en cuenta que actualmente no existe ninguna solución para este problema.
Tenga en cuenta que actualmente no existe ninguna solución para este problema, ya que incluso ejecutar fsync en un hilo diferente bloqueará nuestra llamada write(2) sincrónica.
Actualmente, incluso ejecutar fsync en un hilo diferente bloquea nuestra llamada write(2) sincrónica.
Establezca no-appendfsync-on-rewrite en sí, luego, cuando el proceso secundario realice la reescritura AOF, el proceso principal no llamará a la operación fsync(). Tenga en cuenta que incluso si el proceso no llama a fsync; (), el sistema El kernel también escribirá datos en el disco duro en el momento apropiado (el tiempo predeterminado de Linux es hasta 30 segundos) de acuerdo con su propio algoritmo.
El problema de esta configuración es que cuando ocurre un fallo, la cantidad de datos que se pueden perder puede exceder los 30 segundos como máximo, en lugar de 1 segundo.
Cuando el proceso hijo; AOF se reescribe, la sincronización del sistema provocará el bloqueo de escritura del proceso principal
Vamos a resolverlo:?
1) Motivo: una gran cantidad de operaciones de IO escriben (2) ¿pero no se llama activamente a ninguna sincronización?
2) ¿Hay muchos datos sucios en el buffer del kernel?
3) ¿Tarda demasiado en sincronizar el sistema?
4) ¿Provoca que la operación Redis Write aof Log Write(2) se bloquee?
5) Como resultado, el siguiente evento de redis de un solo subproceso no se puede procesar y todo el redis se bloquea (el procesamiento de eventos de redis se realiza en un subproceso, en el que se escribe un registro de escritura(2) se llama en modo de bloqueo síncrono, a diferencia de la escritura sin bloqueo (2) en la red)
El motivo 1): Este es un problema antes de redis2.6.12. Cuando se reescribe AOF, se ha reescrito. Inmerso en llamar a write(2), el propio sistema activa la sincronización.
Otro motivo: el IO del sistema está ocupado, por ejemplo, otra aplicación está escribiendo en el disco;
Solución:?
Controlar el tiempo del sistema llamada de sincronización; cuando hay muchos datos que deben sincronizarse, llevará mucho tiempo acortar el tiempo y controlar la cantidad de datos que deben sincronizarse cada vez; vm.dirty_background_ratio) o por valor (vm.dirty_bytes) a través de la configuración (generalmente configurado en sincronización de 32 M);
Después de 2.6.12, AOF rewrite 32M llamará activamente a fdatasync
Además, Redis no llamará a Write(2) primero porque simplemente existe en el caché, por lo que ganó; No bloquees. Pero si sigue siendo así después de más de dos segundos, se forzará la llamada a write(2), incluso si se bloquea redis.
Bloqueo al fusionar datos después de completar la reescritura de AOF
Durante el proceso bgrewriteaof, todas las nuevas solicitudes de escritura se escribirán en el archivo AOF antiguo al mismo tiempo y se colocarán en el AOF. buffer, una vez completada la reescritura, el hilo principal fusionará el contenido en un archivo temporal y luego le cambiará el nombre a un nuevo archivo AOF, por lo que el proceso de reescritura continuará imprimiendo "Tamaño del búfer AOF de fondo: 80 MB, fondo". Tamaño del búfer AOF: 180 MB" para monitorear esta parte del registro. Este proceso de fusión se está bloqueando. Si se genera un búfer de 280 MB, Redis se bloqueará durante 2,8 segundos en un disco duro tradicional de 100 MB/s;
Solución:?
Establezca un tamaño lo suficientemente grande. Para el disco duro, aumente el umbral de reescritura de AOF para garantizar que las operaciones de reescritura no se activen durante los períodos pico; use crontab para llamar al comando de reescritura de AOF cuando esté inactivo;