[Preguntas de la entrevista de RocketMQ (23 preguntas)]

Directorio de artículos

Preguntas de la entrevista RocketMQ (23 preguntas)

Base

1. ¿Por qué utilizar la cola de mensajes?

La cola de mensajes tiene tres usos principales, tomemos como ejemplo un pedido en un sistema de comercio electrónico:

  • Desacoplamiento : antes de introducir la cola de mensajes, después de realizar el pedido, el servicio de pedidos debe llamar al servicio de inventario para reducir el inventario y llamar al servicio de marketing para agregar datos de marketing... Después de introducir la cola de mensajes, el El mensaje de finalización del pedido se puede arrojar a la cola y el propio servicio posterior simplemente llámelo, completando así el desacoplamiento del servicio de pedido y otros servicios.

imagen-20230918172901235

  • Asíncrono : Después de pagar el pedido, necesitamos deducir inventario, aumentar puntos, enviar mensajes, etc., por lo que el enlace se alargará y, a medida que el enlace se alargue, el tiempo de respuesta será más largo. Al introducir la cola de mensajes, 更新订单状态todo lo demás se puede hacer de forma asincrónica , de modo que el tiempo de respuesta se pueda reducir tan pronto como llegue.

imagen-20230918173002606

  • Reducción de picos : la cola de mensajes se combina en una para reducir los picos. Por ejemplo, en el sistema de venta flash, el tráfico suele ser muy bajo, pero cuando hay actividad de venta flash, el tráfico llega como loco durante la venta flash. Nuestros servidores, Redis y MySQL tienen cada uno diferentes tolerancias. Debe haber un problema si recopila directamente todo el tráfico según el orden. En casos graves, puede bloquearse directamente.

Podemos colocar solicitudes en la cola y liberar solo el tráfico que nuestro servicio puede manejar, de modo que podamos soportar un gran tráfico en un corto período de tiempo.

imagen-20230918181310247

El desacoplamiento, la asincronía y el recorte de picos son las tres funciones más importantes de las colas de mensajes.

2. ¿Por qué elegir RocketMQ?

Una comparación de varias colas de mensajes importantes en el mercado es la siguiente:

ConejoMQ ActivoMQ cohetemq kafka
compañía Conejo apache Alí apache
idioma erlang Java Java Escala y Java
Soporte de protocolo AMPQ OpenWire, STOMP, REST, XMPP, AMQP personalizar Protocolo personalizado, la comunidad encapsula el soporte del protocolo http
Idiomas admitidos por el cliente Admite oficialmente Erlang, Java, Ruby, etc. La comunidad ha encontrado una variedad de API que admiten casi todos los idiomas. Java, C, C++, Python, PHP, Perl, .net, etc. Java, C++ (inmaduro) Oficialmente es compatible con Java y la comunidad produce una variedad de API, como PHP, Python, etc.
rendimiento de clics 3. Nivel 10,000 4. Nivel 10.000 1. Nivel cien mil 2. Nivel cien mil
retraso del mensaje Nivel de microsegundo nivel de milisegundos nivel de milisegundos En milisegundos
Disponibilidad Alta disponibilidad basada en arquitectura maestro-esclavo Alta disponibilidad basada en arquitectura maestro-esclavo Arquitectura muy alta y distribuida. Arquitectura distribuida muy alta, múltiples copias de un dato.
confiabilidad del mensaje - Hay una menor probabilidad de perder datos. Después de la optimización y configuración de los parámetros, se puede lograr pérdida cero Después de la configuración de parámetros, los mensajes se pueden perder cero.
Soporte de funciones Desarrollado en base a erlang, por lo que la concurrencia es extremadamente sólida, el rendimiento es excelente y la latencia es baja. Las funciones en el campo MQ son sumamente completas. MQ tiene funciones relativamente completas y buena escalabilidad distribuida. La función es relativamente simple y admite principalmente la función MQ única.
Ventaja Desarrollo del lenguaje Erlang, excelente rendimiento, baja latencia, rendimiento de 10,000 niveles, funciones MQ completas, muy buena interfaz de administración, comunidad activa; ampliamente utilizado por empresas de Internet. Muy maduro y potente, se utiliza en un gran número de empresas y proyectos de la industria. La interfaz es simple y fácil de usar, los productos Alibaba están garantizados, el rendimiento es grande, la expansión distribuida es conveniente, la comunidad es activa, admite temas a gran escala y escenarios comerciales complejos, y se puede personalizar y desarrollar en función de código fuente Rendimiento ultraalto, latencia de nivel ms, disponibilidad y confiabilidad extremadamente altas y expansión distribuida conveniente
Desventajas El rendimiento es bajo, el desarrollo de voz de Erlang no es fácil de personalizar y la expansión dinámica del clúster es problemática. Ocasionalmente existe una baja probabilidad de perder mensajes y la actividad de la comunidad no es alta. La interfaz no sigue la especificación JMS estándar, algunas migraciones del sistema requieren la modificación de una gran cantidad de código y la tecnología corre el riesgo de ser abandonada.
Es posible volver a consumir mensajes.
solicitud todos son usados Se utiliza principalmente para desacoplamiento y asíncrono, menos utilizado en escenarios de rendimiento a gran escala. Utilizado en rendimiento a gran escala y negocios complejos. Se utiliza a gran escala en cálculos en tiempo real y recopilación de registros de big data y es un estándar de la industria.

Para resumir :

Quienes eligen middleware pueden considerar estas dimensiones: confiabilidad, rendimiento, funcionalidad, operatividad, escalabilidad y actividad comunitaria. Actualmente, existen varios middlewares de uso común. ActiveMQ es una "antigüedad" y no se utilizan muchos en el mercado. Hay varios otros middlewares:

  • ConejoMQ:

    • Ventajas: ligero, rápido, fácil de implementar y usar, con configuración de enrutamiento flexible
    • Desventajas: el rendimiento y el rendimiento no son ideales y el desarrollo secundario no es fácil
  • CoheteMQ:

    • Ventajas: buen rendimiento, alto rendimiento, comunidad china activa estable y confiable
    • Desventajas: No muy bueno en términos de compatibilidad.
  • Kafka:

    • Ventajas: rendimiento y rendimiento potentes, buena compatibilidad
    • Desventajas: el retraso es relativamente alto debido a "guardar una ola y luego procesarla"

Nuestro sistema es un sistema del lado C orientado al usuario con una cierta cantidad de concurrencia y requisitos de rendimiento relativamente altos, por lo que elegimos RocketMQ con baja latencia, rendimiento relativamente alto y disponibilidad relativamente buena.

3. ¿Cuáles son las ventajas y desventajas de RocketMQ?

Ventajas de RocketMQ:

  • Rendimiento de una sola máquina: 100.000 niveles
  • Disponibilidad: arquitectura distribuida muy alta
  • Fiabilidad de los mensajes: después de la optimización y configuración de los parámetros, los mensajes no se pueden perder
  • Soporte de funciones: MQ tiene funciones relativamente completas, está distribuido y tiene buena escalabilidad.
  • Admite una acumulación de mensajes de mil millones de niveles sin degradación del rendimiento debido a la acumulación.
  • El código fuente es Java, que es conveniente para el desarrollo secundario combinado con el negocio propio de la empresa.
  • Nacido para el campo financiero de Internet, tiene altos requisitos de confiabilidad, especialmente deducciones de pedidos en el comercio electrónico y reducción de picos comerciales. Cuando llega una gran cantidad de transacciones, es posible que el backend no pueda procesarlas a tiempo.
  • RoketMQ puede ser más confiable en términos de estabilidad. Estos escenarios comerciales se han probado muchas veces durante Alibaba Double 11. Si su empresa tiene los escenarios de concurrencia anteriores, se recomienda elegir RocketMQ.

