概述
一、producer和consumer三种消息交付的语义
在kafka中,在producer和consumer这两个维度上都有三种消息交付的语义:
- At most once ---- 消息可能会丢失但绝不重传.
- At least once ---- 消息可以重传但绝不丢失.
- Exactly once ---- 每一条消息只被传递一次.
二、producer三种消息交付的语义
在producer设置中,有一个选项为ack:每发送一次消息,都会要求broker返回一个消息回执。如果ack没有收到,且设置了重发次数,那么producer会进行重发。这个ack有三种模式:
// The level of acknowledgement reliability needed from the broker (defaults
// to WaitForLocal). Equivalent to the `request.required.acks` setting of the JVM producer.
// 等同于jvm kafka中的`request.required.acks`
type RequiredAcks int16
const (
// 第一个模式,NoResponse doesn't send any response, the TCP ACK is all you get.
NoResponse RequiredAcks = 0
// 第二个模式, WaitForLocal waits for only the local commit to succeed before responding.
WaitForLocal RequiredAcks = 1
// 第三个模式,WaitForAll waits for all in-sync replicas to commit before responding.
// The minimum number of in-sync replicas is configured on the broker via the `min.insync.replicas` configuration key.
WaitForAll RequiredAcks = -1
)
如果RequiredAcks设置为0,对于服务器是否收到请求,是没法保证的;并且参数retries(重发)也不会生效(因为客户端无法获得失败信息)。此时提供的是At most once的语义。
如果RequiredAcks大于0,producer在没有收到应答的情况下,会进行重发。此时提供的是At least once的语义。
三、对于producer,幂等性保证Exactly once
在kafka 0.11.0.0之前,是无法保证Exactly once的。但从0.11.0.0开始,producer引入了幂等性的概念,保证消息只会被传递一次。
那么kafka是如何实现的呢?用到了Producer ID(即PID)和Sequence Number。
PID:在初始化的时候,每个新的Producer会被分配一个唯一的PID。这个PID对用户是不可见的。
Sequence Numbler:对于每个PID,该Producer发送数据的每个[ Topic, Partition ]都对应一个从0开始单调递增的Sequence Number。
Broker端在缓存中保存了Sequence Numbler,对于接收的每条消息,如果其序号比Broker缓存中的序号大于1,则接受它;否则,将其丢弃,这样就可以防止消息重复提交。
但是,以上只能保证单个Producer对于同一个[ Topic, Partition ]的Exactly Once语义,不保证同一个Producer一个topic下不同Partition的幂等。
四、对于producer,事务保证Exactly once
从0.11.0.0开始,kafka支持了producer事务。要注意的一点是,不要把“操作db的业务逻辑”跟“操作消息的业务逻辑”当成一个事务。因为操作DB数据库的数据源是DB,消息数据源是kfaka,是完全不同的两个数据;一种数据源(如mysql,kafka)对应一个事务,所以它们是两种独立的事务。kafka事务指“kafka一系列生产、消费消息等操作”组成一个事务。db事务是指“操作数据库的一系列增删改操作”组成一个事务。
对于producer和生产消息来说,如果是只有写(即一条消息要发送给多个topic),可以使用producer事务来保证“要么都发送了,要么就都没有发送”。
如果有消费消息,然后再发送给别的topic,最后提交offset,也可以使用producer事务来保证这一系列操作的原子性。比如消费者提交offset出现问题,导致consumer在重复消费消息的时候,生产者会重复生产消息给其他的消费者。
如果只是消费消息和提交offset,那么producer事务就显得没有意义了。因为这个和手动提交offset没有什么区别。
五、consumer三种消息交付的语义
Consumer 读取到消息之后,先进行offset提交,然后再处理消息。如果在某中间时刻消息处理失败了,那这条消息就再也不会被消费了。这对应于at-most-once的语义。
Consumer 读取到消息之后,先处理消息,最后再offset提交。采用这种方式,如果处理消息成功,但是在offset提交之前服务崩溃了,那么在服务重启之后,这条消息会再次被消费到。这对应于at-least-once的语义。
如果要Exactly once语义,则可以使用如下手段:
消费处理失败指的是业务失败或者操作db失败。
消费处理成功指的是业务成功或者操作db成功。
1,如果消费处理失败,则需要额外记录此条消息的offset(对于有顺序要求的消费来说,此时还得停止消费),下次再统一去消费这些处理失败的offset的消息。
2,同样消费处理失败,也可以利用producer事务来保证。例如,提交offset并且把offset发送到另一个topic中,来保证这一系列的原子性;如果消费处理失败了,则中断事务,offset就不会被发送到topic中,topic中保存的还是上次那个offset。
3,如果消费处理成功,需要额外保存最新提交的offset到文件系统中,然后提交offset。这样,不管offset提交成功,还是失败,在重启之后,都可以从文件中拿到最新的offset。
4,或者,消费处理成功的同时,把offset写到db中,意思就是:首先,consumer将offset值存储到相同的地方;然后,提交offset。这样,输出的地方保存的也是最新、最准确的offset。
尊重别人的劳动成果,原文:https://blog.csdn.net/jeffrey11223/article/details/80775080
最后
以上就是潇洒小熊猫为你收集整理的kafka消息交付语义的分析一、producer和consumer三种消息交付的语义二、producer三种消息交付的语义三、对于producer,幂等性保证Exactly once四、对于producer,事务保证Exactly once五、consumer三种消息交付的语义的全部内容,希望文章能够帮你解决kafka消息交付语义的分析一、producer和consumer三种消息交付的语义二、producer三种消息交付的语义三、对于producer,幂等性保证Exactly once四、对于producer,事务保证Exactly once五、consumer三种消息交付的语义所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复