我正在参加「掘金·启航计划」
1.前言
想要在项目中实现消息发送,你可能会选择rabbitmq或者kafka。无论选择哪一个消息中间件,在与springboot集成时,都会使用其提供的xxxTemplate来实现消息的发送。
使用rabbitmq时会通过rabbitTemplate.convertAndSend("exchange", "routingkey", "消息内容");方法来发送消息
使用kafka时会通过kafkaTemplate.send("topic", "消息内容");方法来发送消息
理想情况下这样使用完全没有问题,但是在一些极端场景下,会出现消息丢失的情况。比如:应用程序将消息发送给消息中间件,消息中间件故障了或者无法处理。
那么我们该如何正确的发送消息,如何保证消息一定发送到消息中间件?
下面将分别介绍rabbitmq和kafka正确的消息发送方式
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 处理消息服务器返回结果
这里就可以搞明白为什么设置confirmType和callback就可以实现消息的可靠性,那么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服务器返回时,会调用callback,callback根据kafka消息服务器是否返回异常来组装CompletableFuture,调用者可以从CompletableFuture得到最终结果,如果结果正常,则无需处理;如果结果异常,可选择进行特殊处理(比如重试),从而保证消息一定发送到消息服务器。
4.总结
要想实现消息一定发送到消息服务器,就需要得到消息服务器的反馈,只有根据反馈结果才能知道消息是否成功发送。
不对服务器返回结果做进一步处理,在一些极端场景下会导致消息的丢失。当然,如果业务场景不在乎消息的丢失,可以选择不对反馈结果进行处理。