如何保证Kafka有且仅消费一次?

Kafka的几个核心的概念:

Producer:生产message发送到topic
Consumer:订阅topic消费message,Consumer作为一个线程来进行消费
Consumer Group:一个Consumer Group包含多个Consumer,这个预先在配置文件中配置
Broker:一个Kafka节点就是一个Broker,多个Broker组成Kafka集群
Topic:一类消息,不同类的消息会对应不同的topic,也就是消息存放的目录(主题),Kafka集群能够同时对多个topic进行分发
Partition:topic物理上的分组,一个topic可以有多个partition,每个partition是一个有序队列,topic是逻辑上的概念,partition是物理上真实存在的
Segment:Partition物理上是由多个Segment组成,每个Segment存放着message信息

发生场景举例:
每个message写入到partition中都有一个offset,当consumer消费message后,隔一段时间会将消费过的offset提交一下(比如提交给zookeeper),代表已经消费过了,下次要是继续消费或者重启就会从去读取提交的最新的offset,从上次消费的offset继续消费,但是如果程序出现故障,consumer消费了但还没来得及提交给zookeeper保存,那么下次再次消费时就有可能造成少量数据被重复消费。

解决方案:
通过三个方面来体现
<1>、幂等producer:保证单个分区只发送一次,不会出现重复消息,即kafka发送相同数据,broker端不会重复写入,只能保证单个分区,如果实现多个分区原子性,就要引入下面的事务性了
<2>、事务transation:保证原子性的写入多个分区,也就是写入多个分区要么都成功,要么都回滚
<3>、流式EOS:EOS保证整个操作是原子性,注意,只使用Kafka Streams
具体配置:
<1>、幂等:在producer程序中设置属性enabled.idempotence=true,但不要设置transational_id,注意是不要设置,而不是设置为空字符串。
<2>、事务:在producer程序中设置transational_id为指定的字符串(可以认为是事务的名称,自己起名字),同时设置enabled.idempotence=true。
<3>、EOS:在Kafka Streams程序中设置processing.guarantee=exactly_once

你可能感兴趣的:(Kafka)