"La comprensión en profundidad RocketMQ" - MQ mecanismo de entrega de mensajes

0. Introducción

la entrega de mensajes RocketMQ se divide en dos: una es 生产者para entregar el MQ Broker; Otro es el agente de MQ a 消费者 la entrega (esta 投递declaración se expone en términos de paso de mensajes, de hecho, es la capa inferior 消费者de la atracción agente de MQ la tirada). Este artículo desde la perspectiva de los modelos para ilustrar estos dos mecanismos.


1. Modelo mensaje RocketMQ

mensaje completo modelo RocketMQ no es complicado, como se muestra a continuación:

 

 

Un Topic(消息主题)posible correspondiente a la pluralidad de cola de mensajes real (MessgeQueue)
sobre la aplicación subyacente, con el fin de mejorar la disponibilidad y la flexibilidad de MQ, un tema almacenado en el proceso real, utilizando múltiples realización cola, las formas específicas mostradas anteriormente. Cada cola de mensajes debería garantizar que, en uso, First In First Out (FIFO, primero en entrar, primero en salir) Consumo manera.
Así, sobre la base de este modelo, que saldrá de dos preguntas:

  • Tema productor al enviar el mismo mensaje, el cuerpo del mensaje debe ser colocado en una cola de mensajes (el MessageQueue) en?

  • Los consumidores en las noticias del consumidor, que debe tirar de mensaje de la cola de mensajes?

 


2. Los productores (Productor) estrategia de entrega de mensajes

2.1 por defecto Envío Método: Queue队列sondeo algoritmo de Entrega

Por defecto, utilizando el algoritmo de votación sencillo más, que tiene una característica buena es para asegurar que cada Queue队列número de entrega de mensaje lo más uniforme posible, el algoritmo como se muestra a continuación:

/**
*  根据 TopicPublishInfo Topic发布信息对象中维护的index,每次选择队列时,都会递增
*  然后根据 index % queueSize 进行取余,达到轮询的效果
*
*/
public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) {
        return tpInfo.selectOneMessageQueue(lastBrokerName);
}

/**
*  TopicPublishInfo Topic发布信息对象中
*/
public class TopicPublishInfo {
    //基于线程上下文的计数递增,用于轮询目的
    private volatile ThreadLocalIndex sendWhichQueue = new ThreadLocalIndex();
   

    public MessageQueue selectOneMessageQueue(final String lastBrokerName) {
        if (lastBrokerName == null) {
            return selectOneMessageQueue();
        } else {
            int index = this.sendWhichQueue.getAndIncrement();
            for (int i = 0; i < this.messageQueueList.size(); i++) {
                //轮询计算
                int pos = Math.abs(index++) % this.messageQueueList.size();
                if (pos < 0)
                    pos = 0;
                MessageQueue mq = this.messageQueueList.get(pos);
                if (!mq.getBrokerName().equals(lastBrokerName)) {
                    return mq;
                }
            }
            return selectOneMessageQueue();
        }
    }

    public MessageQueue selectOneMessageQueue() {
        int index = this.sendWhichQueue.getAndIncrement();
        int pos = Math.abs(index) % this.messageQueueList.size();
        if (pos < 0)
            pos = 0;
        return this.messageQueueList.get(pos);
    }
}

2.2 El modo por defecto de mejoras de entrega: Basado en el Queue队列algoritmo de votación y 消息投递延迟最小entrega estrategia

La entrega por defecto es relativamente simple, pero también expone un problema que algunos Queue队列pueden ser debido a su cartera y otras razones, puede ser largo en el proceso de entrega, para este Queue队列afectará a la posterior entrega de los resultados.
Sobre la base de este fenómeno, RocketMQ después de cada envío de un mensaje MQ, el mensaje será entregado a las estadísticas 时间延迟, de acuerdo con este 时间延迟, podemos saber qué Queue队列entregar más rápido.
En este escenario, se le dará prioridad a la utilización de 消息投递延迟最小tácticas, si no en vigor, reutilización Queue队列轮询manera.