Desventajas de RocketMQ:

  • No hay muchos lenguajes de cliente compatibles, actualmente Java y C++, de los cuales C++ está inmaduro.
  • JMS y otras interfaces no están implementadas en el núcleo MQ . Algunos sistemas necesitan modificar una gran cantidad de código para migrar.

4. ¿Qué modelos de mensajes tiene la cola de mensajes?

Hay dos modelos de colas de mensajes: modelo de cola y modelo de publicación/suscripción .

  • modelo de cola

    Este es el modelo de cola de mensajes original, correspondiente al modelo de cola de mensajes "enviar-depósito-recibir". Los productores envían mensajes a una cola. Una cola puede almacenar mensajes de múltiples productores y una cola también puede tener múltiples consumidores. Sin embargo, existe una relación de competencia entre los consumidores, lo que significa que cada mensaje solo puede ser enviado por un gasto de consumidor.

imagen-20230918200328531

  • modelo de publicación/suscripción

Si los datos de un mensaje deben distribuirse a varios consumidores y cada consumidor requiere recibir la cantidad total de mensajes. Obviamente, el modelo de cola no puede satisfacer esta demanda. La solución es el modelo de publicación/suscripción.

En el modelo de publicación-suscripción, el remitente del mensaje se llama editor, el receptor del mensaje se llama suscriptor y el contenedor donde se almacena el mensaje en el servidor se llama tema. El editor envía mensajes al tema y el suscriptor debe "suscribirse al tema" antes de recibir el mensaje. "Suscribirse" aquí no es solo una acción, sino que también puede considerarse como una copia lógica del tema al consumirlo. En cada suscripción, el suscriptor puede recibir todos los mensajes del tema.

imagen-20230918200358126

Las similitudes y diferencias entre este y el "modo cola": el productor es el editor, la cola es el tema y el consumidor es el suscriptor. No existe una diferencia esencial. La única diferencia es si los datos de un mensaje se pueden consumir varias veces.

5. ¿Qué pasa con el modelo de mensajes de RocketMQ?

El modelo de mensaje utilizado por RocketMQ es el modelo estándar de publicación-suscripción. En el glosario de RocketMQ, los productores, consumidores y temas son exactamente los mismos que los conceptos del modelo de publicación-suscripción.

El mensaje de RocketMQ en sí se compone de las siguientes partes:

imagen-20230918200532191

  • Mensaje

Mensaje es la información que se va a transmitir.

Un mensaje debe tener un tema (Tema), y el tema puede considerarse como la dirección a la que se enviará su carta.

Un mensaje también puede tener una etiqueta opcional (Etiqueta) y un par clave-valor al final, que se puede usar para establecer una clave comercial y encontrar este mensaje en el Broker para encontrar problemas durante el desarrollo.

  • Tema

El tema puede considerarse como la clasificación de mensajes, que es el tipo de mensaje de primer nivel. Por ejemplo, un sistema de comercio electrónico se puede dividir en: mensajes de transacciones, mensajes de logística, etc. Un mensaje debe tener un Tema.

El tema tiene una relación muy flexible con los productores y consumidores. Un tema puede tener 0, 1 o varios productores enviándole mensajes, y un productor también puede enviar mensajes a diferentes temas al mismo tiempo.

Un tema también puede ser suscrito por 0, 1 o varios consumidores.

  • Etiqueta

Las etiquetas pueden considerarse como subtemas, que son tipos de mensajes de segundo nivel que se utilizan para brindar flexibilidad adicional a los usuarios. Mediante etiquetas, se pueden identificar mensajes con diferentes propósitos en un mismo módulo comercial con el mismo Tema pero con diferentes Etiquetas . Por ejemplo, los mensajes de transacción se pueden dividir en: mensajes de creación de transacción, mensajes de finalización de transacción, etc. Es posible que un mensaje no tenga una etiqueta .

Las etiquetas ayudan a mantener el código limpio y coherente y también ayudan en el sistema de consulta proporcionado por RocketMQ .

  • Grupo

En RocketMQ, el concepto de suscriptores está representado por Consumer Group. Cada grupo de consumidores consume un mensaje completo en el tema y el progreso del consumo entre diferentes grupos de consumidores no se ve afectado entre sí. En otras palabras, un mensaje consumido por el Grupo de Consumidores 1 también será consumido por el Grupo de Consumidores 2.

Un grupo de consumo contiene múltiples consumidores. Los consumidores del mismo grupo compiten por el consumo. Cada consumidor es responsable de consumir parte de los mensajes del grupo. De forma predeterminada, si el consumidor Consumidor1 consume un mensaje, otros consumidores del mismo grupo ya no recibirán este mensaje.

  • Cola de mensajes

Cola de mensajes (cola de mensajes), se pueden configurar varias colas de mensajes bajo un tema y un tema incluye varias colas de mensajes. Si un consumidor necesita obtener todos los mensajes bajo el tema, debe atravesar todas las colas de mensajes.

RocketMQ también tiene otras colas, como ConsumerQueue.

  • Compensar

Durante el proceso de consumo de temas, dado que los mensajes deben ser consumidos varias veces por diferentes grupos, los mensajes consumidos no se eliminarán inmediatamente. Esto requiere que RocketMQ mantenga una posición de consumo en cada cola para cada grupo de consumidores (compensación del consumidor), los mensajes anteriores Esta posición se ha consumido y los mensajes posteriores no se han consumido. Cada vez que un mensaje se consume con éxito, la posición de consumo aumenta en uno.

También se puede decir que Queuees una matriz de longitud infinita y Offset es el subíndice.

En el modelo de mensajes de RocketMQ, estos son los conceptos clave. Haz un dibujo para resumir:

imagen-20230918201004095

6. ¿Entiendes el patrón de consumo de mensajes?

Hay dos modos de consumo de mensajes: Clustering (consumo de clústeres) y Broadcasting (consumo de difusión).

imagen-20230918201137328

El valor predeterminado es el consumo de clúster. En este modo 一个消费者组共同消费一个主题的多个队列,一个队列只会被一个消费者消费, si un consumidor muere, otros consumidores del grupo se harán cargo y continuarán consumiendo.

El mensaje de consumo de transmisión se enviará a todos los consumidores del grupo de consumidores para su consumo.

7.¿Entiendes la estructura básica de RoctetMQ?

Primero veamos la imagen, la arquitectura básica de RocketMQ:

imagen-20230918201312128

RocketMQ consta de cuatro partes: NameServer, Broker, Producer y Consumer, que corresponden a: descubrimiento, envío, almacenamiento y recepción. Para garantizar una alta disponibilidad, cada parte generalmente se implementa en un clúster.

8. ¿Puedes presentar estas cuatro partes?

Analogía con el sistema postal en el que vivimos——

