Concepto de diseño de aprendizaje rápido-RocketMQ

Diseño


1 almacenamiento de mensajes

Inserte la descripción de la imagen aquí

El almacenamiento de mensajes es la parte más compleja e importante de RocketMQ. Esta sección comenzará con tres aspectos de la arquitectura general de almacenamiento de mensajes de RocketMQ, el mapeo de memoria PageCache y Mmap, y dos métodos de flasheo diferentes en RocketMQ.

1.1 Arquitectura general del almacenamiento de mensajes

El diagrama de la arquitectura de almacenamiento de mensajes consta principalmente de los siguientes tres archivos relacionados con el almacenamiento de mensajes.

(1) CommitLog: El cuerpo principal del mensaje y el almacenamiento de metadatos. Almacena el contenido del cuerpo del mensaje escrito por el Productor. El contenido del mensaje no es de longitud fija. El tamaño predeterminado de un solo archivo es 1G, la longitud del nombre del archivo es de 20 dígitos, la izquierda está llena de ceros y el resto es el desplazamiento inicial. Por ejemplo, 00000000000000000000 representa el primer archivo, el desplazamiento inicial es 0 y el tamaño del archivo es 1G = 1073741824; El primer archivo está lleno, el segundo archivo es 00000000001073741824, el desplazamiento inicial es 1073741824 y así sucesivamente. Los mensajes se escriben principalmente en el archivo de registro de forma secuencial.Cuando el archivo está lleno, se escribe en el siguiente archivo;

(2) ConsumeQueue: cola de consumo de mensajes. El objetivo principal de presentarla es mejorar el rendimiento del consumo de mensajes. Debido a que RocketMQ es un modelo de suscripción basado en temas, el consumo de mensajes es para temas. Si desea recorrer el archivo de registro de confirmación para recuperar mensajes según el tema Ineficiente. El consumidor puede encontrar el mensaje que se consumirá de acuerdo con ConsumeQueue. Entre ellos, ConsumeQueue (cola de consumo lógico) como índice de mensajes de consumo, guarda el desplazamiento de desplazamiento físico inicial del mensaje de cola bajo el tema especificado en el CommitLog, el tamaño del mensaje y el valor HashCode de la etiqueta del mensaje. El archivo consumequeue se puede considerar como un archivo de índice de registro de confirmación basado en temas, por lo que la carpeta consumequeue se organiza de la siguiente manera: tema / cola / archivo estructura de organización de tres niveles, la ruta de almacenamiento específica es: $ HOME / store / consumequeue / {topic} / {queueId }/{nombre del archivo}. De manera similar, el archivo consumequeue adopta un diseño de longitud fija. Cada entrada tiene un total de 20 bytes, que son 8 bytes de desplazamiento físico del registro de confirmación, 4 bytes de longitud del mensaje y 8 bytes de código hash de etiqueta. Un solo archivo consta de 30 W de entradas. Se puede acceder a cada elemento de forma aleatoria como una matriz, y el tamaño de archivo de cada ConsumeQueue es de aproximadamente 5,72 M;

(3) IndexFile: IndexFile (archivo de índice) proporciona una forma de consultar mensajes por clave o intervalo de tiempo. La ubicación de almacenamiento del archivo de índice es: $ HOME \ store \ index $ {fileName}, el nombre del archivo fileName se nombra después de la marca de tiempo cuando se crea, el tamaño fijo del archivo IndexFile es de aproximadamente 400M, y un IndexFile puede almacenar índices de 2000W, IndexFile El almacenamiento subyacente está diseñado para implementar la estructura HashMap en el sistema de archivos, por lo que la implementación subyacente del archivo de índice rocketmq es un índice hash.

En el diagrama de arquitectura general de almacenamiento de mensajes de RocketMQ anterior, se puede ver que RocketMQ usa una estructura de almacenamiento híbrida, es decir, todas las colas en una sola instancia de Broker comparten un archivo de datos de registro (es decir, CommitLog) para el almacenamiento. La estructura de almacenamiento híbrida de RocketMQ (el contenido de las entidades de mensaje de varios temas se almacena en un CommitLog) utiliza una estructura de almacenamiento separada para los datos y las partes de índice para el Productor y el Consumidor, respectivamente. El Productor envía el mensaje al lado del corredor, y luego el lado del corredor usa la sincronización O conserve el mensaje de forma asincrónica y guárdelo en CommitLog. Mientras el mensaje se vacíe y persista en el archivo de disco CommitLog, el mensaje enviado por el productor no se perderá. Debido a esto, Consumer definitivamente tendrá la oportunidad de consumir esta noticia. Cuando no se puede extraer el mensaje, puede esperar a la siguiente extracción del mensaje. Al mismo tiempo, el servidor también admite el modo de sondeo prolongado. Si una solicitud de extracción de mensaje no extrae el mensaje, el agente puede esperar 30 segundos, siempre que este período de tiempo Cuando llega un nuevo mensaje, se devolverá directamente al consumidor. Aquí, el enfoque específico de RocketMQ es utilizar el subproceso de servicio en segundo plano en el lado del Broker: ReputMessageService para distribuir continuamente solicitudes y construir asincrónicamente ConsumeQueue (cola de consumo lógico) e IndexFile (archivo de índice).

