你的消息真的发出去了吗?

482 阅读3分钟

我正在参加「掘金·启航计划」

1.前言

想要在项目中实现消息发送,你可能会选择rabbitmq或者kafka。无论选择哪一个消息中间件,在与springboot集成时,都会使用其提供的xxxTemplate来实现消息的发送。

使用rabbitmq时会通过rabbitTemplate.convertAndSend("exchange", "routingkey", "消息内容");方法来发送消息

使用kafka时会通过kafkaTemplate.send("topic", "消息内容");方法来发送消息

理想情况下这样使用完全没有问题,但是在一些极端场景下,会出现消息丢失的情况。比如:应用程序将消息发送给消息中间件,消息中间件故障了或者无法处理。

那么我们该如何正确的发送消息,如何保证消息一定发送到消息中间件?

下面将分别介绍rabbitmqkafka正确的消息发送方式

2.rabbitmq

2.1 设置confirm类型

spring:
  rabbitmq:
    publisher-confirm-type: 选择SIMPLE或CORRELATED

2.2 同步处理

rabbitTemplate.waitForConfirms(等待时间);

2.3 异步处理

设置callback

rabbitTemplate.setConfirmCallback(new RabbitTemplateConfirmCallback());

为什么这样做就可以实现消息发送的可靠性呢?

2.4 开启生产者确认模式

2.5 处理消息服务器返回结果

这里就可以搞明白为什么设置confirmTypecallback就可以实现消息的可靠性,那么waitForConfirms又是怎么一回事呢?

2.6 处理ack和nack

再来看看waitForConfirms的实现

这里我们可以得知,当调用waitForConfirms方法时,会阻塞,直到收到消息服务器的确认为止。当收到的返回值为true则说明消息已被消息服务器成功接收;当收到false则说明消息未被消息服务器成功接收,针对该场景就需要根据业务场景进行特殊处理(比如重试)来保证消息一定发送到消息服务器。

3.kafka

3.1 设置acks

spring:
  kafka:
    producer:
      acks: all # 设置确认模式,默认值all 0:生产者不需要等待server确认 1:生产者将消息发送给leader副本,leader副本在写入本地日志成功后才会告知生产者消息已经提交成功 -1:生产者将消息发送给leader副本,leader副本在写入本地日志成功后还需要等待ISR中所有flower副本同步完成后才会告知生产者消息已经提交成功

3.2 接收并处理异步结果

public void sendSimpleMessage(String topic, V value) {
    CompletableFuture<SendResult<K, V>> completableFuture = kafkaTemplate.send(topic, value);
    SendResult<K, V> sendResult = null;
    try {
        sendResult = completableFuture.get();
    } catch (InterruptedException | ExecutionException e) {
        throw new RuntimeException(e);
    }
​
    if (Objects.isNull(sendResult)) {
        log.warn("send result is null");
        return;
    }
​
    ProducerRecord<K, V> producerRecord = sendResult.getProducerRecord();
    log.info("producer record:{}", producerRecord);
    RecordMetadata recordMetadata = sendResult.getRecordMetadata();
    log.info("record metadata:{}", recordMetadata);
}

为什么这样做就可以消息的可靠性?

3.3 定义response

3.4 调用消息callback

3.5 消息callback定义

看到消息callback的定义就可以串起整个链路。当收到kafka服务器返回时,会调用callbackcallback根据kafka消息服务器是否返回异常来组装CompletableFuture,调用者可以从CompletableFuture得到最终结果,如果结果正常,则无需处理;如果结果异常,可选择进行特殊处理(比如重试),从而保证消息一定发送到消息服务器。

4.总结

要想实现消息一定发送到消息服务器,就需要得到消息服务器的反馈,只有根据反馈结果才能知道消息是否成功发送。

不对服务器返回结果做进一步处理,在一些极端场景下会导致消息的丢失。当然,如果业务场景不在乎消息的丢失,可以选择不对反馈结果进行处理。