El funcionamiento normal del sistema postal no puede separarse de las cuatro funciones siguientes: una es el remitente, la otra es el destinatario, la tercera es la oficina de correos responsable del almacenamiento temporal y la transmisión, y la cuarta es la agencia de gestión responsable de coordinar varias oficinas de correos locales. Correspondientes a RocketMQ, estos cuatro roles son Productor, Consumidor, Broker y NameServer.

imagen-20230918201430096

Nombre del servidor

NameServer es un servidor sin estado cuya función es similar a Zookeeper utilizada por Kafka, pero es más liviano que Zookeeper.
Características:

  • Cada nodo de NameServer es independiente entre sí y no intercambia información entre sí.
  • El servidor de nombres está diseñado para ser casi sin estado. Se identifica a sí mismo como un pseudoclúster mediante el despliegue de múltiples nodos. El productor obtiene la información de enrutamiento del tema del servidor de nombres antes de enviar el mensaje, es decir, a qué corredor se envía. El consumidor también enviará periódicamente mensajes desde el NameServer. Para obtener la información de enrutamiento del tema, el Broker se registrará en el NameServer cuando se inicie, realizará conexiones de latido con regularidad y sincronizará los temas mantenidos con el NameServer con regularidad.

Hay dos funciones principales:

  • 1. Mantenga una conexión larga con el nodo Broker.
  • 2. Mantener la información de enrutamiento del Tema.
Corredor

La función de almacenamiento y retransmisión de mensajes es responsable de almacenar y reenviar mensajes.

  • El corredor mantiene internamente una cola de consumidores, que se utiliza para almacenar el índice del mensaje. El lugar real donde se almacena el mensaje es el CommitLog (archivo de registro).

  • Un único Broker mantiene conexiones largas y latidos con todos los servidores de nombres y sincroniza periódicamente la información del tema con el servidor de nombres. La comunicación subyacente con el servidor de nombres se implementa a través de Netty.

Productor

Productor de mensajes, el extremo comercial es responsable de enviar mensajes, que son implementados y distribuidos por el usuario.

  • Los usuarios implementan los productores de manera distribuida y los productores envían los mensajes al clúster de intermediarios a través de múltiples modos de equilibrio de carga. Los mensajes se envían con baja latencia y admiten fallas rápidas.

  • RocketMQ proporciona tres formas de enviar mensajes: sincrónico, asincrónico y unidireccional

    • Envío sincrónico : El envío sincrónico significa que después de que el remitente del mensaje envía los datos, solo enviará el siguiente paquete de datos después de recibir la respuesta del receptor. Generalmente se utiliza para mensajes de notificación importantes, como correos electrónicos de notificación importantes y mensajes de texto de marketing.
    • Envío asincrónico : El envío asincrónico significa que después de que el remitente envía los datos, no espera a que el receptor envíe una respuesta y luego envía el siguiente paquete de datos. Generalmente se usa en escenarios comerciales donde el enlace puede tardar mucho tiempo. y es sensible al tiempo de respuesta, como la carga de videos del usuario. Después de la notificación, se inicia el servicio de transcodificación.
    • Envío unidireccional : El envío unidireccional significa que solo es responsable de enviar mensajes sin esperar la respuesta del servidor y no se activa ninguna función de devolución de llamada. Es adecuado para ciertos escenarios que toman muy poco tiempo pero no requieren alta confiabilidad. como la recopilación de registros.
Consumidor

Los consumidores de mensajes son responsables de consumir mensajes y, en general, el sistema backend es responsable del consumo asincrónico.

  • El consumidor también lo implementan los usuarios, admite dos modos de consumo: PUSH y PULL, admite el consumo de clúster y el consumo de transmisión y proporciona un mecanismo de suscripción de mensajes en tiempo real .
  • Pull : los consumidores de extracción extraen activamente información del servidor de mensajes. Siempre que los mensajes se extraigan en lotes, la aplicación del usuario iniciará el proceso de consumo, por lo que la extracción se denomina consumo activo.
  • Push : Push Consumer encapsula la extracción de mensajes, el progreso del consumo y otros trabajos de mantenimiento interno, dejando la interfaz de devolución de llamada ejecutada cuando el mensaje llega a la aplicación del usuario. Por lo tanto, Push se denomina tipo de consumo pasivo, pero de hecho, desde el punto de vista de la implementación, todavía extrae mensajes del servidor de mensajes. A diferencia de Pull, Push primero debe registrar un oyente de consumo y solo comienza a consumir mensajes cuando el oyente está motivado.

Avanzado

9. ¿Cómo garantizar la disponibilidad/fiabilidad/no pérdida de mensajes?

¿En qué etapas se pueden perder los mensajes? La pérdida puede ocurrir en estas tres etapas: etapa de producción, etapa de almacenamiento y etapa de consumo.

Así que considere estas tres etapas:

imagen-20230918202031047

Producción

En la etapa de producción, el mecanismo de confirmación de solicitud se utiliza principalmente para garantizar la entrega confiable de mensajes .

  • 1. Al realizar envíos sincrónicos, preste atención al manejo de los resultados de la respuesta y las excepciones. Si la respuesta es OK, significa que el mensaje se envió exitosamente al Broker. Si la respuesta falla u ocurren otras excepciones, debe intentarlo nuevamente.
  • 2. Al enviar de forma asincrónica, debes verificarlo en el método de devolución de llamada. Si el envío falla o es anormal, debes intentarlo nuevamente.
  • 3. Si se agota el tiempo de espera, también puede verificar si el almacenamiento en el Broker se realizó correctamente consultando la API de registro.
almacenamiento

En la fase de almacenamiento, puede configurar los parámetros del Broker que priorizan la confiabilidad para evitar perder mensajes debido al tiempo de inactividad . En pocas palabras, la sincronización debe usarse en escenarios donde se prioriza la confiabilidad.

  • 1. Siempre que los mensajes persistan en el CommitLog (archivo de registro), incluso si el Broker deja de funcionar, los mensajes no consumidos se pueden restaurar y consumir nuevamente.
  • 2. Mecanismo de cepillado de disco del intermediario: cepillado de disco sincrónico y cepillado de disco asincrónico. No importa qué tipo de cepillado de disco, se puede garantizar que el mensaje se almacenará en el caché de página (en la memoria), pero el cepillado de disco sincrónico es más confiable. Es el datos que el Productor espera después de enviar el mensaje. Después de persistir en el disco, la respuesta se devuelve al Productor.
  • 3. El Broker garantiza una alta disponibilidad a través del modo maestro-esclavo. El Broker admite replicación sincrónica Maestro y Esclavo, modo de replicación asincrónica Maestro y Esclavo. Los mensajes del productor se envían al Maestro, pero el consumo se puede consumir desde el Maestro o el Esclavo. El modo de replicación sincrónica puede garantizar que incluso si el Maestro está inactivo, el mensaje definitivamente será respaldado en el Esclavo, asegurando que el mensaje no se pierda.

imagen-20230918202927817

Consumo

Desde la perspectiva del consumidor, ¿cómo garantizar que los mensajes se consuman correctamente?

  • La clave para que el consumidor garantice el consumo exitoso de mensajes radica en el momento de la confirmación: no envíe la confirmación de consumo inmediatamente después de recibir el mensaje, sino que envíe la confirmación de consumo después de ejecutar toda la lógica empresarial de consumo. Debido a que la cola de mensajes mantiene la posición de consumo, la ejecución lógica falla y no hay confirmación. Si va a la cola para extraer el mensaje nuevamente, seguirá siendo el mensaje anterior.