1.2 Caché de página y mapeo de memoria

Page Cache (PageCache) es el caché de archivos del sistema operativo, que se utiliza para acelerar la lectura y escritura de archivos. En términos generales, la velocidad de lectura y escritura secuencial de archivos por parte de un programa es casi cercana a la de la memoria. La razón principal es que el sistema operativo usa el mecanismo PageCache para optimizar el rendimiento de las operaciones de acceso de lectura y escritura, y parte de la memoria se usa como PageCache. Para la escritura de datos, el sistema operativo escribe primero en la caché y luego el hilo del kernel pdflush vacía los datos de la caché en el disco físico de manera asincrónica. Para la lectura de datos, si se produce un error de PageCache cuando se lee un archivo una vez, mientras el sistema operativo accede y lee el archivo desde el disco físico, pre-leerá secuencialmente los archivos de datos de otros bloques adyacentes.

En RocketMQ, la cola de consumo lógico de ConsumeQueue almacena menos datos y se lee de forma secuencial. Bajo el efecto de lectura previa del mecanismo de caché de página, el rendimiento de lectura del archivo Consume Queue está casi cerca de la memoria de lectura, incluso en el caso de acumulación de mensajes. No afectará el rendimiento. Para el archivo de datos de registro almacenado en los mensajes de CommitLog, se produce más lectura de acceso aleatorio al leer el contenido del mensaje, lo que afecta gravemente al rendimiento. Si elige un algoritmo de programación de E / S del sistema adecuado, por ejemplo, establece el algoritmo de programación en "Fecha límite" (cuando el almacenamiento en bloque usa SSD), el rendimiento de las lecturas aleatorias también mejorará.

Además, RocketMQ utiliza principalmente MappedByteBuffer para leer y escribir archivos. Entre ellos, el modelo FileChannel en NIO se utiliza para mapear directamente los archivos físicos en el disco a la dirección de memoria del modo de usuario (este método Mmap reduce el búfer de E / S tradicional y la aplicación del usuario de los datos del archivo de disco en el espacio de direcciones del kernel del sistema operativo La sobrecarga de rendimiento de copiar de un lado a otro entre los búferes del espacio de direcciones del programa), la operación del archivo se convierte directamente en la operación de la dirección de memoria, lo que mejora en gran medida la eficiencia de lectura y escritura del archivo (debido a la necesidad de utilizar el mecanismo de asignación de memoria, por lo que El almacenamiento de archivos de RocketMQ utiliza una estructura de longitud fija para almacenarlo, lo cual es conveniente para mapear todo el archivo a la memoria a la vez).

1.3 Mensaje intermitente

Inserte la descripción de la imagen aquí

(1) Parpadeo síncrono: como se muestra en la figura anterior, el extremo Broker de RocketMQ devolverá una respuesta ACK exitosa al extremo Productor solo después de que el mensaje realmente persista en el disco. El flasheo sincrónico es una buena garantía para la confiabilidad de los mensajes MQ, pero tendrá un mayor impacto en el rendimiento. Este modo es generalmente adecuado para aplicaciones comerciales financieras.

(2) Parpadeo asincrónico: Puede aprovechar al máximo el PageCache del sistema operativo. Siempre que el mensaje esté escrito en el PageCache, el ACK exitoso será devuelto al Productor. El vaciado de mensajes se lleva a cabo mediante el envío de subprocesos asíncronos en segundo plano, lo que reduce la latencia de lectura y escritura y mejora el rendimiento y el rendimiento de MQ.

2 Mecanismo de comunicación

El clúster de cola de mensajes de RocketMQ incluye principalmente cuatro roles: NameServer, Broker (Master / Slave), Producer y Consumer. El proceso de comunicación básico es el siguiente:

(1) Después de que se inicia el Broker, necesita completar una operación de registro en el NameServer; luego, reporta regularmente la información de enrutamiento del tema al NameServer cada 30 segundos.

(2) Cuando el productor de mensajes actúa como un cliente para enviar un mensaje, necesita obtener información de enrutamiento de la TopicPublishInfoTable almacenada en caché local de acuerdo con el tema del mensaje. De lo contrario, la información de enrutamiento actualizada se extraerá nuevamente del NameServer y el Productor extraerá la información de enrutamiento del NameServer cada 30 segundos de forma predeterminada.