public class MQFaultStrategy {
    /**
     * 根据 TopicPublishInfo 内部维护的index,在每次操作时,都会递增,
     * 然后根据 index % queueList.size(),使用了轮询的基础算法
     *
     */
    public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) {
        if (this.sendLatencyFaultEnable) {
            try {
                // 从queueid 为 0 开始,依次验证broker 是否有效,如果有效
                int index = tpInfo.getSendWhichQueue().getAndIncrement();
                for (int i = 0; i < tpInfo.getMessageQueueList().size(); i++) {
                    //基于index和队列数量取余,确定位置
                    int pos = Math.abs(index++) % tpInfo.getMessageQueueList().size();
                    if (pos < 0)
                        pos = 0;
                    MessageQueue mq = tpInfo.getMessageQueueList().get(pos);
                    if (latencyFaultTolerance.isAvailable(mq.getBrokerName())) {
                        if (null == lastBrokerName || mq.getBrokerName().equals(lastBrokerName))
                            return mq;
                    }
                }
                
                // 从延迟容错broker列表中挑选一个容错性最好的一个 broker
                final String notBestBroker = latencyFaultTolerance.pickOneAtLeast();
                int writeQueueNums = tpInfo.getQueueIdByBroker(notBestBroker);
                if (writeQueueNums > 0) {
                     // 取余挑选其中一个队列
                    final MessageQueue mq = tpInfo.selectOneMessageQueue();
                    if (notBestBroker != null) {
                        mq.setBrokerName(notBestBroker);
                        mq.setQueueId(tpInfo.getSendWhichQueue().getAndIncrement() % writeQueueNums);
                    }
                    return mq;
                } else {
                    latencyFaultTolerance.remove(notBestBroker);
                }
            } catch (Exception e) {
                log.error("Error occurred when selecting message queue", e);
            }
          // 取余挑选其中一个队列
            return tpInfo.selectOneMessageQueue();
        }

        return tpInfo.selectOneMessageQueue(lastBrokerName);
    }
}

Orden de entrega de mensaje realización 2.3

no se requiere Las dos cajas de la gota que pertenecen a la escena de una secuencia de entrega de mensajes, tal velocidad una entrega y más eficiente. En algunos escenarios, es necesario asegurarse de que la orden del mismo tipo de entrega y el consumo de mensajes.
Por ejemplo, supongamos que tenemos TEMA  TOPIC_SALE_ORDER, tiene este º Tema 4. Queue队列, El tema para las órdenes de transmisión cambia de estado, asumiendo un estado en el orden: 未支付, 已支付, 发货中(处理中), 发货成功, 发货失败.
En la secuencia de tiempo, el productor puede ser generado a partir de la siguiente secuencia de varios mensajes:
订单T0000001:未支付 ->  订单T0000001:已支付 ->  订单T0000001:发货中(处理中) ->  订单T0000001:发货失败
Después de que el mensaje a la MQ, posiblemente debido a encuesta entregado, almacenada en el mensaje MQ puede ser como sigue:

 

En este caso, queremos 消费者orden y consumimos el mensaje que enviamos es el mismo, sin embargo, los mecanismos de entrega y consumo MQ anteriormente, no podemos garantizar el orden es el correcto para el orden inusual de mensajes, 消费者 incluso si hay algún estado tolerante a fallos, no podemos controlar totalmente tantas combinaciones aparecen al azar.

Basado en lo anterior, el RockeMQuso de esta aplicación: el mismo número de orden de mensaje, a través de una cierta política, se coloca en una  queue队列中, y 消费者a continuación, utilizar una determinada estrategia (un procesamiento separado una rosca queue, para asegurar que el orden de procesamiento de mensajes) secuencial, para asegurar el consumo

 

 