10. ¿Cómo afrontar el problema de la duplicación de mensajes?

Para las colas de mensajes distribuidos, es difícil garantizar una entrega segura y no repetida al mismo tiempo, lo que se denomina "una y solo una vez". RocketMQ ha optado por garantizar una entrega determinada para garantizar que los mensajes no se pierdan, pero esto puede provocar la duplicación de mensajes.

El problema de la duplicación de mensajes lo maneja principalmente el propio fin comercial, existen dos métodos principales: idempotencia empresarial y deduplicación de mensajes .

Idempotencia empresarial : El primero es garantizar la idempotencia de la lógica de consumo, es decir, el efecto de varias llamadas y una llamada es el mismo. De esta forma, por muchas veces que se consuma el mensaje, no tendrá ningún impacto en el negocio.

Deduplicación de mensajes : el segundo tipo es el final comercial, que ya no consumirá mensajes duplicados. Este método debe garantizar que cada mensaje tenga un número único, que generalmente está relacionado con el negocio, como el número de pedido. El registro de consumo debe almacenarse en la base de datos y se debe garantizar la atomicidad del paso de confirmación del mensaje.

El método específico es crear una tabla de registro de consumo y recibir este mensaje para realizar una operación de inserción en la base de datos. Asigne a este mensaje una clave primaria única (clave primaria) o una restricción única. Incluso si ocurre un consumo repetido, causará un conflicto de clave primaria y el mensaje ya no se procesará.

11. ¿Cómo lidiar con la acumulación de mensajes?

Cuando se produce una acumulación de mensajes, debe encontrar una manera de consumir rápidamente la acumulación de mensajes y debe considerar mejorar su capacidad de consumo. Generalmente existen dos métodos:

imagen-20230918203127950

  • Expansión del consumidor : si el número de la cola de mensajes del tema actual es mayor que el número de consumidores, los consumidores se pueden expandir y se pueden agregar más consumidores para aumentar la capacidad de consumo y consumir la acumulación de mensajes lo antes posible.
  • Expansión de la cola de migración de mensajes : si la cantidad de colas de mensajes en el tema actual es menor o igual que la cantidad de consumidores, en este caso, es inútil expandir la cantidad de consumidores y debe considerar expandir la cola de mensajes. Puede crear un nuevo tema temporal, configurar más colas de mensajes en el tema temporal y luego usar algunos consumidores para enviar los datos consumidos al tema temporal. Debido a que no hay necesidad de procesamiento comercial, solo se reenvía el mensaje. que sigue siendo muy rápido. A continuación, utilice el consumidor ampliado para consumir los datos en el nuevo tema y, una vez completado el consumo, restaure el estado original.

imagen-20230918203319817

12. ¿Cómo implementar mensajes secuenciales?

Los mensajes secuenciales significan que el orden de consumo del mensaje es el mismo que el orden de producción. Según alguna lógica empresarial, el orden debe estar garantizado, como la generación, el pago y la entrega del pedido. Este mensaje debe procesarse en orden.

Los mensajes secuenciales se dividen en mensajes secuenciales globales y mensajes secuenciales parciales:

Los mensajes secuenciales globales significan que todos los mensajes bajo un determinado tema deben garantizar el orden;

Para algunos mensajes secuenciales, solo necesita asegurarse de que cada grupo de mensajes se consuma en orden. Por ejemplo, para los mensajes de pedido, solo necesita asegurarse de que los mensajes con el mismo ID de pedido se puedan consumir en orden.

mensaje de secuencia parcial

Los mensajes secuenciales parciales son relativamente fáciles de implementar. El extremo de producción necesita enviar mensajes con el mismo ID a la misma cola de mensajes; durante el proceso de consumo, los mensajes leídos de la misma cola de mensajes deben procesarse secuencialmente; el extremo del consumidor no puede ser concurrente Procesar mensajes secuenciales para poder lograr un orden parcial.

imagen-20230918203535409

El remitente utiliza la clase MessageQueueSelector para controlar a qué cola de mensajes se envía el mensaje.

El lado del consumidor utiliza MessageListenerOrderly para resolver el problema de que los mensajes en una única cola de mensajes se procesen simultáneamente.

mensaje de secuencia global

RocketMQ no garantiza el orden de forma predeterminada. Por ejemplo, al crear un tema, hay ocho colas de escritura y ocho colas de lectura de forma predeterminada. En este momento, un mensaje se puede escribir en cualquier cola; durante el proceso de lectura de datos, puede haber múltiples Consumidores, cada Consumidor también puede iniciar múltiples subprocesos para el procesamiento paralelo, por lo que no está claro qué Consumidor consume el mensaje y si el orden en el que se consume es consistente con el orden en que se escribió.

Para garantizar mensajes secuenciales globales, primero debe establecer el número de colas de lectura y escritura del tema en uno y luego establecer la configuración de concurrencia del productor consumidor en uno. En pocas palabras, para garantizar que los mensajes globales de todo el tema estén en orden, solo se puede eliminar todo el procesamiento concurrente y configurar cada parte para el procesamiento de un solo subproceso. En este momento, las características de alta concurrencia y alto rendimiento de RocketMQ están completamente sacrificados.

imagen-20230918203719183

13. ¿Cómo implementar el filtrado de mensajes?

Hay dos opciones:

  • Una es filtrar en el lado del Broker de acuerdo con la lógica de deduplicación del Consumidor. La ventaja de esto es evitar que se transmitan mensajes inútiles al lado del Consumidor. La desventaja es que aumenta la carga para el Broker y es relativamente complicado de implementar.
  • El otro es filtrar en el lado del consumidor, como la deduplicación según la etiqueta establecida en el mensaje. La ventaja de esto es que es fácil de implementar, la desventaja es que una gran cantidad de mensajes inútiles llegan al lado del consumidor y Sólo se puede descartar sin procesar.

Generalmente, se utiliza el filtrado del lado del consumidor. Si desea mejorar el rendimiento, se puede utilizar el filtrado del intermediario.

Hay tres formas de filtrar mensajes:

imagen-20230918203833864

  • Filtrado basado en Etiqueta: Este es el más común y es eficiente y sencillo de usar.

    DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("CID_EXAMPLE");
    consumer.subscribe("TOPIC", "TAGA || TAGB || TAGC");
    
  • Filtrado de expresiones SQL: el filtrado de expresiones SQL es más flexible

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4");
// 只有订阅的消息有这个属性a, a >=0 and a <= 3
consumer.subscribe("TopicTest", MessageSelector.bySql("a between 0 and 3");
consumer.registerMessageListener(new MessageListenerConcurrently() {
    
    
   @Override
   public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
    
    
       return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
   }
});
consumer.start();
  • Método Filter Server: el método más flexible y complejo, que permite a los usuarios personalizar funciones de filtrado

14. ¿Entiendes el mensaje retrasado?

La cancelación automática de pedidos de comercio electrónico después del tiempo de espera es un ejemplo típico del uso de mensajes retrasados. Después de que el usuario envía un pedido, puede enviar un mensaje retrasado. Después de 1 hora, se comprobará el estado del pedido. Si el Aún no se realiza el pago, el pedido será cancelado y liberado.

