RocketMQ se basa en el modo Dledger, operación de actualización suave

Condición previa

Esta solución no es común a todos los casos, y otros modelos de implementación son solo para referencia.

  • Modo de clúster: múltiples maestros y múltiples esclavos (por ejemplo, 2 maestros y 4 esclavos)
  • Admite conmutación maestro-esclavo: Dledger, también puede consultarlo si no lo admite y cumple con el requisito anterior
  • El extremo de envío y el extremo del consumidor están en el proceso de actualización del intermediario (reinicio del intermediario), y se requiere que el cliente no permita que aparezcan los registros de errores.

Escenas

Los nodos del clúster MQ deben actualizarse en rotación o la configuración del intermediario debe modificarse para reiniciarse. Cuando el corredor se reinicia, el cliente no permite que aparezcan los registros de errores de nivel de ERROR.

El reinicio del corredor puede hacer que el cliente informe un error, probablemente en las siguientes situaciones:

1. El productor no envía el mensaje (la información de enrutamiento no se actualiza a tiempo y el corredor detenido no podrá conectarse)

2. El consumidor no pudo actualizar la compensación (programación de tiempos, persistencia del sitio de consumo en el maestro del corredor cada 5 segundos, la conexión falla en este momento)

Artículo 1, el registro de errores se imprime directamente en el sistema empresarial.

El segundo elemento pertenece al registro del consumidor. De forma predeterminada, el consumidor tiene un registro / rocketmq_client.log en el directorio de inicio para registrar el registro por separado. Sin embargo, esto se puede configurar para usar el slf4j del sistema empresarial para registrar el registro, el sistema empresarial puede recopilar el registro y, a continuación, nuestro sistema empresarial ha emitido alarmas relevantes, si hay registros de nivel de ERROR (algunos registros de ERROR lo harán). en realidad no causan ningún impacto en el negocio), se le alertará. Para evitar que las alarmas sean detectadas por el sistema empresarial durante el reinicio del broker master (no se necesitan las alarmas que no afecten al negocio), es necesario asegurar la fluidez y estabilidad de la operación. La falla del latido es el registro de nivel de información.

Supongamos que quiero actualizar el clúster MQ en línea de 4.7.1 a 4.8.0, la operación es la siguiente, explique principalmente el corredor, ignore el servidor de nombres, esa es una buena operación.

Pasos

El modelo de clúster es el siguiente:

Actualice los nodos maestro y esclavo de broker1 y los nodos maestro y esclavo de broker2 a su vez.

1. Primero desactive el permiso de escritura del broker master1 y prohíba al productor enviar mensajes a broker1. En este momento, debe asegurarse de que broker2 pueda soportar toda la presión. Porque después de cerrar el permiso de escritura, todo el tráfico del productor se cortará a broker2 (incluido el broker1 original), lo que refleja la importancia de la redundancia de recursos.

sh mqadmin updatebrokerconfig -n 'nameserver:9876' -k brokerPermission -v 4 -b broker1master:10911

2. A través de la consola / línea de comando o plataforma de monitoreo, dependiendo de las herramientas que tenga, use el comando clusterList de la línea de comando si no tiene nada. Observe que los inTps y outTps del broker1 master son ambos 0, y luego elimine el permiso de lectura (asegúrese de que el nodo Todo el consumo de noticias haya terminado, no hay acumulación).

sh mqadmin updatebrokerconfig -n 'nameserver:9876' -k brokerPermission -v 1 -b broker1master:10911

En este momento, el consumidor informará algunos registros de nivel de advertencia, que está prohibido extraer, pero no afectará porque se han consumido todos los mensajes.

3. Compruebe que los inTps de slave1_1 y slave1_2 sean ambos 0 para asegurarse de que no haya sincronización de mensajes, y luego inicie y detenga slave1_1 y slave1_2 respectivamente para actualizar.