(3) El productor de mensajes selecciona una cola (MessageQueue) para enviar el mensaje de acuerdo con la información de enrutamiento obtenida en 2); el corredor recibe el mensaje como receptor del mensaje y lo almacena en el disco.

(4) El consumidor de mensajes selecciona una o varias colas de mensajes para extraer mensajes y consumirlos después de completar el balanceo de carga del cliente de acuerdo con la información de enrutamiento obtenida en 2).

De lo anterior 1) ~ 3), se puede ver que la comunicación ocurre entre el productor de mensajes, Broker y NameServer (aquí solo se menciona parte de la comunicación de MQ), por lo que cómo diseñar un buen módulo de comunicación de red es muy importante en MQ Determinará la capacidad general de transmisión de mensajes y el rendimiento final del clúster RocketMQ.

El módulo rocketmq-remoting es el módulo responsable de la comunicación de red en la cola de mensajes de RocketMQ. Casi todos los demás módulos que requieren comunicación de red lo utilizan y hacen referencia a él (como rocketmq-client, rocketmq-broker y rocketmq-namesrv). Para lograr una solicitud y recepción de datos eficiente entre el cliente y el servidor, la cola de mensajes de RocketMQ ha personalizado el protocolo de comunicación y ha ampliado el módulo de comunicación sobre la base de Netty.

2.1 Estructura de clases de comunicación remota

Inserte la descripción de la imagen aquí

2.2 Diseño de protocolo y codificación y decodificación

Cuando se envía un mensaje entre el Cliente y el Servidor, se requiere un acuerdo de protocolo para que se envíe el mensaje, por lo que es necesario personalizar el protocolo de mensajes de RocketMQ. Al mismo tiempo, para transmitir mensajes de manera eficiente y leer los mensajes recibidos en la red, es necesario codificar y decodificar los mensajes. En RocketMQ, la clase RemotingCommand encapsula todo el contenido de datos durante la transmisión del mensaje, no solo incluye todas las estructuras de datos, sino que también incluye operaciones de codificación y decodificación.

Campo de encabezado Tipos de Solicitar descripción Descripción de la respuesta
código En t Solicitar código de operación, el respondedor realiza diferentes procesos comerciales de acuerdo con diferentes códigos de solicitud Responder código de respuesta. 0 significa éxito, distinto de cero significa varios errores
idioma Código de lenguaje Idioma implementado por el solicitante Idioma implementado por el respondedor
versión En t Versión del programa solicitante La versión del programa de encuestados
opaco En t Equivalente a requestId, diferentes códigos de identificación de solicitud en la misma conexión, correspondientes al mensaje de respuesta Responder sin modificación
bandera En t Distinguir entre RPC normal y onewayRPC Distinguir entre RPC normal y onewayRPC
observación Cuerda Transferir mensajes de texto personalizados Transferir mensajes de texto personalizados
extFields HashMap <Cadena, Cadena> Solicitar información de extensión personalizada Responder a la información de extensión personalizada

Inserte la descripción de la imagen aquí

Se puede ver que el contenido de la transmisión se puede dividir en las siguientes 4 partes:

(1) Longitud del mensaje: longitud total, almacenamiento de cuatro bytes, ocupando un tipo int;

(2) Tipo de serialización y longitud del encabezado del mensaje: también ocupa un tipo int, el primer byte representa el tipo de serialización y los siguientes tres bytes representan la longitud del encabezado del mensaje;

(3) Datos del encabezado del mensaje: datos del encabezado del mensaje después de la serialización;

(4) Datos del cuerpo del mensaje: el contenido de datos de bytes binarios del cuerpo del mensaje;

2.3 Método y proceso de comunicación de mensajes

Hay tres formas principales de admitir la comunicación en la cola de mensajes de RocketMQ: síncrona (sincronización), asíncrona (asíncrona) y unidireccional (unidireccional)
. Entre ellos, el modo de comunicación "unidireccional" es relativamente simple y generalmente se usa en el escenario de envío de paquetes de latidos sin prestar atención a su respuesta. Aquí, presentamos principalmente el proceso de comunicación asincrónica de RocketMQ.

Inserte la descripción de la imagen aquí

2.4 Diseño de reactor de múltiples subprocesos

La comunicación RPC de RocketMQ utiliza componentes de Netty como biblioteca de comunicación subyacente, y también sigue el modelo de subprocesos múltiples de Reactor y, al mismo tiempo, realiza algunas extensiones y optimizaciones al respecto.

Inserte la descripción de la imagen aquí