RocketMQ admite mensajes retrasados. Solo necesita establecer el nivel de retraso del mensaje al generar el mensaje:

// 实例化一个生产者来产生延时消息
DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
// 启动生产者
producer.start();
int totalMessagesToSend = 100;
for (int i = 0; i < totalMessagesToSend; i++) {
    
    
    Message message = new Message("TestTopic", ("Hello scheduled message " + i).getBytes());
    // 设置延时等级3,这个消息将在10s之后发送(现在只支持固定的几个时间,详看delayTimeLevel)
    message.setDelayTimeLevel(3);
    // 发送消息
    producer.send(message);
}

Sin embargo, los niveles de retraso admitidos actualmente por RocketMQ son limitados:

private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";

¿Cómo implementa RocketMQ los mensajes retrasados?

Sencillo, ocho palabras: 临时存储+ 定时任务.

Cuando el Broker recibe el mensaje retrasado, primero lo enviará a la cola de mensajes del período de tiempo correspondiente al tema (SCHEDULE_TOPIC_XXXX), y luego sondeará estas colas a través de una tarea programada. Después de la expiración, el mensaje se entregará a la cola del tema de destino, y luego los consumidores pueden consumir estos mensajes normalmente.

imagen-20230918204154153

15. ¿Cómo implementar transacciones de mensajes distribuidos? ¿Medio mensaje?

Semimensaje: se refiere al mensaje que el Consumidor no puede consumir por el momento. El Productor envía con éxito el mensaje al Corredor. Sin embargo, este mensaje está marcado como "temporalmente no entregable" y solo puede confirmarse después de que el Productor haya completó la transacción local. El consumidor puede consumir este mensaje.

Basándose en semimensajes, se pueden implementar transacciones de mensajes distribuidos, cuya clave radica en la confirmación secundaria y la revisión del mensaje:

imagen-20230918204332135

  • 1. El productor envía un mensaje a medias al corredor
  • 2. El Productor recibe la respuesta y el mensaje se envía con éxito, en este momento el mensaje es medio mensaje, marcado como "no entregable" y el Consumidor no puede consumirlo.
  • 3. El lado del Productor ejecuta transacciones locales.
  • 4. En circunstancias normales, cuando se completa la ejecución de la transacción local, el Productor envía un Commit / Rollback al Broker. Si es un Commit, el Broker marcará el medio mensaje como un mensaje normal y el Consumidor puede consumirlo. Si se trata de un Rollback, el Broker descartará el mensaje.
  • 5. En circunstancias anormales, el Corredor no puede esperar la segunda confirmación. Después de un cierto período de tiempo, se consultarán todos los semimensajes y luego el estado de ejecución de los semimensajes se consultará en el lado del Productor.
  • 6. El lado del Productor consulta el estado de las transacciones locales.
  • 7. Enviar confirmación/reversión al corredor según el estado de la transacción. (5, 6, 7 son revisión de mensajes)
  • 8. Una vez que el segmento de consumidores consume el mensaje, ejecuta transacciones locales y ejecuta transacciones locales.

16.¿Conoce la cola de mensajes fallidos?

La cola de mensajes no entregados se utiliza para procesar mensajes que no se pueden consumir normalmente, es decir, mensajes de mensajes no entregados.

Cuando un mensaje no se puede consumir por primera vez, Message Queue RocketMQ reintentará automáticamente el mensaje ; después de alcanzar el número máximo de reintentos, si el consumo aún falla, significa que el consumidor no puede consumir el mensaje correctamente en circunstancias normales. En este momento, el mensaje de Message Queue RocketMQ no se descartará inmediatamente, sino que se enviará a una cola especial correspondiente al consumidor , que se denomina cola de mensajes no entregados .

Características de los mensajes de letra muerta :

  • Los consumidores ya no lo consumirán normalmente.
  • El período de validez es el mismo que el de los mensajes normales, que es de 3 días, se eliminará automáticamente después de 3 días. Por lo tanto, los mensajes de letra muerta deben procesarse con prontitud dentro de los 3 días posteriores a su generación.

Características de la cola de mensajes fallidos :

  • Una cola de mensajes fallidos corresponde a un ID de grupo, no a una única instancia de consumidor.
  • Si un ID de grupo no genera un mensaje de mensajes no entregados, Message Queue RocketMQ no creará una cola de mensajes no entregados correspondiente para él.
  • Una cola de mensajes no entregados contiene todos los mensajes de mensajes no entregados generados por el ID de grupo correspondiente, independientemente del tema al que pertenezca el mensaje.

La consola RocketMQ proporciona las funciones de consultar, exportar y reenviar mensajes no entregados.

17. ¿Cómo garantizar la alta disponibilidad de RocketMQ?

Debido a que los NameServers no tienen estado y no se comunican entre sí, se puede garantizar una alta disponibilidad siempre que se implementen en un clúster.

imagen-20230918205657048

La alta disponibilidad de RocketMQ se refleja principalmente en la alta disponibilidad de lectura y escritura del Broker, que se logra a través 集群de y .主从

imagen-20230918205744712

El Broker se puede configurar con dos roles: Maestro y Esclavo. El Broker en el rol Maestro admite lectura y escritura, y el Broker en el rol Esclavo solo admite lectura. El Maestro sincronizará los mensajes con el Esclavo.

En otras palabras, el Productor solo puede escribir mensajes al Broker en el rol Maestro, y el Consumidor puede leer mensajes del Broker en los roles Maestro y Esclavo.

En el archivo de configuración del Consumidor, no es necesario establecer si leer desde el Maestro o el Esclavo. Cuando el Maestro no está disponible o está ocupado, la solicitud de lectura del Consumidor cambiará automáticamente al Esclavo. Con el mecanismo de cambio automático de Consumidores, cuando falla una máquina en el rol Maestro, el Consumidor aún puede leer mensajes del Esclavo sin afectar la lectura de mensajes por parte del Consumidor, lo que logra una alta disponibilidad de lectura.

¿Cómo lograr una alta disponibilidad de escrituras en el lado emisor? Al crear un tema, cree varias colas de mensajes del tema en varios grupos de intermediarios (el mismo nombre de intermediario, diferentes máquinas con ID de intermediario forman un grupo de intermediarios), de modo que cuando el maestro del grupo de intermediarios deje de estar disponible, el maestro de otros grupos todavía esté disponible, y el Productor aún puede enviar mensajes. RocketMQ actualmente no admite la conversión automática de Esclavo a Maestro. Si los recursos de la máquina son insuficientes y necesita convertir Esclavo a Maestro, debe detener manualmente el Broker de color Esclavo, cambiar el archivo de configuración e inicie Broker con un nuevo archivo de configuración.

principio

18. ¿Cuénteme sobre el flujo de trabajo general de RocketMQ?

En pocas palabras, RocketMQ es una cola de mensajes distribuida, es decir 消息队列+ 分布式系统.

Como cola de mensajes, es un modelo de - , correspondiente a Productor, Broker y Consumidor; como sistema distribuido, debe tener un servidor, cliente y centro de registro, correspondiente a Broker, Productor/Consumidor y NameServer.

