消息投递语义
投递语义,即生产者投递到服务端
- 如何保证消息最多投递一次
- 如何保证消息至少投递一次
- 如何保证消息恰好投递一次
消费语义,即消费者消费服务端
- 如何保证消息最多消费一次
- 如何保证消息至少消费一次
- 如何保证消息恰好消费一次
以下对各种语义,用kafka进行讲解:
# 1. 生产者
# 如何保证消息最多投递一次
消息最多投递一次,即消息要么不投递,要么只投递成功一次
简单,就是我已经投出去了,收没收到不管了,会存在消息丢失。
我们在初始化Producer
时可以通过配置request.required.acks
不同的值,来实现不同的发送模式。
这里将request.required.acks
设为0,意思就是Producer
不等待Leader确认,只管发出即可;最可能丢失消息。如果丢了消息,就是投递0次。如果没丢,就是投递1次。符合最多投递一次的含义。
# 如何保证消息至少投递一次
消息要么重复发送,要么只发送成功一次
这里将request.required.acks
设为-1。Producer
往kafka
的Leader(主)
节点发送消息后,会等follower(从)
节点同步完数据以后,再给Producer
返回ACK确认消息。
但是这里是有几率出现重复消费的问题的。
例如,kafka
保存消息后,发送ACK前宕机,Producer
认为消息未发送成功并重试,造成数据重复!
那么,在这种情况下,就会出现大于1次的投递情况,符合至少投递一次的含义。
# 如何保证消息恰好投递一次
消息发送确保只成功发送一次
kafka
在0.11.0.0版本之后支持恰好投递一次的语义。
我们将enable.idempotence
设置为ture,此时就会默认把request.required.acks
设为-1,可以达到恰好投递一次的语义。
如何做到的?
为了实现Producer
的幂等语义,Kafka引入了Producer ID(即PID)和Sequence Number。
kafka
为每个Producer
分配一个pid,作为该Producer
的唯一标识。
Producer
会为每一个<topic,partition>维护一个单调递增的seq。
类似的,Message Queue
也会为每个<pid,topic,partition>记录下最新的seq。
当req_seq == message_seq+1时,Message Queue
才会接受该消息。因为:
- (1)消息的seq比
Message Queue
的seq大一以上,说明中间有数据还没写入,即乱序了。 - (2)消息的seq比
Message Queue
的seq小,那么说明该消息已被保存。
# 2.消费者
# 如果保证消息最多消费一次
消费者要么消费,要么只消费一次
其实这里根消费者的位移提交机制有关。
按照下面的处理方式
consumer.poll();
consumer.commit();
processMsg(msg);
2
3
消费者如果在处理消息前宕机,那么下次消费时将不会再处理消息,消息丢失。即最多就消费了一次。
# 如果保证消息至少消费一次
消费者要么消费一次,要么多次消费
consumer.poll();
processMsg(msg);
consumer.commit();
2
3
消费者如果在提交位移前宕机,那么下次消费时将再次处理,消息重复消费。即消息进行了多次消费。
# 如果保证消息只消费一次
https://juejin.cn/post/7002169135908012062#heading-8
思路:至少一次 + 幂等性(为每条消息分配唯一id,并在第三方缓存中进行幂等性去重)
https://www.yuque.com/u1047901/hs89ud/aagb2utmhitxtccv