En cuanto a la forma en que la orden es para asegurar que la línea de consumo de consumo, a continuación, iniciar el seguimiento detallado, miramos 生产者es cómo ser capaz de enviar el mismo mensaje al mismo número de orden queue队列: el
productor en el proceso de entrega de mensajes, el uso de  MessageQueueSelector una selección de colas las interfaces de estrategia, que se definen como sigue:

package org.apache.rocketmq.client.producer;

import java.util.List;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;

public interface MessageQueueSelector {
        /**
         * 根据消息体和参数,从一批消息队列中挑选出一个合适的消息队列
         * @param mqs  待选择的MQ队列选择列表
         * @param msg  待发送的消息体
         * @param arg  附加参数
         * @return  选择后的队列
         */
        MessageQueue select(final List<MessageQueue> mqs, final Message msg, final Object arg);
}

En consecuencia, actualmente ofrece varios RocketMQ lograr lo siguiente:

 

 

 

La implementación por defecto:

estrategia de entrega clase de implementación de políticas explicación
estrategia de asignación al azar SelectMessageQueueByRandom El uso de un sencillo algoritmo de selección de número aleatorio
estrategia de asignación basado en hash SelectMessageQueueByHash El valor Hash del parámetro adicional de acuerdo con el tamaño del resto de la lista de cola de mensajes a tomar para obtener el índice de cola de mensajes
estrategia de asignación basado en la ubicación cuarto de máquinas SelectMessageQueueByMachineRoom La versión de código abierto ninguna implementación específica, el objetivo básico debe ser asignar principio de proximidad de la máquina

El código ahora probablemente mira estrategias para lograr:

public class SelectMessageQueueByHash implements MessageQueueSelector {

    @Override
    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
        int value = arg.hashCode();
        if (value < 0) {
            value = Math.abs(value);
        }

        value = value % mqs.size();
        return mqs.get(value);
    }
}

El funcionamiento real de la siguiente código de ejemplo, por el número de orden que los operandos de hash, puede garantizar el mismo número de orden de los mensajes puede caer en el mismo queue队列上.

rocketMQTemplate.asyncSendOrderly(saleOrderTopic + ":" + tag, msg,saleOrderId /*传入订单号作为hash运算对象*/, new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                log.info("SALE ORDER NOTIFICATION SUCCESS:{}",sendResult.getMsgId());
            }
            @Override
            public void onException(Throwable throwable) {
                 //exception happens
            }
        });

3. ¿Cómo asignar para el consumidor queue队列?

noticias RocketMQ de gasto de los consumidores en dos formas:

  • BROADCASTING: Difusión de los consumidores, en este modo, un mensaje se notifica a cada uno消费者

  • CLUSTERING: Consumo de Cluster, este modo, un mensaje será entregado a un máximo de 消费者consumo de conducta
    modo de la siguiente manera:

     

广播式El modo de mensaje es relativamente simple, vamos a introducir el siguiente 集群式. Para el modo de consumo MessageModel.CLUSTERINGcuando el consumidor, la necesidad de garantizar que 消息sólo necesita ser consumido una vez en todo el clúster. De hecho, en RoketMQ se asigna el mensaje que subyace a la especificada alcanzar a los consumidores a través de queue队列la distribución a 消费者manera de completa: es decir, 消息la unidad que se asigna el mensaje queue队列. A saber:

El queue队列particular asignada al 消费者puesto, queue队列todos los mensajes dentro será asignado a 消费者consumir.

política RocketMQ define la interfaz AllocateMessageQueueStrategypara un determinado 消费者分组, y 消息队列列表, 消费者列表, 当前消费者se debe asignar a lo que queue队列se define como sigue:

/**
 * 为消费者分配queue的策略算法接口
 */
public interface AllocateMessageQueueStrategy {

    /**
     * Allocating by consumer id
     *
     * @param consumerGroup 当前 consumer群组
     * @param currentCID 当前consumer id
     * @param mqAll 当前topic的所有queue实例引用
     * @param cidAll 当前 consumer群组下所有的consumer id set集合
     * @return 根据策略给当前consumer分配的queue列表
     */
    List<MessageQueue> allocate(
        final String consumerGroup,
        final String currentCID,
        final List<MessageQueue> mqAll,
        final List<String> cidAll
    );

