Aprendizaje rápido: mejores prácticas de RocketMQ

Mejores prácticas


1 productor

1.1 Notas para enviar mensajes

1 Uso de etiquetas

Una aplicación utiliza un tema tanto como sea posible y el subtipo de mensaje se puede identificar mediante etiquetas. Las etiquetas pueden ser configuradas libremente por la aplicación Solo cuando el productor establece las etiquetas al enviar un mensaje, el consumidor puede usar etiquetas para filtrar mensajes a través del corredor cuando se suscribe al mensaje: message.setTags ("TagA").

2 Uso de llaves

El código de identificación único de cada mensaje a nivel de servicio debe establecerse en el campo de claves para facilitar la ubicación del problema de pérdida de mensajes en el futuro. El servidor creará un índice (índice hash) para cada mensaje, y la aplicación puede consultar el contenido del mensaje por tema y clave, y quién consume el mensaje. Dado que es un índice hash, asegúrese de que la clave sea lo más única posible para evitar posibles colisiones hash.

   // 订单Id   
   String orderId = "20034568923546";   
   message.setKeys(orderId);   

Impresión de 3 registros

Si el mensaje se envía correctamente o falla, se debe imprimir el registro de mensajes y se deben imprimir los campos SendResult y clave. Siempre que el método de envío de mensajes no genere una excepción, significa que el mensaje se envió correctamente. Hay varios estados para un envío exitoso, que se definen en sendResult. A continuación se describe cada estado:

  • SEND_OK

El mensaje se envió con éxito. Cabe señalar que el éxito de un mensaje no significa que sea confiable. Para asegurarse de que no se pierdan mensajes, también debe habilitar el servidor maestro síncrono o el flasheo síncrono, a saber, SYNC_MASTER o SYNC_FLUSH.

  • FLUSH_DISK_TIMEOUT

El mensaje se envió correctamente, pero se agotó el tiempo de espera del servidor. En este punto, el mensaje ha entrado en la cola del servidor (memoria) y el mensaje se perderá solo si el servidor no funciona. Los parámetros de configuración de almacenamiento de mensajes pueden establecer el modo de parpadeo y la duración del parpadeo sincrónico. Si el servidor Broker ha configurado el modo de parpadeo para que sea un parpadeo sincrónico, es decir, FlushDiskType = SYNC_FLUSH (el modo predeterminado es el modo de parpadeo asíncrono), cuando el servidor del Broker no parpadea sincrónicamente Si el parpadeo se completa dentro del tiempo de parpadeo (el valor predeterminado es 5 s), volverá a este estado de tiempo de espera de parpadeo.

  • FLUSH_SLAVE_TIMEOUT

El mensaje se envió correctamente, pero el servidor agotó el tiempo de espera al sincronizar con el esclavo. En este punto, el mensaje ha entrado en la cola del servidor y solo se perderá si el servidor no funciona. Si la función del servidor Broker es el maestro síncrono, es decir, SYNC_MASTER (el valor predeterminado es el maestro asíncrono o ASYNC_MASTER), y el servidor Broker esclavo no completa la sincronización con el servidor maestro dentro del tiempo de sincronización (el valor predeterminado es 5 segundos), volverá a este estado: —Se agotó el tiempo de sincronización de datos con el servidor esclavo.

  • SLAVE_NOT_AVAILABLE

El mensaje se envió correctamente, pero el esclavo no está disponible en este momento. Si la función del servidor Broker es el maestro síncrono, es decir, SYNC_MASTER (el valor predeterminado es el servidor maestro asíncrono, es decir, ASYNC_MASTER), pero no hay un servidor Broker esclavo configurado, volverá a este estado: no hay ningún servidor esclavo disponible.

1.2 Cómo lidiar con la falla en el envío de mensajes

El método de envío del propio Producer admite reintentos internos, y la lógica de reintento es la siguiente:

  • Hasta 2 intentos múltiples (2 veces para transmisión síncrona y 0 veces para transmisión asíncrona).
  • Si el envío falla, diríjase al siguiente Broker. El tiempo total de este método no excede el valor establecido por sendMsgTimeout, que es 10 segundos por defecto.
  • Si enviar un mensaje al corredor genera una excepción de tiempo de espera, no volverá a intentarlo.

