RocketMQ copia código de registro de consumo

1. Antecedentes

El escenario empresarial más reciente requiere sincronización de datos. En pocas palabras, los datos de origen deben almacenarse en la base de datos de Oracle. Hay demasiados datos históricos en la base de datos de Oracle y la consulta tarda demasiado en ser aceptada por los usuarios. Por lo tanto, la base de datos mysql se divide en tablas y los datos deben sincronizarse con la base de datos mysql. La implementación original era ejecutar una tarea programada todos los días para sincronizar los datos del día anterior. El problema surgió y los datos no se sincronizaron a tiempo. Si realiza una consulta, hay dos interfaces. Los datos históricos son verificados por Mysql y los datos del día son verificados por Oracle. Pero la lógica de las dos interfaces es exactamente la misma, porque las funciones comerciales son las mismas, lo cual es muy ** [difícil de describir]. Entonces el punto está aquí. Usando el método de mensaje, cuando los datos se guardan en Oracle, envíe un mensaje, el cuerpo del mensaje son los datos guardados, consuma el mensaje y guarde los datos en Mysql, lo que básicamente garantiza el rendimiento en tiempo real. ¿Qué pasa si no usa mensajes? Después de guardar Oracle y luego guardar en Mysql, ¿esta interfaz de guardado es demasiado larga? Hermano dei [no

Segundo, date cuenta

1. Configuración del productor de mensajes

/**
 * 消息生产方配置
 *
 * @yx8102 2019/1/25
 */
@Component
public class MessageProducerConfig {

    // 消息服务器地址
    @Value("${message.producer.serverAddress}")
    private String serverAddress;

    // 发送分组名称
    @Value("${message.producer.groupName}")
    private String groupName;

    @Bean
    public RocketMqClient initRocketMqClient(){
        validateMessage();
        RocketMqServer server = RocketMqServer.build(this.serverAddress);
        return RocketMqClient.build(server, this.groupName);
    }

    private void validateMessage(){
        Assert.notNull(this.serverAddress, "serverAddress is blank");
        Assert.notNull(this.groupName, "groupName is blank");
    }

    public void setServerAddress(String serverAddress) {
        this.serverAddress = serverAddress;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }
}

2. Servicio de envío de mensajes

/**
 * 发送消息服务
 *
 * @xyang010 2019/1/30
 */
@Service
@Slf4j
public class PictureSyncMessageService {

    @Autowired
    private RocketMqClient rocketMqClient;


    /**
     * 发送同步消息
     * @param syncFailedDO
     */
    public void sendPictureSyncMessage(PictureSyncFailedDO syncFailedDO) {

        //1. 拼装消息
        RocketMqMessage mqMessage = new RocketMqMessage();
        mqMessage.setTopic(MessageConstant.ROCKET_MQ_TOPIC);
        mqMessage.setTag(MessageConstant.PICTURE_SYNC_TAG);
        mqMessage.setKey(buildMessageKey(syncFailedDO.getZpFileId()));
        mqMessage.setData(syncFailedDO);

        //2. 发送消息
        ITryCatchResult<SendResult> invokeResult = rocketMqClient.send(mqMessage);

        //3. 发送成功
        if(invokeResult.isSuccess() && invokeResult.getResult() != null) {
            SendResult sendRes = invokeResult.getResult();
            SendStatus sendStatus = sendRes.getSendStatus();
            if (sendStatus.equals(SendStatus.SEND_OK)) {
                
            }
        }
    }

    /**
     * 创建messageKey
     * @param id
     * @return
     */
    private static String buildMessageKey(Long id){
        return  "zpFileId:"+ id +"_" + UUIDUtils.getUUID("N");
    }
}

3. Configuración de mensajes del consumidor

/**
 * 消息消费方配置
 *
 * @yx8102 2019/2/2
 */
@Component
@Slf4j
public class MessageConsumerConfig {

    @Value("${message.consumer.serverAddress}")
    private String serverAddress;

    @Value("${message.consumer.groupName}")
    private String groupName;

    @Value("${message.consumer.topic}")
    private String topic;

    @Autowired
    private PictureSyncMessageListener messageListener;

    @Bean
    public DefaultMQPushConsumer getRocketMQConsumer() {
        validateMessage();
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(groupName);
        consumer.setNamesrvAddr(serverAddress);
        consumer.setMessageListener(messageListener);
        consumer.setConsumeMessageBatchMaxSize(10);
        consumer.setConsumeThreadMax(10);
        consumer.setConsumeThreadMin(5);
        try{
            consumer.subscribe(topic, MessageConstant.PICTURE_SYNC_TAG);
            consumer.start();
            log.info("message consumer is start successfully");
        } catch (MQClientException e){
            log.error("message consumer start error {}", e);
        }
        return consumer;
    }

    public void setServerAddress(String serverAddress) {
        this.serverAddress = serverAddress;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public void setTopic(String topic) {
        this.topic = topic;
    }

    private void validateMessage(){
        Assert.notNull(this.serverAddress, "serverAddress is blank");
        Assert.notNull(this.groupName, "groupName is blank");
        Assert.notNull(this.topic, "topic is blank");
    }
}

4. Servicio de mensajería al consumidor

/**
 * 消息监听服务
 *
 * @yx8102 2019/2/2
 */
@Component
@Slf4j
public class PictureSyncMessageListener implements MessageListenerConcurrently {

    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {

        for (MessageExt messageExt : msgs) {
            String message = new String(messageExt.getBody());
            log.info("receive picture sync message {}", message);

            PictureSyncFailedDO syncFailedDO = JSON.parseObject(message, PictureSyncFailedDO.class);
            
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
    }
}

5. Descripción

  • Aumente la configuración del consumidor: clusterName, brokerName, groupName
  • Agregar tema: usar nombres de casos de camellos
  • Solo use un producerGroupName y consumerGroupName para cada proyecto del productor y consumidor
  • El mismo tema se puede filtrar según diferentes etiquetas
  • El productor solo puede comenzar una vez
  • Los consumidores deben recordar comenzar
  • En la prueba única local, el tiempo de suspensión es lo suficientemente largo como para garantizar que el mensaje se envíe y supervise
  • ConsumerListener se puede configurar para la clase correspondiente, y diferentes temas necesitan diferentes clases de configuración

Supongo que te gusta

Origin blog.csdn.net/yxz8102/article/details/88309339
Recomendado
Clasificación