如果你已经了解了kafka的producer基础理论,可以跳过这篇文章
Partition & Replicas
我创建了一个名为producer-0
的topic
,partitions
的数量为3,每个partitions
除了本身之外还有一个副本,如下图。
Topic:producer-0 Partition:0 Leader:2 Replicas:2,1 Isr:2,1
分析第二行,对于 partition:0
,在broker id为1,2的机器上各有一份,内容相同,这两个partition中有一个leader,然后这个leader负责对外的读写,Leader:2
表示broker id为2的机器是leader。
在上一篇文章中,生产者的配置中有个
props.put("acks","all")
的配置,将acks设置为all,表示只有所有的副本都保存了生产者发送的消息后,才表示生产者发送成功。其本质是消息被发送到leader后,其他的副本会从leader上增量复制,如果一个副本没能与leader保持同步,那么他将会从Isr列表中移除。
以上面为例,如果机器1没能及时的从机器2中同步消息,那么Isr将会只有2了。
当ack=1,表示producer写partition leader成功后,broker就返回成功,无论其他的partition follower是否写成功。
当ack=2,表示producer写partition leader和其他一个follower成功的时候,broker就返回成功,无论其他的partition follower是否写成功。
如果ack=1的时候,一旦有个broker宕机导致partition的follower和leader切换,会导致丢数据
kafka消息传输的3种语义
(1)At most once 消息可能会丢,绝对不会重复传输;
(2)At least once 消息绝对不会丢,但是可能会重复传输;
(3)Exactly once 每条信息肯定会被传输一次且仅传输一次,这是用户想要的。
at most once
消费者fetch消息,然后保存offset,然后处理消息;当client保存offset之后,但是在消息处理过程中consumer进程失效(crash),导致部分消息未能继续处理.那么此后可能其他consumer会接管,但是因为offset已经提前保存,那么新的consumer将不能fetch到offset之前的消息(尽管它们尚没有被处理),这就是”at most once”.at least once
消费者fetch消息,然后处理消息,然后保存offset.如果消息处理成功之后,但是在保存offset阶段zookeeper异常或者consumer失效,导致保存offset操作未能执行成功,这就导致接下来再次fetch时可能获得上次已经处理过的消息,这就是”at least once”.Exactly once
“Kafka Cluster”到消费者的场景中可以采取以下方案来得到“恰好1次”的一致性语义:
最少1次+消费者的输出中额外增加已处理消息最大编号:由于已处理消息最大编号的存在,不会出现重复处理消息的情况。
在实际应用中其实也很好实现,只需要保证消费接口的幂等性即可。比如,你收到一条订单号为101的付款成功的消息,此时你会将订单状态更新为已付款状态,由于At least once的存在,你可能再次收到这条消息,此时你只需要查询数据库中订单的状态,如果已经付款了,那么这条消息可以忽略掉。所以很多时候,从业务层面上,其实是很容易实现Exactly once。
有一篇非常好的kafka文章: https://blog.csdn.net/ychenfeng/article/details/74980531