Entonces, echemos un vistazo a su flujo de trabajo principal: RocketMQ consta del clúster del centro de registro de NameServer, el clúster de productores, el clúster de consumidores y varios corredores (procesos RocketMQ):

  1. El corredor se registra en todos los NameServers cuando se inicia, mantiene una conexión larga y envía un latido cada 30 segundos.
  2. El Productor obtiene la dirección del servidor Broker del NameServer al enviar un mensaje y selecciona un servidor para enviar el mensaje según el algoritmo de equilibrio de carga.
  3. Cuando Conusmer consume mensajes, también obtiene la dirección del Broker de NameServer y luego extrae activamente los mensajes para su consumo.

imagen-20230918214743408

19. ¿Por qué RocketMQ no utiliza Zookeeper como centro de registro?

Todos sabemos que Kafka usa Zookeeper como centro de registro; por supuesto, gradualmente ha comenzado a usar Zookeeper, RocketMQ no usa Zookeeper, de hecho, se puede considerar principalmente desde los siguientes aspectos:

La teoría CAP se refiere al hecho de que en un sistema distribuido, la coherencia, la disponibilidad y la tolerancia de la partición no se pueden establecer al mismo tiempo.

  1. Según consideraciones de disponibilidad, según la teoría CAP, solo se pueden satisfacer dos puntos al mismo tiempo, y Zookeeper satisface CP, lo que significa que Zookeeper no puede garantizar la disponibilidad del servicio. Cuando Zookeeper realiza una elección, todo el tiempo de elección es demasiado largo. Durante este período, todo el clúster está en un estado no disponible, lo que definitivamente es inaceptable para un centro de registro. Como descubrimiento de servicios, debe diseñarse para disponibilidad.
  2. Según consideraciones de rendimiento, la implementación de NameServer en sí es muy liviana y se puede expandir horizontalmente agregando máquinas para aumentar la resistencia a la presión del clúster. Sin embargo, la escritura de Zookeeper no es escalable. Zookeeper solo puede resolver este problema dividiendo áreas. Dividiendo múltiples clústeres de Zookeeper Resolver este problema es, en primer lugar, demasiado complicado de operar y, en segundo lugar, viola el diseño de A en CAP, lo que resulta en la desconexión entre servicios.
  3. Problemas causados ​​por el mecanismo de persistencia. El protocolo ZAB de ZooKeeper seguirá escribiendo un registro de transacciones en cada nodo de ZooKeeper para cada solicitud de escritura y, al mismo tiempo, reflejará periódicamente (instantáneas) los datos de la memoria en el disco para garantizar la coherencia y persistencia de los datos. , Pero para un escenario simple de descubrimiento de servicios, esto en realidad no es necesario. Esta solución de implementación es demasiado pesada. Y los datos almacenados deben ser altamente personalizados.
  4. El envío de mensajes debe depender débilmente del centro de registro, y el concepto de diseño de RocketMQ se basa en esto. Cuando el productor envía el mensaje por primera vez, obtiene la dirección del Broker del NameServer y la almacena en caché localmente. Si todo el clúster de NameServer Si no está disponible, se almacenará en caché localmente en poco tiempo y no tendrá mucho impacto en los productores y consumidores.

20.¿Cómo guarda Broker los datos?

Los archivos de almacenamiento principales de RocketMQ incluyen archivos CommitLog, archivos ConsumeQueue y archivos Indexfile.

CommitLog : El cuerpo de almacenamiento del cuerpo del mensaje y los metadatos. Almacena el contenido del cuerpo del mensaje escrito por el Productor. El contenido del mensaje no tiene una longitud fija. El tamaño predeterminado de un solo archivo es 1G, la longitud del nombre del archivo es de 20 dígitos, los ceros se rellenan a la izquierda y el resto es el desplazamiento inicial. Por ejemplo, 000000000000000000000 representa el primer archivo, el desplazamiento inicial es 0, y el tamaño del archivo es 1G = 1073741824; cuando 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 el siguiente archivo.

El archivo CommitLog se guarda en el directorio ${Rocket_Home}/store/commitlog. En la figura, podemos ver claramente el desplazamiento del nombre del archivo. Cada archivo tiene por defecto 1G. Cuando está lleno, se genera automáticamente un nuevo archivo.

ConsumeQueue : cola de consumo de mensajes. El objetivo principal de su introducción es mejorar el rendimiento del consumo de mensajes. Dado que RocketMQ es un modelo de suscripción basado en el tema, el consumo de mensajes es para el tema. Si desea atravesar el archivo de registro de confirmación para recuperar mensajes Según el tema, es muy ineficiente.

El consumidor puede utilizar ConsumeQueue para buscar mensajes que consumir. Entre ellos, ConsumeQueue (cola de consumo lógica) sirve como índice de mensajes de consumo y guarda el desplazamiento físico inicial del mensaje de la 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 puede considerarse como un archivo de índice CommitLog basado en el tema. Por lo tanto, la carpeta ConsumeQueue está organizada de la siguiente manera: estructura organizativa de tres capas tema/cola/archivo. La ruta de almacenamiento específica es: $HOME/store/consumequeue/{ tema}/{queueId }/{fileName}. De manera similar, el archivo ConsumeQueue adopta un diseño de longitud fija. Cada entrada tiene un total de 20 bytes, que son un desplazamiento físico de CommitLog de 8 bytes, una longitud de mensaje de 4 bytes y un código hash de etiqueta de 8 bytes. Un solo archivo consta de entradas de 30 W. Se puede acceder a cada entrada de forma aleatoria como una matriz, y el tamaño de cada archivo ConsumeQueue es de aproximadamente 5,72 M;

IndexFile : IndexFile (archivo de índice) proporciona un método para consultar mensajes por clave o intervalo de tiempo. La ubicación de almacenamiento del archivo Index es: {fileName}. El nombre del archivo fileName lleva el nombre de la marca de tiempo cuando se creó. El tamaño fijo de un único archivo IndexFile es de aproximadamente 400 M. Un IndexFile puede guardar índices de 2000 W. El almacenamiento subyacente de IndexFile está diseñado para estar en el archivo. La estructura HashMap se implementa en el sistema, por lo que la implementación subyacente del archivo de índice de RocketMQ es un índice hash.

imagen-20230918214945104

Para resumir: RocketMQ utiliza una estructura de almacenamiento híbrida, lo que significa que todas las colas bajo una única instancia de Broker comparten un archivo de datos de registro (CommitLog) para almacenar.

La estructura de almacenamiento híbrida de RocketMQ (el contenido de la entidad de mensaje de varios temas se almacena en un CommitLog) utiliza una estructura de almacenamiento que separa los datos y las partes del índice para el Productor y el Consumidor, respectivamente. El Productor envía mensajes al lado del Broker y luego el lado del Broker usa la sincronización O persista asincrónicamente el mensaje y guárdelo en CommitLog.

Mientras el mensaje persista en el archivo de disco CommitLog, el mensaje enviado por el Productor no se perderá. Debido a esto, el consumidor definitivamente tendrá la oportunidad de consumir este mensaje. Cuando el mensaje no se puede extraer, puede esperar a que se extraiga el siguiente mensaje. Al mismo tiempo, el servidor también admite el modo de sondeo largo. Si una solicitud de extracción de mensaje no extrae el mensaje, el Broker puede esperar 30 segundos. Siempre que pase este tiempo, cuando lleguen nuevos mensajes, se devolverán directamente al consumidor.

