Red de conocimiento informático - Problemas con los teléfonos móviles - diseño de almacenamiento de alto rendimiento rocketMq

diseño de almacenamiento de alto rendimiento rocketMq

?El middleware de mensajes generalmente usa discos para almacenamiento. En las PC económicas, generalmente se usan discos duros mecánicos. Sin embargo, los discos duros mecánicos son n órdenes de magnitud más lentos que el acceso a la memoria, y un buen middleware de mensajes inevitablemente lo hará. Los recursos se reducen al límite. Veamos cómo RocketMq logra un almacenamiento eficiente.

Este diagrama de flujo presenta brevemente la implementación de almacenamiento de rocketMq. Primero, explica brevemente el significado de cada almacenamiento.

Primero, presente brevemente mmap como un método de mapeo de memoria. Es decir, asignar un archivo u otro objeto al espacio de direcciones del proceso y realizar un par de relaciones de mapeo entre la dirección del disco del archivo y una determinada dirección virtual en el espacio de direcciones virtuales del proceso. Una vez que se implementa este mapeo, el proceso puede usar el puntero para leer y escribir en esta memoria, y el sistema escribirá automáticamente las páginas sucias en el disco de archivos correspondiente. En cambio, las modificaciones del espacio del kernel en esta área se reflejan directamente en el espacio del usuario, lo que permite que diferentes procesos compartan archivos.

El tamaño de archivo predeterminado de ?rocketMq es 1G, lo que significa que los archivos 1G se asignan a la memoria física. Sin embargo, la inicialización de mmap solo asigna la dirección de disco del archivo y la dirección virtual del proceso, y en realidad no asigna todo el archivo a la memoria. Cuando el programa realmente accede a estas memorias, la excepción de página generada es insuficiente, lo que cambiará el contenido. del archivo. Copiado al caché de la página. Imagínese si solo realiza el mapeo al principio y luego carga algunas páginas en MappedFile cuando realmente escribe un mensaje en el archivo. La operación de inicialización se implementa mediante un subproceso separado (AllocateMappedFileService). Este es el modelo de producción-consumo correspondiente. Afortunadamente, rocketMq calienta la memoria al inicializar MappedFile y escribe algunos datos en el caché de la página de antemano y los vacía en el disco, cargando así el archivo completo en el caché de la página.

Si hay suficiente memoria, el sistema operativo cargará el archivo en la caché de la página para mejorar la eficiencia de lectura y escritura de archivos, pero cuando no hay memoria suficiente, el sistema operativo reciclará la caché de la página. Si el sistema operativo recicla el caché de página correspondiente a MappedFile, generará una excepción de falla de página y recargará el caché de página desde el disco, lo que tendrá un gran impacto en el rendimiento del sistema. Después de crear MappedFile y completar el calentamiento de la memoria, rocketMq llama a la función mlock de c para bloquear la memoria. Específicamente, veamos cómo funciona. ¿Cómo se hace esto?

Para escribir un mensaje, primero debe escribirlo en el pagecache. rocketMq proporciona dos mecanismos de vaciado, el vaciado sincrónico y el vaciado asincrónico, que son adecuados para ocasiones con alta confiabilidad de mensajes. El rendimiento del flasheo sincrónico del disco es relativamente bajo, por lo que los mensajes no se perderán incluso si el sistema deja de funcionar. Como se muestra en la figura, de la comunidad rocketMq

? La siguiente es una breve introducción al principio del cepillado de disco sincrónico. En el mecanismo de cepillado de disco sincrónico, el hilo de envío crea una instancia de GroupCommitRequest, la variable miembro es CountDownLatch. Y luego lo empuja a la cola de bloqueo. Un hilo de cepillo separado (GroupCommitService), ¡el hilo de cepillo limpia el disco de la cola de bloqueo! De hecho, es llamar al método mappedByteBuffer.force () una vez que el vaciado del disco se realiza correctamente, el hilo de espera de vaciado se activa mediante cuenta regresiva. El principio es muy simple.