4. Detenga el nodo maestro1 y asegúrese de que el intervalo entre este paso y el paso 2 sea de al menos 2 minutos (por qué el intervalo es tan largo, como se explica más adelante). Después de detenerse, uno de los nodos esclavos se elegirá automáticamente como maestro nodo, y el productor y el consumidor se conectarán al nuevo normalmente El nodo maestro envía y consume mensajes. Luego, inicie el último broker nuevo (acaba de detener esto) como un nodo esclavo (si no es una actualización de versión, simplemente reinícielo, primero cambie el valor del elemento de configuración brokerPermission de este nodo a 6 y luego inícielo (porque el pasos anteriores Desactive los permisos de lectura y escritura de este nodo, por lo que este elemento de configuración ahora es 1).

Durante la actualización, cuando el nodo esclavo se cambia al nuevo nodo maestro, si el consumidor informa este registro de advertencia, no importa. Este es el equilibrio de carga y la asignación de cola en el lado del consumidor. Hay una falta de implementación. aún no se ha solucionado Fenómeno normal. Razones detalladas, explicaré este problema por separado en el futuro cuando tenga tiempo:

En este caso, todo el proceso de reinicio / actualización de broker1 no tiene ningún impacto en el cliente del lado empresarial, pero se informará una pequeña cantidad de registros de nivel de advertencia y los registros de error de nivel de ERROR no aparecerán.

5. Confirme que no hay ningún problema con broker1, repita los pasos 1 a 4 para operar los nodos relacionados de broker2 hasta que se complete la actualización de todo el clúster.

Cierre el permiso de lectura del maestro, se recomienda detenerse al menos 2 minutos

Como vio anteriormente, después de cerrar el permiso de lectura en el paso 2, tomará al menos 2 minutos detener el broker, para evitar el error ERROR de la excepción de conexión en el lado del consumidor: falla la compensación de consumo persistente. Para detener el escenario del broker1, analice uno por uno a continuación:

¿Envío cronometrado de latidos del corazón? Eche un vistazo al código: En el método startScheduledTask () de la clase MQClientInstance, preste atención al comentario chino que agregué:

        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                try {
                    // 默认是30秒
                    // 遍历缓存的broker地址,然后判断topic路由信息(但是topicRouteInfo一定会有)里是否有该broker,不存在就剔除
                    // 没有read perm是pub info表里没有该topic的队列数据,没有write perm是sub info里没有该topic的队列数据,但是topicRouteInfo一定会有
                    MQClientInstance.this.cleanOfflineBroker();
                    // 尽管 发送心跳的时候,broker地址表里保存的是所有broker的地址,如果没有消费端实例,只会向master节点发送心跳,否则向所有broker发送心跳
                    // 每次发送心跳的时候broker端都会创建retry topic。所以retry topic即使删除了,只要消费端运行,一个心跳后便又创建了,
                    // 同时也意味着创建一个消费组,只有消费端启动之后才会创建重试topic
                    MQClientInstance.this.sendHeartbeatToAllBrokerWithLock();
                } catch (Exception e) {
                    log.error("ScheduledTask sendHeartbeatToAllBroker exception", e);
                }
            }
        }, 1000, this.clientConfig.getHeartbeatBrokerInterval(), TimeUnit.MILLISECONDS);

Este latido no afectará la actualización de la compensación de consumo. Es principalmente para prestar atención a mis comentarios anteriores. Sin el permiso de escritura, la información de suscripción no tendrá los datos de la cola de temas.

 

Hay una tarea programada que actualiza la información de enrutamiento de temas cada 30 segundos (el código no se publica demasiado). Al actualizar la información de enrutamiento, actualice la información de suscripción almacenada en caché (este lugar está relacionado con la compensación de actualización, primero explique a continuación):

                            // Update sub info,没有读权限的话,就没有队列信息
                            {
                                Set<MessageQueue> subscribeInfo = topicRouteData2TopicSubscribeInfo(topic, topicRouteData);
                                Iterator<Entry<String, MQConsumerInner>> it = this.consumerTable.entrySet().iterator();
                                while (it.hasNext()) {
                                    Entry<String, MQConsumerInner> entry = it.next();
                                    MQConsumerInner impl = entry.getValue();
                                    if (impl != null) {
                                        impl.updateTopicSubscribeInfo(topic, subscribeInfo);
                                    }
                                }
                            }

De forma predeterminada , la compensación de consumo se mantiene regularmente cada 5 segundos . Siempre que se garantice que no hay una dirección de broker1 cuando el desplazamiento persiste, no hay necesidad de preocuparse por detener broker1.

        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                try {
                    // 默认每隔5秒钟上报偏移
                    // 如果上报偏移的 时候,已停止 broker的地址还缓存呢,就该报错了
                    MQClientInstance.this.persistAllConsumerOffset();
                } catch (Exception e) {
                    log.error("ScheduledTask persistAllConsumerOffset exception", e);
                }
            }
        }, 1000 * 10, this.clientConfig.getPersistConsumerOffsetInterval(), TimeUnit.MILLISECONDS);

(Demasiado código, no pegado) En pocas palabras, la actualización del desplazamiento actualizará toda la información de desplazamiento de la cola de mensajes local, y la información de la cola de mensajes suscritos proviene de cuando se actualiza la información de enrutamiento del tema. Sin permiso de lectura, no habrá información de cola para broker1 y la actualización de la compensación no actualizará la compensación de consumo en este corredor. El tiempo máximo para este proceso es: 30 + 5 = 35 s, que es el intervalo de tiempo del lado del cliente (máximo). Mire el lado del corredor, porque después de que el lado del corredor cierra el permiso de lectura, ¿cuánto tiempo se tarda en actualizar el información de enrutamiento de este tema: 30 s,

        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                try {//brokerConfig.isForceRegister()默认值是true
                    BrokerController.this.registerBrokerAll(true, false, brokerConfig.isForceRegister());
                } catch (Throwable e) {
                    log.error("registerBrokerAll Exception", e);
                }
            }// brokerConfig.getRegisterNameServerPeriod() 默认30s,在10-60s,之间,30s注册一次broker->name server,即每30s上报一次topic信息
        }, 1000 * 10, Math.max(10000, Math.min(brokerConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);

La información de enrutamiento del tema se envía al servidor de nombres una vez cada 30 segundos, y luego el consumidor puede comenzar a percibirla.

Entonces, el tiempo total es de 65 segundos. Para garantizar que el lado del consumidor no se vea afectado, se necesitan al menos 65 segundos para detener al corredor después de que se cierra el permiso de lectura. Por supuesto, en la práctica, estos horarios se superponen (algunas actualizaciones de información tienen otros escenarios además de horarios), y también es posible en diez a veinte segundos. La razón por la que recomiendo 2 minutos es que es fácil de recordar, no hay necesidad de preocuparse por los detalles, 2 minutos es absolutamente seguro.

Supongo que te gusta

Origin blog.csdn.net/x763795151/article/details/112385106
Recomendado
Clasificación