    /**
     * 算法名称
     *
     * @return The strategy name
     */
    String getName();
}

En consecuencia, RocketMQ ofrece varios lograr lo siguiente:

 

 

nombre del algoritmo significado
AllocateMessageQueueAveragely El algoritmo de promedio asignación
AllocateMessageQueueAveragelyByCircle El algoritmo de promedio de asignación basado en anillo
AllocateMachineRoomNearby Habitación cerca del algoritmo basado en el principio de
AllocateMessageQueueByMachineRoom Sala de algoritmo de asignación
AllocateMessageQueueConsistentHash La consistencia algoritmo de hash
AllocateMessageQueueByConfig algoritmo de asignación basado en la configuración

Con el fin de comprender los principios básicos sobre el algoritmo anterior, asumimos un ejemplo, todo lo siguiente algoritmo se basará en este ejemplo para explicar.

Supongamos que la cola actual con un tema de colas  10más, los consumidores total de 4número, como se muestra a continuación:

 

 

El siguiente principio introducido a su vez:

3.1  AllocateMessageQueueAveragely- Promedio algoritmo de asignación

Aquí el llamado algoritmo de asignación promedio, no significa completamente normal en el sentido estricto, como en el ejemplo anterior, el 10 de colas, y los consumidores sólo 4, no es divisible las relaciones, además de la cola adicional divisible, ellos a su vez, se repartirán por igual de acuerdo con la orden del consumidor.
De acuerdo con el ejemplo anterior, vista 10/4=2, es decir, cada uno representa 消费者un promedio de dos compartida igualmente cola; y 10%4=2, además de compartir igualmente es decir, extra 2 queueno se ha asignado, entonces, de acuerdo con el pedido del consumidor consumer-1,, consumer-2, consumer-3, consumer-4el dos extra queuerespectivamente a consumer-1y consumer-2. Finalmente, compartir la siguiente relación:
consumer-1: 3个; consumer-2: 3个; consumer-3: 2个; consumer-4: 2个, como se muestra a continuación:

 


Su implementación del código es muy simple:

 

public class AllocateMessageQueueAveragely implements AllocateMessageQueueStrategy {
    private final InternalLogger log = ClientLogger.getLog();

    @Override
    public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> mqAll,
        List<String> cidAll) {
        if (currentCID == null || currentCID.length() < 1) {
            throw new IllegalArgumentException("currentCID is empty");
        }
        if (mqAll == null || mqAll.isEmpty()) {
            throw new IllegalArgumentException("mqAll is null or mqAll empty");
        }
        if (cidAll == null || cidAll.isEmpty()) {
            throw new IllegalArgumentException("cidAll is null or cidAll empty");
        }

        List<MessageQueue> result = new ArrayList<MessageQueue>();
        if (!cidAll.contains(currentCID)) {
            log.info("[BUG] ConsumerGroup: {} The consumerId: {} not in cidAll: {}",
                consumerGroup,
                currentCID,
                cidAll);
            return result;
        }

        int index = cidAll.indexOf(currentCID);
        int mod = mqAll.size() % cidAll.size();
        int averageSize =
            mqAll.size() <= cidAll.size() ? 1 : (mod > 0 && index < mod ? mqAll.size() / cidAll.size()
                + 1 : mqAll.size() / cidAll.size());
        int startIndex = (mod > 0 && index < mod) ? index * averageSize : index * averageSize + mod;
        int range = Math.min(averageSize, mqAll.size() - startIndex);
        for (int i = 0; i < range; i++) {
            result.add(mqAll.get((startIndex + i) % mqAll.size()));
        }
        return result;
    }

    @Override
    public String getName() {
        return "AVG";
    }
}

3.2  AllocateMessageQueueAveragelyByCircle - algoritmo de promedio basado en el anillo