Principio de actualización asincrónica: el hilo de envío del mensaje escribe en el caché de la página y regresa después del éxito. El disco de actualización asincrónico corresponde a un hilo de actualización separado en el origen. El código predeterminado es 4 actualizaciones de tamaño de página, es decir, una vez 16k de datos. La actualización asincrónica puede provocar la pérdida de datos. Cuando el programa jvm muere pero la máquina no falla, las páginas sucias en el pagecache aún se pueden vaciar manualmente en el disco, pero cuando la máquina falla, los datos se perderán para siempre.

?Como se mencionó anteriormente, rocketMq proporciona un mecanismo de grupo de memoria fuera del montón llamado TransientStorePool.

Cuando TransientStorePool se inicializa, crea instancias de 5 memorias fuera del montón con el mismo tamaño que MappedFile, que es 1G, y luego bloquea esa área de memoria. Si el mecanismo de memoria fuera del montón está habilitado, al enviar un mensaje, MappedFile obtendrá una instancia de directBuffer del grupo de memoria fuera del montón cuando se cree una instancia. El mensaje escrito se escribirá primero en la memoria fuera del montón y luego habrá. un subproceso independiente (CommitRealTimeService) lo descarga en la caché de la página, que luego se descarga en la caché de la página mediante un subproceso independiente (FlushRealTimeService) para vaciar desde la caché de la página al disco.

? Beneficios de tener un grupo de memoria fuera del montón: escribir mensajes primero en la memoria fuera del montón hace que las operaciones de memoria pura sean muy rápidas. A medida que se leen los mensajes, se leen desde la memoria caché de la página, lo que equivale a separar lecturas y escrituras.

?Como puede ver en la imagen general al principio, todos los subprocesos que envían mensajes se ejecutan en serie y todos los datos del tema se juntan y escriben en el caché de la página en secuencia, por lo que la eficiencia Muy alto. Una vez que el caché de la página se escribe correctamente, un hilo separado crea de forma asincrónica consumerQueue y indexFile (basado en el hashMap basado en disco para implementar la búsqueda de mensajes. Los consumidores que construyen con éxito consumerQueue pueden consumir los mensajes más recientes). también ejecutado en serie. consumerQueue también se escribe secuencialmente, solo se escriben 20 bytes cada vez y el espacio ocupado no es grande.

?Cada tema puede corresponder a múltiples consumerQueue, lo que equivale al concepto de partición en Kafka. El algoritmo de asignación de consumidores y consumerQueue de Rocketmq es similar a Kafka. Dado que consumerQueue solo guarda el desplazamiento, el tamaño del mensaje y el código de etiquetas del mensaje en commitLog, debe obtener el desplazamiento para extraer el mensaje en commitLog. Tenga en cuenta que la lectura en este momento es muy similar a la lectura aleatoria y se ve afectada por el. bloqueo de memoria mlock anterior Además, los datos consumidos generalmente se generan recientemente y todos los datos todavía están en el caché de la página, por lo que el impacto en el rendimiento no es grande. Un punto es que cuando los datos consumidos por el consumidor están lejos, definitivamente no hay caché en el caché de la página. En este momento, rocketMq sugerirá al consumidor que lea desde el esclavo.

Todos los temas *** de rocketMq tienen commitLog y el disco se escribe secuencialmente. La implementación de este punto también se refiere a kafka. Al leer el mensaje, vaya al commitLog de acuerdo con consumerQueue. Los datos, aunque son una lectura aleatoria, los datos más recientes generalmente son insignificantes en pagecahce. Aunque es una lectura aleatoria, los datos más recientes generalmente son insignificantes en la página. Un buen middleware debe maximizar el rendimiento del hardware y tener en cuenta las características relevantes del sistema operativo, como el uso de bloqueos de memoria para evitar el intercambio de memoria, la memoria fuera del montón y la separación de lectura y escritura del caché de página, etc. Lo anterior se resume viendo el código fuente de almacenamiento de rocketMq. Si hay algún error, corríjalo.