Aquí, el enfoque específico de RocketMQ es utilizar el hilo de servicio en segundo plano en el lado del Broker: ReputMessageService para distribuir continuamente solicitudes y construir de forma asincrónica datos ConsumeQueue (cola de consumo lógico) e IndexFile (archivo de índice).

imagen-20230918215018016

21. ¿Habla sobre cómo RocketMQ lee y escribe archivos?

La lectura y escritura de archivos de RocketMQ utiliza inteligentemente algunos métodos eficientes de lectura y escritura de archivos del sistema operativo: PageCache, 顺序读写.零拷贝

  • PageCache, lectura secuencial

En RocketMQ, la cola de consumo lógico ConsumeQueue almacena menos datos y se lee secuencialmente. 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 leer la memoria, incluso cuando hay acumulación de mensajes. No hay impacto en el rendimiento. Para los archivos de datos de registro almacenados en los mensajes CommitLog, se producirán más lecturas de acceso aleatorio al leer el contenido del mensaje, lo que afectará seriamente el rendimiento. Si elige un algoritmo de programación de IO del sistema apropiado, como configurar el algoritmo de programación en "Fecha límite" (si el almacenamiento en bloque usa SSD en este momento), también mejorará el rendimiento de la lectura aleatoria.

La caché de página (PageCache) es la 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 de un programa es casi cercana a la velocidad de lectura y escritura de la memoria, la razón principal es que el sistema operativo utiliza el mecanismo PageCache para optimizar el rendimiento de las operaciones y usos de acceso de lectura y escritura. una parte de la memoria como PageCache. Para la escritura de datos, el sistema operativo primero los escribirá en la caché y luego el subproceso del kernel pdflush descargará los datos de la caché en el disco físico de forma asincrónica. Para la lectura de datos, si se produce un error de PageCache al leer un archivo, el sistema operativo leerá previamente secuencialmente los archivos de datos de otros bloques adyacentes mientras accede al archivo leído desde el disco físico.

  • copia cero

Además, RocketMQ lee y escribe archivos principalmente a través de MappedByteBuffer. Entre ellos, el modelo FileChannel en NIO se utiliza para asignar directamente archivos físicos en el disco a direcciones de memoria en modo de usuario (este método Mmap reduce el IO tradicional y almacena los datos del archivo del disco en el búfer del espacio de direcciones del kernel del sistema operativo, y el rendimiento sobrecarga de copiar de un lado a otro entre buffers en el espacio de direcciones de la aplicación del usuario), convirtiendo operaciones de archivos en operaciones directas en direcciones de memoria, mejorando así en gran medida la eficiencia de lectura y escritura de archivos (precisamente debido a la necesidad de utilizar el mecanismo de mapeo de memoria, por lo que El almacenamiento de archivos de RocketMQ utiliza estructuras de longitud fija para facilitar la asignación de todo el archivo a la memoria a la vez).

¿Qué es la copia cero?

En el sistema operativo, utilizando el método tradicional, los datos deben copiarse varias veces y deben pasar por el modo de usuario/modo kernel.

imagen-20230918215058881

  1. Copie datos del disco a la memoria en modo kernel;
  2. Copiar de la memoria en modo kernel a la memoria en modo usuario;
  3. Luego copie desde la memoria en modo usuario a la memoria en modo kernel del controlador de red;
  4. Finalmente, se copia desde la memoria en modo kernel del controlador de red a la tarjeta de red para su transmisión.

Por lo tanto, la copia cero se puede utilizar para reducir la cantidad de cambios de contexto y copias de memoria entre el modo de usuario y el modo kernel para mejorar el rendimiento de E/S. La implementación más común de copia cero esmmap , Este mecanismo se implementa en Java a través de MappedByteBuffer.

imagen-20230918215120209

22. ¿Cómo se implementa el vaciado de mensajes?

RocketMQ proporciona dos estrategias de cepillado de disco: cepillado de disco sincrónico y cepillado de disco asincrónico.

  • Vaciado sincrónico: una vez que el mensaje llega a la memoria del Broker, debe vaciarse en el archivo de registro commitLog para que se considere exitoso y luego se le devolverá al Productor que los datos se enviaron exitosamente.
  • Descarga asincrónica: la descarga asincrónica significa que después de que el mensaje llega a la memoria del Broker, le devuelve al Productor que los datos se enviaron correctamente y se activa un subproceso para conservar los datos en el archivo de registro CommitLog.

El corredor opera directamente la memoria (archivos asignados en memoria) al acceder a los mensajes, lo que puede mejorar el rendimiento del sistema, pero no puede evitar la pérdida de datos cuando la máquina está apagada, por lo que es necesario conservarlos en el disco.

La implementación final del cepillado de disco usa MappedByteBuffer.force () en NIO para escribir los datos en el área de mapeo en el disco. Si se trata de un cepillado de disco sincrónico, después de que el Broker escriba el mensaje en el área de mapeo de CommitLog, esperará la escritura para completar. .

En términos de operación asincrónica, solo activa el hilo correspondiente y no garantiza el tiempo de ejecución, el proceso es como se muestra en la figura.

imagen-20230918215157713

22. ¿Puede decirme cómo se implementa el equilibrio de carga de RocketMQ?

El equilibrio de carga en RocketMQ se completa en el lado del cliente, específicamente, se puede dividir en equilibrio de carga cuando el lado Productor envía mensajes y equilibrio de carga cuando el lado Consumidor se suscribe a mensajes.

Equilibrio de carga del productor

Cuando el productor envía un mensaje, primero encontrará el TopicPublishInfo especificado según 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 (). para enviar un mensaje. Aquí hay una variable de cambio sendLatencyFaultEnable. Si está activada, los agentes de Broker que no están disponibles se filtrarán según el módulo de incremento aleatorio.

imagen-20230918215220144

La llamada "latencyFaultTolerance" se refiere a retroceder durante un cierto período de tiempo debido a fallas anteriores. Por ejemplo, si la latencia de la última solicitud excede los 550 Lms, retrocederá 3000 Lms; si excede los 1000 L, retrocederá 60000 L; si está cerrada, se seleccionará una cola (MessageQueue) usando un módulo de incremento aleatorio para enviar mensajes. El mecanismo de latenciaFaultTolerance es lograr una alta disponibilidad para el envío de mensajes, la clave principal.

Equilibrio de carga del consumidor

En RocketMQ, los dos modos de consumo (Push / Pull) en el lado del Consumidor se basan en el modo pull para obtener mensajes. El modo Push es solo una encapsulación del modo pull. Su esencia es que el hilo de extracción de mensajes extrae el mensaje de el servidor Después de recibir un lote de mensajes y luego enviarlos al grupo de subprocesos de consumo de mensajes, continuarán intentando extraer mensajes del servidor "sin parar". Si el mensaje no se recupera, se retrasará un tiempo y luego se recuperará nuevamente. En ambos métodos de consumo basados ​​en pull (Push/Pull), el lado del consumidor necesita saber de qué cola de mensajes del lado del Broker obtener mensajes. Por lo tanto, es necesario realizar un equilibrio de carga en el lado del Consumidor, es decir, se asignan múltiples MessageQueue en el lado del Broker a los cuales consumen los Consumidores en el mismo Grupo de Consumidores.

  1. Envío de paquetes de latidos en el lado del consumidor

