[mq] Realice el envío y la recepción por lotes de mq-12-messages desde cero

Revisión de prospectos

[mq] Implementar mq-01-productor y inicio de consumidor desde cero

[mq] Para implementar mq-02 desde cero: ¿cómo implementar un productor que llama a un consumidor?

[mq] Implementación de mq-03-introducción de intermediarios de corredores desde cero

[mq] Realice la detección y optimización de mq-04-start desde cero

[mq] Implementar mq-05 desde cero: lograr un apagado correcto

[mq] Darse cuenta de mq-06-consumidor de detección de latidos desde cero

[mq] Realice mq-07-balance de carga balance de carga desde cero

[mq] Implementar la optimización de configuración mq-08 con fluidez desde cero

[mq] Implementar mensaje de extracción mq-09-consumidor desde cero

[mq] Implementar mq-10-recepción de mensaje de extracción de consumidor desde cero

[mq] Implementar la recepción del mensaje mq-11-consumidor desde cero agregar información de grupo extraer mensaje ACK groupName

[mq] Realice el envío y la recepción por lotes de mq-12-messages desde cero

mensaje masivo

Para el envío de mensajes, a veces puede ser necesario enviar más de uno a la vez, como mensajes de registro.

Las operaciones masivas pueden mejorar el rendimiento.

En esta sección, el viejo caballo agregará una pequeña función de lote con usted.

lote

Envío masivo de mensajes

Implementación del productor

Definición de interfaz

/**
 * 同步发送消息-批量
 * @param mqMessageList 消息类型
 * @return 结果
 * @since 0.1.3
 */
SendBatchResult sendBatch(final List<MqMessage> mqMessageList);

/**
 * 单向发送消息-批量
 * @param mqMessageList 消息类型
 * @return 结果
 * @since 0.1.3
 */
SendBatchResult sendOneWayBatch(final List<MqMessage> mqMessageList);
复制代码

Admite el envío de varios mensajes a la vez.

implementación de la interfaz

El productor se implementa de la siguiente manera.

@Override
public SendBatchResult sendBatch(List<MqMessage> mqMessageList) {
    final List<String> messageIdList = this.fillMessageList(mqMessageList);
    final MqMessageBatchReq batchReq = new MqMessageBatchReq();
    batchReq.setMqMessageList(mqMessageList);
    String traceId = IdHelper.uuid32();
    batchReq.setTraceId(traceId);
    batchReq.setMethodType(MethodType.P_SEND_MSG_BATCH);
    return Retryer.<SendBatchResult>newInstance()
            .maxAttempt(maxAttempt)
            .callable(new Callable<SendBatchResult>() {
                @Override
                public SendBatchResult call() throws Exception {
                    return doSendBatch(messageIdList, batchReq, false);
                }
            }).retryCall();
}

@Override
public SendBatchResult sendOneWayBatch(List<MqMessage> mqMessageList) {
    List<String> messageIdList = this.fillMessageList(mqMessageList);
    MqMessageBatchReq batchReq = new MqMessageBatchReq();
    batchReq.setMqMessageList(mqMessageList);
    String traceId = IdHelper.uuid32();
    batchReq.setTraceId(traceId);
    batchReq.setMethodType(MethodType.P_SEND_MSG_ONE_WAY_BATCH);
    return doSendBatch(messageIdList, batchReq, true);
}


private SendBatchResult doSendBatch(List<String> messageIdList,
                               MqMessageBatchReq batchReq,
                               boolean oneWay) {
    log.info("[Producer] 批量发送消息 messageIdList: {}, batchReq: {}, oneWay: {}",
            messageIdList, JSON.toJSON(batchReq), oneWay);
    // 以第一个 sharding-key 为准。
    // 后续的会被忽略
    MqMessage mqMessage = batchReq.getMqMessageList().get(0);
    Channel channel = getChannel(mqMessage.getShardingKey());
    //one-way
    if(oneWay) {
        log.warn("[Producer] ONE-WAY send, ignore result");
        return SendBatchResult.of(messageIdList, SendStatus.SUCCESS);
    }
    MqCommonResp resp = callServer(channel, batchReq, MqCommonResp.class);
    if(MqCommonRespCode.SUCCESS.getCode().equals(resp.getRespCode())) {
        return SendBatchResult.of(messageIdList, SendStatus.SUCCESS);
    }
    throw new MqException(ProducerRespCode.MSG_SEND_FAILED);
}
复制代码

pd: Hay una diferencia entre esto y un envío único, y esa es la elección del canal. Debido a que solo se puede seleccionar uno, la clave de fragmentación de cada mensaje no se puede tener en cuenta.

Manejo de Corredores

distribución de mensajes

// 生产者消息发送-批量
if(MethodType.P_SEND_MSG_BATCH.equals(methodType)) {
    return handleProducerSendMsgBatch(channelId, json);
}

// 生产者消息发送-ONE WAY-批量
if(MethodType.P_SEND_MSG_ONE_WAY_BATCH.equals(methodType)) {
    handleProducerSendMsgBatch(channelId, json);
    return null;
}
复制代码

Implementación

/**
 * 处理生产者发送的消息
 *
 * @param channelId 通道标识
 * @param json 消息体
 * @since 0.1.3
 */