En el diagrama de bloques anterior, puede comprender aproximadamente el modelo de subprocesos múltiples de Reactor de NettyRemotingServer en RocketMQ. Un hilo principal de Reactor (eventLoopGroupBoss, 1 arriba) es responsable de monitorear las solicitudes de conexión de red TCP, establecer una conexión, crear un SocketChannel y registrarse con el selector. El código fuente de RocketMQ seleccionará automáticamente NIO y Epoll de acuerdo con el tipo de sistema operativo, y también se puede configurar a través de parámetros), y luego monitoreará los datos reales de la red. Después de obtener los datos de la red, envíelos al grupo de subprocesos del trabajador (eventLoopGroupSelector, que es la "N" anterior, y el código fuente está configurado en 3 de forma predeterminada). Se requieren verificación SSL, códec, verificación inactiva y conexión de red antes de que se ejecute realmente la lógica empresarial. Gestión, estas tareas se entregan al defaultEventExecutorGroup (es decir, "M1" arriba, establecido en 8 de forma predeterminada en el código fuente) para realizar. Las operaciones comerciales de procesamiento se ejecutan en el grupo de subprocesos comerciales. De acuerdo con el código de código de solicitud comercial de RomotingCommand, el procesador correspondiente se encuentra en la variable de caché local de la tabla del procesador, y luego se encapsula en una tarea y se envía al grupo de subprocesos de procesamiento del procesador comercial correspondiente para su ejecución ( sendMessageExecutor, tomando el envío de un mensaje como ejemplo, es "M2" arriba). En los varios pasos desde la entrada a la lógica empresarial, el grupo de subprocesos sigue aumentando, lo que está relacionado con la complejidad lógica de cada paso. Cuanto más complejo, más amplio es el canal concurrente requerido.

Hilos Nombre del hilo Instrucciones específicas del hilo
1 NettyBoss_% d Hilo principal del reactor
norte NettyServerEPOLLSelector_% d_% d Grupo de subprocesos del reactor
M1 NettyServerCodecThread_% d Grupo de subprocesos de trabajo
M2 RemotingExecutorThread_% d Grupo de subprocesos de procesamiento del procesador empresarial

3 filtrado de mensajes

El método de filtrado de mensajes de la cola de mensajes distribuidos de RocketMQ es diferente de otro middleware de MQ, y el filtrado de mensajes se realiza cuando el consumidor final se suscribe al mensaje. RocketMQ hace esto porque su lado productor escribe mensajes y el lado consumidor suscribe mensajes usando un mecanismo de almacenamiento separado. Los mensajes de suscripción del lado consumidor necesitan obtener un índice a través de la cola lógica de consumo de mensajes de ConsumeQueue, y luego leer de CommitLog Se toma el contenido real de la entidad del mensaje, por lo que al final, su estructura de almacenamiento no se puede evitar. La estructura de almacenamiento de su ConsumeQueue es la siguiente: Puede ver el valor hash de la etiqueta de mensaje almacenada en 8 bytes, y el filtrado de mensajes basado en la etiqueta se basa oficialmente en el valor de este campo.

Inserte la descripción de la imagen aquí

Soporta principalmente los siguientes dos métodos de filtrado
(1) Método de filtrado de etiquetas: el consumidor puede especificar TAG además de Topic cuando se suscribe a un mensaje. Si un mensaje tiene múltiples TAG, se pueden separar por ||. Entre ellos, el extremo del consumidor construirá esta solicitud de suscripción en un SubscriptionData y enviará una solicitud de mensaje de extracción al extremo del corredor. Antes de que el corredor lea los datos de la Tienda, la capa de almacenamiento de archivos de RocketMQ, utilizará los datos para construir un MessageFilter y luego pasarlo a la Tienda. Una vez que la tienda lee un registro de ConsumeQueue, utilizará el valor hash de la etiqueta de mensaje que registró para filtrar. Dado que el servidor solo juzga en función del código hash, la cadena original de la etiqueta no se puede filtrar con precisión, por lo que se extrae del consumidor del mensaje. Una vez recibido el mensaje, es necesario comparar la cadena de etiquetas original del mensaje. Si es diferente, el mensaje se descarta sin consumo de mensaje.

(2) Método de filtrado SQL92: el método general de este método es el mismo que el método de filtrado de etiquetas anterior, excepto que el proceso de filtrado específico en la capa Store es diferente. La construcción y ejecución de la expresión SQL real es responsable del módulo rocketmq-filter. La ejecución de expresiones SQL cada vez que el filtrado afectará la eficiencia, por lo que RocketMQ usa BloomFilter para evitar la ejecución en todo momento. El contexto de expresión de SQL92 es el atributo del mensaje.

4 Equilibrio de carga

El equilibrio de carga en RocketMQ se realiza en el lado del cliente. Específicamente, se puede dividir en equilibrio de carga cuando el productor envía mensajes y equilibrio de carga cuando se suscribe a mensajes en el lado del consumidor.