Una vez que se inicia el Consumidor, enviará continuamente paquetes de latidos a todas las instancias del Broker en el clúster RocketMQ a través de tareas programadas (que contienen información como el nombre del grupo de consumo de mensajes, la colección de relaciones de suscripción, el modo de comunicación del mensaje y el valor). de la identificación del cliente). Después de recibir el mensaje de latido del Consumidor, el Broker lo mantendrá en la variable de caché local de ConsumerManager - consumerTable y, al mismo tiempo, guardará la información encapsulada del canal de red del cliente en la variable de caché local - channelInfoTable, para su posterior carga en el lado del Consumidor. Balance proporciona información de metadatos en la que se puede confiar.

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

En el proceso de inicio de la instancia del Consumidor, el inicio de la instancia MQClientInstance completará el inicio del subproceso del servicio de equilibrio de carga: RebalanceService (se ejecuta cada 20 segundos).

Al observar el código fuente, podemos encontrar que el método run() del subproceso RebalanceService finalmente llama al método rebalanceByTopic() de la clase RebalanceImpl, que es el núcleo para lograr el equilibrio de carga del lado del consumidor.

El método rebalanceByTopic() realizará un procesamiento lógico diferente dependiendo de si el tipo de comunicación del consumidor es "modo de transmisión" o "modo de clúster". Aquí analizamos principalmente los principales procedimientos de procesamiento en modo clúster:

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

(2) Llame al método mQClientFactory.findConsumerIdList() según el tema y consumerGroup como parámetros para enviar una solicitud de comunicación al Broker para obtener la lista de ID de consumidores bajo el grupo de consumidores;

(3) Primero ordene las colas de consumo de mensajes y las ID de los consumidores bajo el tema, y ​​luego use el algoritmo de estrategia de asignación de colas de mensajes (el valor predeterminado es: el algoritmo de asignación promedio de la cola de mensajes) para calcular la cola de mensajes que se extraerá. El algoritmo de asignación promedio aquí es similar al algoritmo de paginación: clasifica todas las MessageQueues como registros, clasifica a todos los consumidores como el número de páginas y encuentra el tamaño promedio y los registros de cada página que cada página debe contener. recorra todo el rango para calcular el MessageQueue que debe asignarse al lado del consumidor actual.

imagen-20230918215304192

(4) Luego, llame al método updateProcessQueueTableInRebalance (). El método específico es realizar primero una comparación de filtrado entre el conjunto de colas de mensajes asignado (mqSet) y ProcessQueueTable.

imagen-20230918215322343

  • La parte roja marcada por ProcessQueueTable en la figura anterior indica que no está incluida en 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 removeUnnecessaryMessageQueue () se ejecuta específicamente, es decir, cada 1 s, verifique si el bloqueo del consumo actual Se puede obtener la cola de procesamiento y devolver verdadero si se obtiene. Si después de esperar 1 segundo, aún no se obtiene el bloqueo de la cola de procesamiento de consumo actual, se devolverá falso. Si se devuelve verdadero, la entrada correspondiente se elimina de la variable de caché ProcessQueueTable;
  • La parte verde de ProcessQueueTable en la figura anterior representa la intersección con el conjunto de colas de mensajes asignado mqSet. Determine si ProcessQueue ha caducado. No se preocupe en el modo Pull. Si está en modo Push, establezca el atributo Dropped en verdadero, llame al método removeUnnecessaryMessageQueue() e intente 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 de RebalanceImpl para obtener el siguiente consumo de progreso del Desplazamiento del valor del objeto MessageQueue y luego rellénelo en el atributo del objeto pullRequest que se creará a continuación), cree el objeto de solicitud de extracción-pullRequest y agréguelo a la lista de extracción-pullRequestList. Finalmente, ejecute el método despachoPullRequest() y coloque el objeto de solicitud PullRequest del mensaje Pull en secuencia, ingrese a la cola de bloqueo pullRequestQueue del hilo de servicio PullMessageService y luego inicie una solicitud de mensaje Pull al Broker después de que se elimine el hilo de servicio. Entre ellos, puede centrarse en la comparación. El método de despachoPullRequest () de las dos clases de implementación RebalancePushImpl y RebalancePullImpl es diferente. El método en la clase RebalancePullImpl está vacío.

El concepto de diseño central del equilibrio de carga de la cola de consumo de mensajes entre diferentes consumidores en el mismo grupo de consumidores es que solo un consumidor en el mismo grupo de consumidores puede consumir una cola de consumo de mensajes al mismo tiempo, y un consumidor de mensajes puede consumir múltiples mensajes al mismo tiempo cola de mensajes.

23.¿Entiendes el sondeo largo de mensajes de RocketMQ?

El llamado sondeo largo significa que el consumidor extrae mensajes. Si la cola correspondiente no tiene datos, el corredor no regresará inmediatamente, sino que retendrá el PullReuqest y esperará a que la cola tenga mensajes o se acabe el tiempo de bloqueo del sondeo prolongado. expiró antes de reiniciar. Procese todas las solicitudes de extracción en esta cola.

imagen-20230918215353728

  • PullMessageProcessor#procesoSolicitud

    //如果没有拉到数据
    case ResponseCode.PULL_NOT_FOUND:
    // broker 和 consumer 都允许 suspend,默认开启
    if (brokerAllowSuspend && hasSuspendFlag) {
          
          
        long pollingTimeMills = suspendTimeoutMillisLong;
        if (!this.brokerController.getBrokerConfig().isLongPollingEnable()) {
          
          
            pollingTimeMills = this.brokerController.getBrokerConfig().getShortPollingTimeMills();
        }
    
        String topic = requestHeader.getTopic();
        long offset = requestHeader.getQueueOffset();
        int queueId = requestHeader.getQueueId();
        //封装一个PullRequest
        PullRequest pullRequest = new PullRequest(request, channel, pollingTimeMills,
                                                  this.brokerController.getMessageStore().now(), offset, subscriptionData, messageFilter);
        //把PullRequest挂起来
        this.brokerController.getPullRequestHoldService().suspendPullRequest(topic, queueId, pullRequest);
        response = null;
        break;
    }
    

Para las solicitudes pendientes, un hilo de servicio comprobará constantemente si hay datos en la cola o expirará el tiempo de espera.

  • PullRequestHoldService#ejecutar()
@Override
public void run() {
    
    
    log.info("{} service started", this.getServiceName());
    while (!this.isStopped()) {
    
    
        try {
    
    
            if (this.brokerController.getBrokerConfig().isLongPollingEnable()) {
    
    
                this.waitForRunning(5 * 1000);
            } else {
    
    
                this.waitForRunning(this.brokerController.getBrokerConfig().getShortPollingTimeMills());
            }

            long beginLockTimestamp = this.systemClock.now();
            //检查hold住的请求
            this.checkHoldRequest();
            long costTime = this.systemClock.now() - beginLockTimestamp;
            if (costTime > 5 * 1000) {
    
    
                log.info("[NOTIFYME] check hold request cost {} ms.", costTime);
            }
        } catch (Throwable e) {
    
    
            log.warn(this.getServiceName() + " service has exception. ", e);
        }
    }

    log.info("{} service end", this.getServiceName());
}

Fuente de datos: Contraataque de cabrones: RocketMQ Veintitrés preguntas (qq.com)

Supongo que te gusta

Origin blog.csdn.net/weixin_45483322/article/details/132998780
Recomendado
Clasificación