La estrategia anterior también garantiza hasta cierto punto que el mensaje se puede enviar con éxito. Si la empresa tiene altos requisitos para la confiabilidad de los mensajes, se recomienda que la aplicación agregue la lógica de reintento correspondiente: por ejemplo, cuando el método de sincronización de envío no se envía, intente almacenar el mensaje en la base de datos y luego el hilo en segundo plano volverá a intentarlo con regularidad para asegurarse de que el mensaje debe llegar al corredor.

Por qué el método de reintento de base de datos anterior no está integrado en el cliente MQ, pero requiere que la aplicación lo complete por sí mismo, principalmente en base a las siguientes consideraciones: Primero, el cliente MQ está diseñado como un modo sin estado, que es conveniente para la expansión horizontal arbitraria, y es correcto El consumo de recursos de la máquina es solo cpu, memoria y red. En segundo lugar, si un módulo de almacenamiento KV está integrado en el cliente MQ, los datos solo se pueden colocar en un disco síncrono para que sean más confiables, y la sobrecarga de rendimiento del disco síncrono en sí es relativamente alta, por lo que generalmente se usa la ubicación del disco asíncrono y el proceso de cierre de la aplicación no se ve afectado por la operación de MQ. Control del personal de mantenimiento, a menudo puede suceder que kill -9 se cierre de forma violenta, provocando la pérdida de datos por no haber sido colocados de forma oportuna. En tercer lugar, la confiabilidad de la máquina donde se encuentra el Productor es baja, generalmente una máquina virtual, que no es adecuada para almacenar datos importantes. En resumen, se recomienda que la aplicación controle el proceso de reintento.

1.3 Elija una forma para enviar

Por lo general, el envío de un mensaje es un proceso de este tipo:

  • El cliente envía una solicitud al servidor
  • Solicitud de procesamiento del servidor
  • El servidor devuelve una respuesta al cliente.

Por lo tanto, el tiempo que lleva el envío de un mensaje es la suma de los tres pasos anteriores, y algunos escenarios requieren muy poco tiempo, pero los requisitos de confiabilidad no son altos, como las aplicaciones de recopilación de registros, que se pueden llamar de forma unidireccional. El formulario unidireccional solo envía una solicitud sin esperar una respuesta, y la solicitud de envío es solo una sobrecarga de una llamada al sistema operativo en el nivel de implementación del cliente, es decir, escribir datos en el búfer de socket del cliente. Este proceso generalmente toma microsegundos.

2 consumidores

2.1 El proceso de consumo es idempotente

RocketMQ no puede evitar la duplicación de mensajes (exactamente una vez), por lo que si la empresa es muy sensible a la duplicación del consumo, debe deduplicarse a nivel empresarial. Puede utilizar bases de datos relacionales para la deduplicación. Primero, debe determinar la clave única del mensaje, que puede ser msgId o un campo de identificación único en el contenido del mensaje, como el Id. Del pedido. Antes del consumo, determine si la clave única existe en la base de datos relacional. Si no existe, inserte y consuma, de lo contrario omita. (El proceso real debe considerar la cuestión de la atomicidad para determinar si hay un intento de inserción. Si se informa del conflicto de clave primaria, la inserción falla y se salta directamente)

msgId debe ser un identificador único global, pero en el uso real, puede haber situaciones en las que el mismo mensaje tenga dos msgIds diferentes (retransmisión activa del consumidor, repetición causada por el mecanismo de retransmisión del cliente, etc.). Esta situación requiere Hacer que los campos empresariales se repitan en el consumo.

2.2 Maneras de lidiar con el consumo lento

1 Mejorar el paralelismo de consumo

La mayor parte del comportamiento de consumo de mensajes es intensivo en IO, es decir, puede estar operando la base de datos o llamando a RPC. La velocidad de consumo de este tipo de comportamiento de consumo radica en el rendimiento de la base de datos back-end o del sistema externo. Al aumentar el paralelismo de consumo, se puede mejorar el total. Rendimiento de consumo, pero el grado de paralelismo aumenta hasta cierto punto, pero disminuirá. Por lo tanto, la aplicación debe establecer un grado razonable de paralelismo. Hay varias formas de modificar el paralelismo de consumo de la siguiente manera:

  • Bajo el mismo ConsumerGroup, aumente el número de instancias de consumidor para aumentar el grado de paralelismo (tenga en cuenta que las instancias de consumidor que exceden el número de colas de suscripción no son válidas). Puede agregar una máquina o iniciar varios procesos en una máquina existente.
  • Mejore el consumo de subprocesos paralelos de un solo consumidor modificando los parámetros consumeThreadMin y consumeThreadMax.