4.1 Equilibrio de carga del productor

Cuando el productor envía un mensaje, primero encontrará el TopicPublishInfo especificado de acuerdo con el tema. Después de obtener la información de enrutamiento de TopicPublishInfo, el cliente RocketMQ seleccionará una cola (MessageQueue) de messageQueueList en TopicPublishInfo de forma predeterminada en el método selectOneMessageQueue (). Enviar mensaje. La estrategia de tolerancia a fallos específica se define en la clase MQFaultStrategy. Hay una variable de conmutación sendLatencyFaultEnable. Si está activada, los agentes Broker que no están disponibles se filtran según el incremento aleatorio y el módulo. La llamada "latencyFaultTolerance" se refiere a una cierta cantidad de tiempo para retroceder la falla anterior. Por ejemplo, si la latencia solicitada la última vez supera los 550Lms, retroceso 3000Lms; más de 1000L, retroceso 60000L; si está cerrada, seleccione una cola (MessageQueue) para enviar mensajes en un modo de incremento aleatorio. El mecanismo latencyFaultTolerance es para lograr una alta disponibilidad de envío de mensajes La clave del núcleo.

4.2 Equilibrio de carga del consumidor

En RocketMQ, los dos modos de consumo (Push / Pull) en el lado del consumidor se basan en el modo de extracción para obtener mensajes, mientras que el modo Push es solo un paquete del modo de extracción, y su esencia se realiza cuando el hilo de extracción de mensajes se extrae del servidor. Después de obtener un lote de mensajes y enviarlos al grupo de subprocesos de consumo de mensajes, continúan "sin parar" tratando de extraer mensajes del servidor nuevamente. Si no se extrae el mensaje, seguirá apareciendo después de una demora. En los dos métodos de consumo (Push / Pull) basados ​​en el modo pull, el lado del consumidor necesita saber qué cola de mensajes del lado del intermediario: colas para obtener mensajes. Por lo tanto, es necesario realizar un balanceo de carga en el lado del consumidor, es decir, se asignan múltiples MessageQueues en el lado del intermediario a qué consumidores del mismo grupo de consumidores consumirán.

1. Envío de paquetes de latidos desde el consumidor

Una vez iniciado el consumidor, enviará continuamente paquetes de latidos a todas las instancias de Broker en el clúster de RocketMQ a través de tareas programadas (incluida información como el nombre del grupo de consumo de mensajes, la recopilación de relaciones de suscripción, el modo de comunicación de mensajes y el valor de la identificación del cliente) . Después de recibir el mensaje de latido del consumidor, el intermediario lo mantendrá en la variable de caché local del ConsumerManager, consumerTable, y guardará la información del canal de red del cliente encapsulado en la variable de caché local, channelInfoTable para cargarla posteriormente en el consumidor. Proporcione información de metadatos equilibrada en la que se pueda basar.

2. La clase principal para el equilibrio de carga en el lado del consumidor: RebalanceImpl

En el proceso de inicio de la instancia de consumidor, el inicio de la instancia de MQClientInstance completará el inicio del subproceso del servicio de equilibrio de carga: RebalanceService (que se ejecuta una vez cada 20 s). Al observar el código fuente, se puede encontrar que el método run () del subproceso RebalanceService finalmente llama al método rebalanceByTopic () de la clase RebalanceImpl, que es el núcleo de la realización del equilibrio de carga del lado del consumidor. Aquí, el método rebalanceByTopic () realizará un procesamiento lógico diferente según si el tipo de comunicación del consumidor es "modo de transmisión" o "modo de grupo". Aquí miramos principalmente el flujo de procesamiento principal en el modo de clúster:

(1) Obtenga el conjunto de colas de consumo de mensajes (mqSet) bajo el tema de la variable de caché local topicSubscribeInfoTable de la instancia rebalanceImpl;

(2) Llame al método mQClientFactory.findConsumerIdList () de acuerdo con el tema y el grupo consumidor como parámetros para enviar una solicitud de comunicación RPC al corredor para obtener la lista de ID de consumidor en el grupo de consumidores (el intermediario se basa en la tabla de consumidores construida según los datos del paquete de latidos informados por el consumidor anterior. Se devuelve una respuesta, código de solicitud de servicio: GET_CONSUMER_LIST_BY_GROUP);

(3) Primero, ordene la cola de consumo de mensajes y el ID del consumidor en el tema, y ​​luego use el algoritmo de estrategia de distribución de cola de mensajes (predeterminado: el algoritmo de distribución promedio de la cola de mensajes) para calcular la cola de mensajes que se extraerá. El algoritmo de distribución promedio aquí es similar al algoritmo de paginación, clasifica todos los MessageQueues en orden similar a los registros, clasifica a todos los consumidores del lado del consumidor en orden similar al número de páginas y encuentra el tamaño promedio que cada página debe contener y cada registro de página Finalmente, atraviesa todo el rango y calcula los registros que deberían asignarse al consumidor actual (aquí: MessageQueue).