algoritmo de promedio anular, de acuerdo a una secuencia se refiere a los consumidores, por secuencialmente queue队列uno asignado por una que consiste en un anillo de la fig. proceso específico es el siguiente:

 


El resultado final de este algoritmo de asignación es:
consumer-1: # 0, # 4, # 8
consumer-2: # 1, # 5, # 9
consumer-3: # 2, # 6
consumer-4: # 3, # 7
que codifican para los siguientes:

 

/**
 * Cycle average Hashing queue algorithm
 */
public class AllocateMessageQueueAveragelyByCircle implements AllocateMessageQueueStrategy {
    private final InternalLogger log = ClientLogger.getLog();

    @Override
    public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> mqAll,
        List<String> cidAll) {
        if (currentCID == null || currentCID.length() < 1) {
            throw new IllegalArgumentException("currentCID is empty");
        }
        if (mqAll == null || mqAll.isEmpty()) {
            throw new IllegalArgumentException("mqAll is null or mqAll empty");
        }
        if (cidAll == null || cidAll.isEmpty()) {
            throw new IllegalArgumentException("cidAll is null or cidAll empty");
        }

        List<MessageQueue> result = new ArrayList<MessageQueue>();
        if (!cidAll.contains(currentCID)) {
            log.info("[BUG] ConsumerGroup: {} The consumerId: {} not in cidAll: {}",
                consumerGroup,
                currentCID,
                cidAll);
            return result;
        }

        int index = cidAll.indexOf(currentCID);
        for (int i = index; i < mqAll.size(); i++) {
            if (i % cidAll.size() == index) {
                result.add(mqAll.get(i));
            }
        }
        return result;
    }

    @Override
    public String getName() {
        return "AVG_BY_CIRCLE";
    }
}

3.3  AllocateMachineRoomNearby- Basado en el principio de la habitación cerca del algoritmo

El algoritmo utilizado 装饰者设计模式para la estrategia de asignación se ha mejorado. En un entorno de producción en general, si la arquitectura micro-servicio, racimos RocketMQ despliegue pueden ser desplegados en diferentes habitaciones, la estructura básica puede ser como se muestra a continuación:

 


Para el escenario transversal habitación, la red existir razones, la estabilidad y el corazón aislado, el algoritmo basado en queueel despliegue de la ubicación de la habitación y 消费者consumerla posición, el filtro actual 消费者consumerla misma habitación queue队列, a continuación, la combinación de estos algoritmos tales como algoritmo de asignación basado en el promedio queue队列a continuación, elegir un subconjunto de la base. código relacionado para lograr lo siguiente:

 