2 Consumo de lote

Si ciertos procesos comerciales admiten el consumo por lotes, el rendimiento del consumo se puede mejorar enormemente. Por ejemplo, en las aplicaciones de deducción de pedidos, se tarda 1 segundo en procesar un pedido a la vez y solo 2 segundos en procesar 10 pedidos a la vez. Esto puede aumentar considerablemente el rendimiento del consumo. Al establecer el parámetro consumerMessageBatchMaxSize, el valor predeterminado es 1, es decir, solo se consume un mensaje a la vez. Por ejemplo, si se establece en N, el número de mensajes consumidos cada vez es menor o igual a N.

3 Omitir mensajes no importantes

Cuando se produce la acumulación de mensajes, si la velocidad de consumo no se ha mantenido a la par de la velocidad de envío, si la empresa no requiere datos elevados, puede optar por descartar los mensajes sin importancia. Por ejemplo, cuando el número de mensajes en una determinada cola se acumula a más de 100.000, intente descartar algunos o todos los mensajes, para que pueda ponerse al día rápidamente con la velocidad de envío de mensajes. El código de muestra es el siguiente:

    public ConsumeConcurrentlyStatus consumeMessage(
            List<MessageExt> msgs,
            ConsumeConcurrentlyContext context) {
    
    
        long offset = msgs.get(0).getQueueOffset();
        String maxOffset =
                msgs.get(0).getProperty(Message.PROPERTY_MAX_OFFSET);
        long diff = Long.parseLong(maxOffset) - offset;
        if (diff > 100000) {
    
    
            // TODO 消息堆积情况的特殊处理
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
        // TODO 正常消费过程
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }    

4 Optimiza el proceso de consumo de cada mensaje

Por ejemplo, el proceso de consumo de un mensaje es el siguiente:

  • Consulta desde DB según el mensaje [Data 1]
  • Consulta desde la base de datos según el mensaje [Data 2]
  • Cálculos comerciales complejos
  • Inserte [Data 3] en la base de datos
  • Inserte [Data 4] en la base de datos

Hay 4 interacciones con la base de datos durante el consumo de este mensaje. Si se calcula como 5 ms cada vez, el tiempo total es 20 ms. Suponiendo que el cálculo comercial toma 5 ms, el tiempo total es 25 ms, por lo que si puede interactuar con la base de datos 4 veces La optimización es 2 veces, luego el tiempo total se puede optimizar a 15 ms, es decir, el rendimiento general aumenta en un 40%. Por lo tanto, si la aplicación es sensible a la latencia, la base de datos se puede implementar en discos duros SSD, en comparación con los discos SCSI, el RT de los primeros será mucho menor.

2.3 Registro de impresión de consumo

Si la cantidad de mensajes es pequeña, se recomienda imprimir mensajes en el método de entrada de consumo, que consume mucho tiempo para facilitar la resolución de problemas posterior.

   public ConsumeConcurrentlyStatus consumeMessage(
            List<MessageExt> msgs,
            ConsumeConcurrentlyContext context) {
    
    
        log.info("RECEIVE_MSG_BEGIN: " + msgs.toString());
        // TODO 正常消费过程
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }   

Si puede imprimir cada mensaje y consumir tiempo, será más conveniente para solucionar problemas en línea, como el consumo lento.

2.4 Otras sugerencias de los consumidores

1 Sobre consumidores y suscripciones

Lo primero a tener en cuenta es que diferentes grupos de consumidores pueden consumir algunos temas de forma independiente, y cada grupo de consumidores tiene su propia compensación de consumo. Asegúrese de que se mantenga la información de suscripción de cada consumidor en el mismo grupo. Consistente.

2 Acerca de los mensajes ordenados

Los consumidores bloquearán cada cola de mensajes para asegurarse de que se consuman uno por uno. Aunque esto provocará una degradación del rendimiento, es útil cuando se preocupa por el orden de los mensajes. No recomendamos lanzar excepciones, puede devolver ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT en su lugar.

3 Acerca del consumo concurrente

Como su nombre lo indica, los consumidores consumirán estos mensajes al mismo tiempo. Se recomienda que los use para un buen rendimiento. No recomendamos lanzar excepciones. Puede devolver ConsumeConcurrentlyStatus.RECONSUME_LATER en su lugar.

4 Acerca del estado de consumo

Para los oyentes de consumo simultáneo, puede devolver RECONSUME_LATER para notificar al consumidor que el mensaje no se puede consumir ahora y esperar que se pueda consumir de nuevo más tarde. Luego, puede continuar consumiendo otros mensajes. Para un receptor de mensajes ordenado, debido a que le importa su orden, no puede omitir el mensaje, pero puede devolver SUSPEND_CURRENT_QUEUE_A_MOMENT para decirle al consumidor que espere un rato.

5 Acerca del bloqueo

No se recomienda bloquear al oyente, porque bloqueará el grupo de subprocesos y eventualmente puede terminar el proceso del consumidor.

6 Acerca de la configuración del número de hilos

Los consumidores usan ThreadPoolExecutor para consumir mensajes internamente, por lo que puede cambiarlo configurando setConsumeThreadMin o setConsumeThreadMax.

7 Acerca de los sitios de consumo

Al crear un nuevo grupo de consumidores, debe decidir si necesita consumir mensajes históricos que ya existen en Broker. CONSUME_FROM_LAST_OFFSET ignorará los mensajes históricos y consumirá los mensajes generados posteriormente. CONSUME_FROM_FIRST_OFFSET consumirá toda la información que exista en el Broker. También puede usar CONSUME_FROM_TIMESTAMP para consumir mensajes generados después de la marca de tiempo especificada.

3 Broker

3.1 Rol del corredor

Los roles del intermediario se dividen en ASYNC_MASTER (maestro asíncrono), SYNC_MASTER (maestro síncrono) y SLAVE (esclavo). Si la confiabilidad del mensaje es más estricta, puede usar el método de implementación SYNC_MASTER más SLAVE. Si los requisitos de confiabilidad del mensaje no son altos, se puede utilizar el método de implementación de ASYNC_MASTER más SLAVE. Si solo es conveniente para las pruebas, puede elegir implementar solo ASYNC_MASTER o SYNC_MASTER solamente.

3.2 FlushDiskType

SYNC_FLUSH (actualización síncrona) perderá mucho rendimiento en comparación con ASYNC_FLUSH (procesamiento asincrónico), pero también es más confiable, por lo que debe hacer una compensación basada en el escenario empresarial real.

3.3 Configuración del corredor

nombre del parámetro Defaults Descripción
listenPort 10911 El puerto de escucha que acepta conexiones de clientes
namesrvAddr nulo nombre Dirección del servidor
brokerIP1 Inet Dirección de la tarjeta de red IP actualmente monitoreada por el corredor
brokerIP2 Igual que brokerIP1 Cuando hay un broker maestro-esclavo, si el atributo brokerIP2 está configurado en el nodo maestro del broker, el nodo esclavo del broker se conectará al brokerIP2 configurado por el nodo maestro para la sincronización.
brokerName nulo el nombre del corredor
brokerClusterName DefaultCluster El nombre del Cluser al que pertenece este intermediario
brokerId 0 ID de corredor, 0 significa maestro, otros enteros positivos significan esclavo
storePathCommitLog $ HOME / tienda / commitlog / Ruta para almacenar el registro de confirmación
storePathConsumerQueue $ HOME / store / consumequeue / La ruta para almacenar la cola de consumo
mappedFileSizeCommitLog 1024 * 1024 * 1024 (1G) Asignación del tamaño de archivo del registro de confirmación
deleteWhen 04 A qué hora del día elimine el registro de confirmación que ha excedido el tiempo de retención del archivo
fileReservedTime 72 Tiempo de retención de archivos en horas
brokerRole ASYNC_MASTER SYNC_MASTER / ASYNC_MASTER / SLAVE
flushDiskType ASYNC_FLUSH SYNC_FLUSH / ASYNC_FLUSH El intermediario en modo SYNC_FLUSH garantiza eliminar el mensaje antes de recibir la confirmación del productor. El corredor en modo ASYNC_FLUSH usa el modo de flashear un grupo de mensajes para lograr un mejor rendimiento.

4 NameServer

En RocketMQ, los servidores de nombres están diseñados para una administración de enrutamiento simple. Sus responsabilidades incluyen:

  • Los corredores registran periódicamente los datos de enrutamiento con cada servidor de nombres.
  • El servidor de nombres proporciona la información de enrutamiento más reciente para los clientes, incluidos productores, consumidores y clientes de línea de comandos.

5 Configuración del cliente

En comparación con el grupo de agentes de RocketMQ, tanto los productores como los consumidores son clientes. Esta sección describe principalmente la configuración del comportamiento público de productores y consumidores.

5.1 Modo de direccionamiento del cliente

RocketMQ puede hacer que el cliente busque el servidor de nombres y luego busque el corredor a través del servidor de nombres. Hay varios métodos de configuración, como se muestra a continuación, la prioridad es de mayor a menor y la prioridad alta anulará la prioridad baja.

  • Especifique la dirección del servidor de nombres en el código, separe las direcciones de nombres múltiples con punto y coma
producer.setNamesrvAddr("192.168.0.1:9876;192.168.0.2:9876");  

consumer.setNamesrvAddr("192.168.0.1:9876;192.168.0.2:9876");
  • Especifique la dirección del servidor de nombres en los parámetros de inicio de Java
-Drocketmq.namesrv.addr=192.168.0.1:9876;192.168.0.2:9876  
  • La variable de entorno especifica la dirección del servidor de nombres
export   NAMESRV_ADDR=192.168.0.1:9876;192.168.0.2:9876   
  • Direccionamiento del servidor estático HTTP (predeterminado)

Una vez iniciado el cliente, accederá periódicamente a un servidor HTTP estático, la dirección es la siguiente: http://jmenv.tbsite.net:8080/rocketmq/nsaddr , el contenido de retorno de esta URL es el siguiente:

192.168.0.1:9876;192.168.0.2:9876   

El cliente visita este servidor HTTP cada 2 minutos de forma predeterminada y actualiza la dirección del servidor de nombres local. La URL ha sido codificada en el código. Puede cambiar el servidor al que se accede modificando el archivo / etc / hosts. Por ejemplo, agregue la siguiente configuración a / etc / hosts:

10.232.22.67    jmenv.taobao.net   

Se recomienda utilizar el método de direccionamiento del servidor estático HTTP La ventaja es que la implementación del cliente es simple y el clúster del servidor de nombres se puede actualizar en caliente.

5.2 Configuración del cliente

DefaultMQProducer, TransactionMQProducer, DefaultMQPushConsumer y DefaultMQPullConsumer heredan de la clase ClientConfig, que es una clase de configuración pública para el cliente. La configuración del cliente es en forma de get y set. Cada parámetro se puede configurar con spring o en el código. Por ejemplo, el parámetro namesrvAddr se puede configurar así, producer.setNamesrvAddr ("192.168.0.1:9876"), otros parámetros Lo mismo es verdad.

1 Configuración pública del cliente

nombre del parámetro Defaults Descripción
namesrvAddr Lista de direcciones del servidor de nombres, varias direcciones del servidor de nombres están separadas por punto y coma
clientIP IP local La dirección IP local del cliente, algunas máquinas no reconocerán la dirección IP del cliente, debe especificarse en el código a la fuerza
nombre de instancia DEFECTO El nombre de la instancia del cliente, el productor y el consumidor múltiples creados por el cliente en realidad comparten una instancia interna (esta instancia incluye conexiones de red, recursos de subprocesos, etc.)
clientCallbackExecutorThreads 4 Número de subprocesos de devolución de llamada asíncronos en la capa de comunicación
pollNameServerInteval 30000 Intervalo de sondeo del servidor de nombres, en milisegundos
HeartbeatBrokerInterval 30000 El intervalo de envío de latidos al Broker, en milisegundos
persistConsumerOffsetInterval 5000 Intervalo de progreso del consumo persistente del consumidor, en milisegundos

2 Configuración del productor

nombre del parámetro Defaults Descripción
productorGrupo DEFAULT_PRODUCER Nombre del grupo de productores, si varios productores pertenecen a una aplicación y envían el mismo mensaje, deben agruparse en el mismo grupo
createTopicKey TBW102 Al enviar un mensaje, se crea automáticamente un tema que no existe en el servidor y es necesario especificar una clave, que se puede utilizar para configurar la ruta predeterminada del tema donde se envía el mensaje.
defaultTopicQueueNums 4 El número de colas creadas por defecto al enviar mensajes y crear automáticamente temas donde el servidor no existe
sendMsgTimeout 10000 Tiempo de espera de envío del mensaje, en milisegundos
compressMsgBodyOverHowmuch 4096 El cuerpo del mensaje excede el tamaño para iniciar la compresión (el consumidor descomprimirá automáticamente el mensaje cuando lo reciba), en bytes
retryAnotherBrokerWhenNotStoreOK FALSO Si enviar un mensaje devuelve sendResult, pero sendStatus! = SEND_OK, si volver a intentar enviar
retryTimesWhenSendFailed 2 Si el mensaje no se envía, el número máximo de reintentos, este parámetro solo funciona en modo de envío síncrono
maxMessageSize 4 MB El tamaño del mensaje limitado por el cliente excede el informe de errores y el servidor también lo limitará, por lo que debe usarse junto con el servidor.
transactionCheckListener Mensaje de transacción, verifique el oyente, si envía un mensaje de transacción, debe configurarse
checkThreadPoolMinSize 1 El número mínimo de subprocesos en el grupo de subprocesos cuando el corredor verifica el estado de la transacción del productor
checkThreadPoolMaxSize 1 El número máximo de subprocesos en el grupo de subprocesos cuando el corredor verifica el estado de la transacción del productor
checkRequestHoldMax 2000 Broker回查Producer事务状态时,Producer本地缓冲请求队列大小
RPCHook null 该参数是在Producer创建时传入的,包含消息发送前的预处理和消息响应后的处理两个接口,用户可以在第一个接口中做一些安全控制或者其他操作。

3 PushConsumer配置

参数名 默认值 说明
consumerGroup DEFAULT_CONSUMER Consumer组名,多个Consumer如果属于一个应用,订阅同样的消息,且消费逻辑一致,则应该将它们归为同一组
messageModel CLUSTERING 消费模型支持集群消费和广播消费两种
consumeFromWhere CONSUME_FROM_LAST_OFFSET Consumer启动后,默认从上次消费的位置开始消费,这包含两种情况:一种是上次消费的位置未过期,则消费从上次中止的位置进行;一种是上次消费位置已经过期,则从当前队列第一条消息开始消费
consumeTimestamp 半个小时前 只有当consumeFromWhere值为CONSUME_FROM_TIMESTAMP时才起作用。
allocateMessageQueueStrategy AllocateMessageQueueAveragely Rebalance算法实现策略
subscription 订阅关系
messageListener 消息监听器
offsetStore 消费进度存储
consumeThreadMin 10 消费线程池最小线程数
consumeThreadMax 20 消费线程池最大线程数
consumeConcurrentlyMaxSpan 2000 单队列并行消费允许的最大跨度
pullThresholdForQueue 1000 拉消息本地队列缓存消息最大数
pullInterval 0 拉消息间隔,由于是长轮询,所以为0,但是如果应用为了流控,也可以设置大于0的值,单位毫秒
consumeMessageBatchMaxSize 1 批量消费,一次消费多少条消息
pullBatchSize 32 批量拉消息,一次最多拉多少条

4 PullConsumer配置

参数名 默认值 说明
consumerGroup DEFAULT_CONSUMER Consumer组名,多个Consumer如果属于一个应用,订阅同样的消息,且消费逻辑一致,则应该将它们归为同一组
brokerSuspendMaxTimeMillis 20000 长轮询,Consumer拉消息请求在Broker挂起最长时间,单位毫秒
consumerTimeoutMillisWhenSuspend 30000 长轮询,Consumer拉消息请求在Broker挂起超过指定时间,客户端认为超时,单位毫秒
consumerPullTimeoutMillis 10000 非长轮询,拉消息超时时间,单位毫秒
messageModel BROADCASTING 消息支持两种模式:集群消费和广播消费
messageQueueListener 监听队列变化
offsetStore 消费进度存储
registerTopics 注册的topic集合
allocateMessageQueueStrategy AllocateMessageQueueAveragely Rebalance算法实现策略

5 Message数据结构

字段名 默认值 说明
Topic null 必填,消息所属topic的名称
Body null 必填,消息体
Tags null 选填,消息标签,方便服务器过滤使用。目前只支持每个消息设置一个tag
Keys null 选填,代表这条消息的业务关键词,服务器会根据keys创建哈希索引,设置后,可以在Console系统根据Topic、Keys来查询消息,由于是哈希索引,请尽可能保证key唯一,例如订单号,商品Id等。
Flag 0 选填,完全由应用来设置,RocketMQ不做干预
DelayTimeLevel 0 选填,消息延时级别,0表示不延时,大于0会延时特定的时间才会被消费
WaitStoreMsgOK TRUE 选填,表示消息是否在服务器落盘后才返回应答。

6 系统配置

本小节主要介绍系统(JVM/OS)相关的配置。

6.1 JVM选项

​ 推荐使用最新发布的JDK 1.8版本。通过设置相同的Xms和Xmx值来防止JVM调整堆大小以获得更好的性能。简单的JVM配置如下所示:

​ ​-server -Xms8g -Xmx8g -Xmn4g ​


如果您不关心RocketMQ Broker的启动时间,还有一种更好的选择,就是通过“预触摸”Java堆以确保在JVM初始化期间每个页面都将被分配。那些不关心启动时间的人可以启用它:
​ -XX:+AlwaysPreTouch
禁用偏置锁定可能会减少JVM暂停,
​ -XX:-UseBiasedLocking
至于垃圾回收,建议使用带JDK 1.8的G1收集器。

-XX:+UseG1GC -XX:G1HeapRegionSize=16m   
-XX:G1ReservePercent=25 
-XX:InitiatingHeapOccupancyPercent=30

​ 这些GC选项看起来有点激进,但事实证明它在我们的生产环境中具有良好的性能。另外不要把-XX:MaxGCPauseMillis的值设置太小,否则JVM将使用一个小的年轻代来实现这个目标,这将导致非常频繁的minor GC,所以建议使用rolling GC日志文件:

-XX:+UseGCLogFileRotation   
-XX:NumberOfGCLogFiles=5 
-XX:GCLogFileSize=30m

如果写入GC文件会增加代理的延迟,可以考虑将GC日志文件重定向到内存文件系统:

-Xloggc:/dev/shm/mq_gc_%p.log123   

6.2 Linux内核参数

​ os.sh脚本在bin文件夹中列出了许多内核参数,可以进行微小的更改然后用于生产用途。下面的参数需要注意,更多细节请参考/proc/sys/vm/*的文档

  • vm.extra_free_kbytes,告诉VM在后台回收(kswapd)启动的阈值与直接回收(通过分配进程)的阈值之间保留额外的可用内存。RocketMQ使用此参数来避免内存分配中的长延迟。(与具体内核版本相关)
  • vm.min_free_kbytes,如果将其设置为低于1024KB,将会巧妙的将系统破坏,并且系统在高负载下容易出现死锁。
  • vm.max_map_count,限制一个进程可能具有的最大内存映射区域数。RocketMQ将使用mmap加载CommitLog和ConsumeQueue,因此建议将为此参数设置较大的值。(agressiveness --> aggressiveness)
  • vm.swappiness,定义内核交换内存页面的积极程度。较高的值会增加攻击性,较低的值会减少交换量。建议将值设置为10来避免交换延迟。
  • File descriptor limits,RocketMQ需要为文件(CommitLog和ConsumeQueue)和网络连接打开文件描述符。我们建议设置文件描述符的值为655350。
  • Disk scheduler,RocketMQ建议使用I/O截止时间调度器,它试图为请求提供有保证的延迟。

Supongo que te gusta

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