Inserte la descripción de la imagen aquí

(4) Luego, llame al método updateProcessQueueTableInRebalance (). El método específico es comparar primero el conjunto de colas de mensajes asignado (mqSet) con processQueueTable.

Inserte la descripción de la imagen aquí

  • La parte roja marcada por processQueueTable en la figura anterior indica que no se contienen entre sí con el conjunto de colas de mensajes asignado mqSet. Establezca el atributo Dropped de estas colas en verdadero y luego verifique si estas colas se pueden eliminar de la variable de caché processQueueTable. Aquí, el método removeUnnesentialMessageQueue () se ejecuta específicamente, es decir, cada 1 para verificar si se puede obtener el bloqueo de la cola de procesamiento de consumo actual, y devuelve verdadero si lo obtiene. . Si después de esperar 1s, aún no se obtiene el bloqueo de la cola de procesamiento de consumo actual, se devuelve falso. Si devuelve verdadero, elimine la entrada correspondiente de la variable de caché processQueueTable;

  • La parte verde de processQueueTable en la figura anterior indica la intersección con el conjunto de cola de mensajes asignado mqSet. Para determinar si ProcessQueue ha caducado, no se preocupe por él en modo Pull. Si está en modo Push, establezca la propiedad Dropped en true y llame al método removeUnnesentialMessageQueue () para intentar eliminar la entrada como se indicó anteriormente;

Finalmente, cree un objeto ProcessQueue para cada MessageQueue en el conjunto de colas de mensajes filtrados (mqSet) y guárdelo en la cola processQueueTable de RebalanceImpl (donde se llama al método computePullFromWhere (MessageQueue mq) de la instancia RebalanceImpl para obtener el siguiente consumo de progreso del objeto MessageQueue Luego, el valor de compensación se completa en las propiedades del objeto pullRequest que se creará a continuación), y se crea el objeto de solicitud de extracción; se agrega pullRequest a la lista de extracción; pullRequestList, y finalmente se ejecuta el método dispatchPullRequest () para poner el objeto de solicitud PullRequest del mensaje de extracción a su vez En la cola de bloqueo pullRequestQueue del subproceso de servicio PullMessageService, después de que se elimina el subproceso de servicio, se inicia una solicitud de un mensaje de extracción en el extremo del Broker. Entre ellos, puede centrarse en la comparación.Los métodos dispatchPullRequest () de las dos clases de implementación de RebalancePushImpl y RebalancePullImpl son diferentes, y el método de la clase RebalancePullImpl está vacío, lo que responde a la última pregunta del artículo anterior.

La cola de consumo de mensajes equilibra la carga entre diferentes consumidores en el mismo grupo de consumo. El concepto de diseño básico es que una cola de consumo de mensajes solo puede ser consumida por un consumidor en el mismo grupo de consumo al mismo tiempo, y un consumidor de mensajes puede consumir más al mismo tiempo. Cola de mensajes.

5 Mensaje de transacción

Apache RocketMQ ya admite mensajes de transacciones distribuidos en la versión 4.3.0. Aquí, RocketMQ usa la idea de 2PC para implementar el envío de mensajes de transacciones y agrega una lógica de compensación para manejar el tiempo de espera de dos fases o el mensaje de falla, como se muestra en la siguiente figura.

Inserte la descripción de la imagen aquí

5.1 Resumen del proceso del mensaje de transacción de RocketMQ

La figura anterior ilustra el esquema general de los mensajes de transacción, que se divide en dos procesos: envío y envío de mensajes de transacción normales y proceso de compensación de mensajes de transacción.

1. Envío y envío de mensajes de transacción:

(1) Envíe un mensaje (medio mensaje).

(2) El servidor escribe el resultado en respuesta al mensaje.

(3) Ejecute transacciones locales de acuerdo con los resultados del envío (si falla la escritura, el medio mensaje no es visible para la empresa en este momento y la lógica local no se ejecuta).

(4) Ejecute Commit o Rollback de acuerdo con el estado de la transacción local (la operación de confirmación genera un índice de mensajes y el mensaje es visible para los consumidores)

2. Proceso de compensación:

(1) Para mensajes de transacciones sin Confirmar / Revertir (mensajes en estado pendiente), inicie una "verificación de retroceso" desde el servidor

(2) El productor recibe el mensaje de devolución y verifica el estado de la transacción local correspondiente al mensaje de devolución.

(3) Volver a comprometer o deshacer según el estado de la transacción local