private MqCommonResp handleProducerSendMsgBatch(String channelId, String json) {
    MqMessageBatchReq batchReq = JSON.parseObject(json, MqMessageBatchReq.class);
    final ServiceEntry serviceEntry = registerProducerService.getServiceEntry(channelId);
    List<MqMessagePersistPut> putList = buildPersistPutList(batchReq, serviceEntry);

    MqCommonResp commonResp = mqBrokerPersist.putBatch(putList);

    // 遍历异步推送
    for(MqMessagePersistPut persistPut : putList) {
        this.asyncHandleMessage(persistPut);
    }
    return commonResp;
}
复制代码

Aquí, la lista de mensajes se conserva.

La estrategia de persistencia demostrada es la siguiente:

@Override
public MqCommonResp putBatch(List<MqMessagePersistPut> putList) {
    // 构建列表
    for(MqMessagePersistPut put : putList) {
        this.doPut(put);
    }

    MqCommonResp commonResp = new MqCommonResp();
    commonResp.setRespCode(MqCommonRespCode.SUCCESS.getCode());
    commonResp.setRespMessage(MqCommonRespCode.SUCCESS.getMsg());
    return commonResp;
}
复制代码

ACK masivo para mensajes

ilustrar

La implementación anterior es realizar un ACK después de que se complete el consumo de cada mensaje.

Para el consumo de mensajes de la estrategia de extracción, podemos esperar el final del lote actual y emitir un recibo ACK de manera uniforme.

Realización del consumo

El ajuste se implementa de la siguiente manera:

for(MqTopicTagDto tagDto : subscribeList) {
    final String topicName = tagDto.getTopicName();
    final String tagRegex = tagDto.getTagRegex();
    MqConsumerPullResp resp = consumerBrokerService.pull(topicName, tagRegex, size);

    if(MqCommonRespCode.SUCCESS.getCode().equals(resp.getRespCode())) {
        List<MqMessage> mqMessageList = resp.getList();
        if(CollectionUtil.isNotEmpty(mqMessageList)) {
            List<MqConsumerUpdateStatusDto> statusDtoList = new ArrayList<>(mqMessageList.size());
            for(MqMessage mqMessage : mqMessageList) {
                IMqConsumerListenerContext context = new MqConsumerListenerContext();
                final String messageId = mqMessage.getTraceId();
                ConsumerStatus consumerStatus = mqListenerService.consumer(mqMessage, context);
                log.info("消息:{} 消费结果 {}", messageId, consumerStatus);

                // 状态同步更新
                if(!ackBatchFlag) {
                    MqCommonResp ackResp = consumerBrokerService.consumerStatusAck(messageId, consumerStatus);
                    log.info("消息:{} 状态回执结果 {}", messageId, JSON.toJSON(ackResp));
                } else {
                    // 批量
                    MqConsumerUpdateStatusDto statusDto = new MqConsumerUpdateStatusDto();
                    statusDto.setMessageId(messageId);
                    statusDto.setMessageStatus(consumerStatus.getCode());
                    statusDto.setConsumerGroupName(groupName);
                    statusDtoList.add(statusDto);
                }
            }

            // 批量执行
            if(ackBatchFlag) {
                MqCommonResp ackResp = consumerBrokerService.consumerStatusAckBatch(statusDtoList);
                log.info("消息:{} 状态批量回执结果 {}", statusDtoList, JSON.toJSON(ackResp));
                statusDtoList = null;
            }
        }
    } else {
        log.error("拉取消息失败: {}", JSON.toJSON(resp));
    }
}
复制代码

Si ackBatchFlag = falso, la lógica de procesamiento es la misma que antes.

Si ackBatchFlag = true, coloque el mensaje en la lista primero y ejecútelo uniformemente después del final.

implementación del corredor

distribución de mensajes

//消费者消费状态 ACK-批量
if(MethodType.C_CONSUMER_STATUS_BATCH.equals(methodType)) {
    MqConsumerUpdateStatusBatchReq req = JSON.parseObject(json, MqConsumerUpdateStatusBatchReq.class);
    final List<MqConsumerUpdateStatusDto> statusDtoList = req.getStatusList();
    return mqBrokerPersist.updateStatusBatch(statusDtoList);
}
复制代码

realizar

La implementación de persistencia predeterminada, actualizada de la siguiente manera:

@Override
public MqCommonResp updateStatusBatch(List<MqConsumerUpdateStatusDto> statusDtoList) {
    for(MqConsumerUpdateStatusDto statusDto : statusDtoList) {
        this.doUpdateStatus(statusDto.getMessageId(), statusDto.getConsumerGroupName(),
                statusDto.getMessageStatus());
    }

    MqCommonResp commonResp = new MqCommonResp();
    commonResp.setRespCode(MqCommonRespCode.SUCCESS.getCode());
    commonResp.setRespMessage(MqCommonRespCode.SUCCESS.getMsg());
    return commonResp;
}
复制代码

Recorre cada elemento y actualiza el estado.

resumen

Asíncrono y por lotes son las dos formas más comunes de mejorar el rendimiento.

La implementación por lotes es la más fácil y efectiva.

Espero que este artículo te sea útil. Si te gusta, dale me gusta, recógelo y reenvíalo.

Soy un caballo viejo, y espero verte de nuevo la próxima vez.

dirección de fuente abierta

La cola de mensajes en Java (implementación mq de la versión simple de Java) github.com/houbb/mq

Lectura extendida

rpc - Implementando rpc desde cero github.com/houbb/rpc

Supongo que te gusta

Origin juejin.im/post/7098894399630737415
Recomendado
Clasificación