@Override
    public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> mqAll,
        List<String> cidAll) {
        //省略部分代码
        List<MessageQueue> result = new ArrayList<MessageQueue>();

        //将MQ按照 机房进行分组
        Map<String/*machine room */, List<MessageQueue>> mr2Mq = new TreeMap<String, List<MessageQueue>>();
        for (MessageQueue mq : mqAll) {
            String brokerMachineRoom = machineRoomResolver.brokerDeployIn(mq);
            if (StringUtils.isNoneEmpty(brokerMachineRoom)) {
                if (mr2Mq.get(brokerMachineRoom) == null) {
                    mr2Mq.put(brokerMachineRoom, new ArrayList<MessageQueue>());
                }
                mr2Mq.get(brokerMachineRoom).add(mq);
            } else {
                throw new IllegalArgumentException("Machine room is null for mq " + mq);
            }
        }

        //将消费者 按照机房进行分组
        Map<String/*machine room */, List<String/*clientId*/>> mr2c = new TreeMap<String, List<String>>();
        for (String cid : cidAll) {
            String consumerMachineRoom = machineRoomResolver.consumerDeployIn(cid);
            if (StringUtils.isNoneEmpty(consumerMachineRoom)) {
                if (mr2c.get(consumerMachineRoom) == null) {
                    mr2c.put(consumerMachineRoom, new ArrayList<String>());
                }
                mr2c.get(consumerMachineRoom).add(cid);
            } else {
                throw new IllegalArgumentException("Machine room is null for consumer id " + cid);
            }
        }

        List<MessageQueue> allocateResults = new ArrayList<MessageQueue>();

        //1.过滤出当前机房内的MQ队列子集,在此基础上使用分配算法挑选
        String currentMachineRoom = machineRoomResolver.consumerDeployIn(currentCID);
        List<MessageQueue> mqInThisMachineRoom = mr2Mq.remove(currentMachineRoom);
        List<String> consumerInThisMachineRoom = mr2c.get(currentMachineRoom);
        if (mqInThisMachineRoom != null && !mqInThisMachineRoom.isEmpty()) {
            allocateResults.addAll(allocateMessageQueueStrategy.allocate(consumerGroup, currentCID, mqInThisMachineRoom, consumerInThisMachineRoom));
        }

        //2.不在同一机房,按照一般策略进行操作
        for (String machineRoom : mr2Mq.keySet()) {
            if (!mr2c.containsKey(machineRoom)) { // no alive consumer in the corresponding machine room, so all consumers share these queues
                allocateResults.addAll(allocateMessageQueueStrategy.allocate(consumerGroup, currentCID, mr2Mq.get(machineRoom), cidAll));
            }
        }

        return allocateResults;
    }

3,4  AllocateMessageQueueByMachineRoom- Basado en habitación algoritmo de asignación

Este algoritmo es adecuado para los mensajes internos que pertenecen a la misma habitación, a la cola de la asignación. Este enfoque es muy claro, sobre la base de lo anterior 机房临近分配算法escenario, esto más a fondo, especificar directamente una política basada en el consumo de la sala de máquinas. De esta manera una fuerte convención de propiedad, tales como brokerel nombre de la costura de habitación por su nombre, por convención dividió el análisis de algoritmos.
Qué código se implementa de la siguiente manera:

/**
 * Computer room Hashing queue algorithm, such as Alipay logic room
 */
public class AllocateMessageQueueByMachineRoom implements AllocateMessageQueueStrategy {
    private Set<String> consumeridcs;

    @Override
    public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> mqAll,
        List<String> cidAll) {
        List<MessageQueue> result = new ArrayList<MessageQueue>();
        int currentIndex = cidAll.indexOf(currentCID);
        if (currentIndex < 0) {
            return result;
        }
        List<MessageQueue> premqAll = new ArrayList<MessageQueue>();
        for (MessageQueue mq : mqAll) {
            String[] temp = mq.getBrokerName().split("@");
            if (temp.length == 2 && consumeridcs.contains(temp[0])) {
                premqAll.add(mq);
            }
        }

        int mod = premqAll.size() / cidAll.size();
        int rem = premqAll.size() % cidAll.size();
        int startIndex = mod * currentIndex;
        int endIndex = startIndex + mod;
        for (int i = startIndex; i < endIndex; i++) {
            result.add(mqAll.get(i));
        }
        if (rem > currentIndex) {
            result.add(premqAll.get(currentIndex + mod * cidAll.size()));
        }
        return result;
    }

    @Override
    public String getName() {
        return "MACHINE_ROOM";
    }

    public Set<String> getConsumeridcs() {
        return consumeridcs;
    }

    public void setConsumeridcs(Set<String> consumeridcs) {
        this.consumeridcs = consumeridcs;
    }

3,5  AllocateMessageQueueConsistentHashSobre la base de la consistencia de algoritmo de hash

Utilizando este algoritmo, se consumer消费者configura como un nodo Nodo anillo de hachís, a continuación, queue队列decidir que se asigna a la almohadilla a través del anillo consumer消费者.
Los modos básicos son:

 

 