Entre ellos, la fase de compensación se utiliza para resolver el timeout o falla del mensaje Commit o Rollback.

5.2 Diseño de mensaje de transacción de RocketMQ

1. Los mensajes de transacción no son visibles para los usuarios en una etapa.

En el flujo principal de mensajes de transacciones de RocketMQ, cómo los mensajes de la primera etapa son invisibles para los usuarios. Entre ellos, la característica más importante de los mensajes de transacciones en relación con los mensajes ordinarios es que los mensajes enviados en una etapa son invisibles para los usuarios. Entonces, ¿cómo escribir un mensaje pero no visible para el usuario? El método de mensaje de transacción de RocketMQ es: si el mensaje es un medio mensaje, se realiza una copia de seguridad del asunto del mensaje original y de la cola de consumo de mensajes, y luego el asunto se cambia a RMQ_SYS_TRANS_HALF_TOPIC. Dado que el grupo de consumidores no se ha suscrito al tema, el consumidor no puede consumir mensajes de medio tipo y RocketMQ iniciará una tarea cronometrada, extraerá el mensaje del tema RMQ_SYS_TRANS_HALF_TOPIC para su consumo y obtendrá un proveedor de servicios de acuerdo con el grupo de productores para enviarlo de vuelta para verificar la transacción. Solicitud de estado, según el estado de la transacción para decidir si enviar o revertir el mensaje.

En RocketMQ, la estructura de almacenamiento de mensajes en el lado del servidor es la siguiente. Cada mensaje tendrá la información de índice correspondiente. El consumidor lee el contenido de la entidad del mensaje a través del índice secundario de ConsumeQueue. El proceso es el siguiente:
Inserte la descripción de la imagen aquí

La estrategia de implementación específica de RocketMQ es: si se escribe el mensaje de transacción, se reemplazan las propiedades de Tema y Cola del mensaje, y la información original de Tema y Cola se almacena en las propiedades del mensaje. Debido a que se reemplaza el asunto del mensaje, el mensaje no se No se reenviará a la cola de consumo de mensajes del tema original y los consumidores no pueden percibir la existencia del mensaje y no lo consumirán. De hecho, cambiar el asunto del mensaje es una "rutina" común de RocketMQ. Recuerde el mecanismo de implementación de los mensajes retrasados.

2. Operaciones de confirmación y reversión e introducción de mensajes Op

Después de completar la primera fase de escribir un mensaje que no es visible para el usuario, si la segunda fase es una operación de confirmación, el mensaje debe ser visible para el usuario; si se trata de una reversión, la primera fase del mensaje debe cancelarse. Permítanme hablar primero sobre Rollback. Para Rollback, el mensaje de la primera etapa es invisible para el usuario y no es necesario cancelar el mensaje (en realidad, RocketMQ no puede eliminar un mensaje porque escribe archivos de forma secuencial). Pero a diferencia del hecho de que este mensaje no tiene un estado determinado (estado pendiente, transacción pendiente), se necesita una operación para identificar el estado final de este mensaje. El esquema de mensajes de transacción de RocketMQ introduce el concepto de mensajes de operación y utiliza mensajes de operación para identificar el estado del mensaje de transacción (confirmación o reversión). Si un mensaje de transacción no tiene un mensaje de operación correspondiente, el estado de la transacción aún no se puede determinar (tal vez la segunda fase haya fallado). Una vez introducido el mensaje Op, ya sea que el mensaje de transacción sea Confirmar o Revertir, se registrará una operación Op. Comprometerse en comparación con Rollback solo crea un índice de mensajes Half antes de escribir mensajes Op.

3.Almacenamiento y correspondencia de mensajes op.

RocketMQ escribe el mensaje Op en un tema específico globalmente a través del método en el código fuente — TransactionalMessageUtil.buildOpTopic (); este tema es un tema interno (como el tema del mensaje Half) y no será consumido por los usuarios. El contenido del mensaje Op es la compensación almacenada del mensaje Half correspondiente, de modo que el mensaje Half puede indexarse ​​a través del mensaje Op para operaciones de revisión posteriores.

Inserte la descripción de la imagen aquí

4. Construcción del índice del medio mensaje

Al realizar la operación de confirmación de la segunda fase, es necesario construir un índice de mensajes Half. Dado que el medio mensaje de la primera etapa se escribe en un tema especial, el medio mensaje debe leerse cuando se crea el índice en la segunda etapa, y el tema y la cola se reemplazan con el tema y la cola de destino reales, y luego se escribe un mensaje normal Opere para generar un mensaje visible para el usuario. Por lo tanto, la segunda etapa del mensaje de transacción de RocketMQ realmente usa el contenido del mensaje almacenado en la primera etapa para recuperar un mensaje común completo en la segunda etapa, y luego pasa por el proceso de escritura del mensaje.

5. ¿Cómo lidiar con el mensaje de que la segunda etapa falló?

Si el mensaje de transacción de RocketMQ falla en el proceso de la segunda etapa, por ejemplo, durante la operación Commit, ocurre un problema de red y el Commit falla, entonces se debe adoptar una cierta estrategia para que este mensaje finalmente se confirme. RocketMQ utiliza un mecanismo de compensación llamado "check back". El lado del corredor inicia una verificación de retroceso en el mensaje del estado indeterminado y envía el mensaje al lado del productor correspondiente (Productor del mismo grupo). El productor verifica el estado de la transacción local de acuerdo con el mensaje y luego ejecuta Commit o Rollback. El corredor final revisa los mensajes de transacciones y avanza CheckPoint comparando los mensajes Half y los mensajes Op (se determina el estado de grabación de esos mensajes de transacción).

Vale la pena señalar que Rocketmq no verifica continuamente el estado de la transacción de información. De forma predeterminada, lo hace 15 veces. Si no se conoce el estado de la transacción después de 15 verificaciones, Rocketmq revierte el mensaje de forma predeterminada.

6 Consulta de mensaje

RocketMQ admite la consulta de mensajes según las dos dimensiones siguientes ("Consultar mensajes según Id. De mensaje" y "Consultar mensajes según clave de mensaje").

6.1 Consultar mensajes según MessageId

El MessageId en RocketMQ tiene una longitud total de 16 bytes, que contiene la dirección del host de almacenamiento de mensajes (dirección IP y puerto) y el mensaje Commit Log offset. El método específico de "mensaje de consulta según MessageId" en RocketMQ es: el lado del cliente analiza la dirección del corredor (dirección IP y puerto) y la dirección de compensación del registro de confirmación de MessageId, lo encapsula en una solicitud RPC y lo envía a través de la capa de comunicación Remoting (negocio Código de solicitud: VIEW_MESSAGE_BY_ID). El Broker usa el QueryMessageProcessor El proceso de lectura del mensaje usa el desplazamiento y el tamaño de commitLog para encontrar el registro real en el commitLog y analizarlo en un mensaje completo para regresar.

6.2 Consultar mensajes según la clave de mensaje

"Consultar mensajes según la clave del mensaje" se implementa principalmente en base al archivo de índice IndexFile de RocketMQ. La estructura lógica del archivo de índice de RocketMQ es similar a la implementación de HashMap en JDK. La estructura específica del archivo de índice es la siguiente:

Inserte la descripción de la imagen aquí

El archivo de índice IndexFile proporciona a los usuarios un servicio de consulta de índice de mensajes a través de "consultas de mensajes de acuerdo con la clave de mensaje". La ubicación de almacenamiento del archivo IndexFile es: $ HOME \ store \ index $ {fileName}, y el nombre del archivo fileName se nombra después de la marca de tiempo cuando se creó. , El tamaño del archivo es fijo, igual a 40 + 500W * 4 + 2000W * 20 = 420000040 bytes. Si el atributo UNIQ_KEY está configurado en las propiedades del mensaje, use el valor de tema + "#" + UNIQ_KEY como clave para escribir. Si el mensaje tiene establecido el atributo KEYS (varias KEYS están separadas por espacios), el tema + "#" + KEY también se utilizará para la indexación.

Los datos del índice contienen cuatro campos: Key Hash / CommitLog Offset / Timestamp / NextIndex offset, por un total de 20 bytes. El desplazamiento de NextIndex es el valor de slot leído anteriormente. Si hay un conflicto de hash, puede usar este campo para encadenar todos los índices en conflicto en una lista vinculada. Timestamp registra la diferencia entre el mensaje storeTimestamp, no un tiempo absoluto. La estructura de todo el archivo de índice se muestra en la figura. El encabezado de 40 bytes se utiliza para almacenar información estadística total. La tabla de ranuras de 4 * 500W no almacena los datos del índice real, sino el encabezado de la lista enlazada unidireccional correspondiente a cada ranura. 20 * 2000W son los datos de índice reales, es decir, un archivo de índice puede almacenar índices de 2000W.

"Consultar mensajes de acuerdo con la clave del mensaje", el enfoque específico de RocketMQ es realizar consultas principalmente a través del procesador de negocios QueryMessageProcessor en el lado del corredor. El proceso de lectura de mensajes es usar el tema y la clave para encontrar un registro en el archivo de índice IndexFile, de acuerdo con el commitLog que contiene. offset lee el contenido de la entidad del mensaje del archivo CommitLog.

Supongo que te gusta

Origin blog.csdn.net/weixin_42528266/article/details/108625061
Recomendado
Clasificación