¿Cuál es la consistencia del algoritmo de hash?
Algoritmo de hash La consistencia se utiliza en un sistema distribuido, garantizar la consistencia de los datos y propuso una implementación basada en el anillo de algoritmo de hash, limitada a la longitud del artículo, no estoy aquí para ampliar descrito, los estudiantes interesados pueden Bowen se refiere a los otros: el principio del algoritmo de hash consistente

El algoritmo no es complicado, como se muestra a continuación:

public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> mqAll,
        List<String> cidAll) {
        //省略部分代码
        List<MessageQueue> result = new ArrayList<MessageQueue>();
        if (!cidAll.contains(currentCID)) {
            log.info("[BUG] ConsumerGroup: {} The consumerId: {} not in cidAll: {}",
                consumerGroup,
                currentCID,
                cidAll);
            return result;
        }

        Collection<ClientNode> cidNodes = new ArrayList<ClientNode>();
        for (String cid : cidAll) {
            cidNodes.add(new ClientNode(cid));
        }
//使用consumer id 构造hash环
        final ConsistentHashRouter<ClientNode> router; //for building hash ring
        if (customHashFunction != null) {
            router = new ConsistentHashRouter<ClientNode>(cidNodes, virtualNodeCnt, customHashFunction);
        } else {
            router = new ConsistentHashRouter<ClientNode>(cidNodes, virtualNodeCnt);
        }
        //依次为 队列分配 consumer
        List<MessageQueue> results = new ArrayList<MessageQueue>();
        for (MessageQueue mq : mqAll) {
            ClientNode clientNode = router.routeNode(mq.toString());
            if (clientNode != null && currentCID.equals(clientNode.getKey())) {
                results.add(mq);
            }
        }

        return results;

    }

3.6  AllocateMessageQueueByConfig- Configurar algoritmo de asignación basado en

Este algoritmo se basa en una configuración simple, un uso muy simple, real no puede usar. Código es el siguiente:

public class AllocateMessageQueueByConfig implements AllocateMessageQueueStrategy {
    private List<MessageQueue> messageQueueList;

    @Override
    public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> mqAll,
        List<String> cidAll) {
        return this.messageQueueList;
    }

    @Override
    public String getName() {
        return "CONFIG";
    }

    public List<MessageQueue> getMessageQueueList() {
        return messageQueueList;
    }

    public void setMessageQueueList(List<MessageQueue> messageQueueList) {
        this.messageQueueList = messageQueueList;
    }
}

3.7 Cómo consumidores especifique el algoritmo de asignación?

Por defecto, los consumidores están usando el AllocateMessageQueueAveragelyalgoritmo, puede especificar su propia:

public class DefaultMQPushConsumer{    
    /**
     * Default constructor.
     */
    public DefaultMQPushConsumer() {
        this(MixAll.DEFAULT_CONSUMER_GROUP, null, new AllocateMessageQueueAveragely());
    }

    /**
     * Constructor specifying consumer group, RPC hook and message queue allocating algorithm.
     *
     * @param consumerGroup Consume queue.
     * @param rpcHook RPC hook to execute before each remoting command.
     * @param allocateMessageQueueStrategy message queue allocating algorithm.
     */
    public DefaultMQPushConsumer(final String consumerGroup, RPCHook rpcHook,
        AllocateMessageQueueStrategy allocateMessageQueueStrategy) {
        this.consumerGroup = consumerGroup;
        this.allocateMessageQueueStrategy = allocateMessageQueueStrategy;
        defaultMQPushConsumerImpl = new DefaultMQPushConsumerImpl(this, rpcHook);
    }
}

4. Conclusión

Lo anterior es de la breve diseño del mecanismo de entrega RocketMQ, si quieres principios de diseño más detallados, el público puede estar preocupado por mi cuenta a continuación, se actualizará al mismo tiempo, gracias al apoyo ~
autor se limita, mensaje de bienvenida correcciones Tucao ~

Publicado 13 artículos originales · ganado elogios 78 · Vistas de 450.000 +

Supongo que te gusta

Origin blog.csdn.net/bluehawksky/article/details/100663989
Recomendado
Clasificación