概述

  • at most once模式
    基本思想是保证每一条消息commit成功之后,再进行消费处理;

    设置自动提交为false,接收到消息之后,首先commit,然后再进行消费

  • at least once模式

    基本思想是保证每一条消息处理成功之后,再进行commit;

    设置自动提交为false;消息处理成功之后,手动进行commit;

  • exactly once模式

    核心思想是发送端数据发送成功,并且成功的消息只发送一次(重复的数据被服务器拒绝掉);消费端再进行at most once模式消费。

消费者的三种模式是从消费者角度衡量次数的。但是其实现却依赖生产者,因为生产者可能发送丢失数据或发送重复数据的情况:

  • at most once(消费者最多收到一次消息,0--1次)

    特点:不会重复发送,可能消息丢失 ,acks = 0 可以实现。

    acks=0 保证producer往leader只发送一次,不管是否发送成功,因此可能丢数据,但不会重复发送

  • at least once(消费者至少收到一次消息,1--多次)

    特点:会重复发送,消息不会丢失,ack = all 或-1可以实现。

  • exactly once(消费者刚好收到一次消息)

    特点:不会重复发送,消息不会丢失,at least once 加上消费者幂等性可以实现,还可以用kafka生产者的幂等性来实现。

回顾ack配置

当producer向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别:

  • 1(默认):这意味着producer在ISR中的leader已成功收到的数据并得到确认后发送下一条message。如果leader宕机了,则会丢失数据。可能丢数据,但可能重复数据。最无用,2个缺点都占到了,因此,不会用到该模式来解决本文的主题。

  • 0:这意味着producer无需等待来自broker的确认而继续发送下一批消息。这种情况下数据传输效率最高,但是数据可靠性确是最低的。可能丢数据,不会重复发送

    因为0模式下,重试机制失效。

  • -1或all:producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。但是这样也不能保证数据不丢失,比如当ISR中只有leader时,这样就变成了acks=1的情况。 不丢数据,但可能重复数据。

开启失败重试,可能导致发送重复数据。

幂等性

幂等性:是指producer无论向broker发送了多少条重复的消息,broker只会持久化一条。

因为发送端重试导致的消息重复发送问题,kafka的幂等性可以保证重复发送的消息只接收一次,只需在生产者加上参数 props.put(“enable.idempotence”, true) 即可,默认是false,表示不开启

具体实现原理是,kafka每次发送消息会生成PID和Sequence Number,并将这两个属性一起发送给broker,broker会将PID和Sequence Number跟消息绑定一起存起来,下次如果生产者重发相同消息,broker会检查PID和Sequence Number,如果相同不会再接收。

PID:每个新的 Producer 在初始化的时候会被分配一个唯一的 PID,这个PID 对用户完全是透明的。生产者如果重启则会生成新的PID。
Sequence Number:对于每个 PID,该 Producer 发送到每个 Partition 的数据都有对应的序列号,这些序列号是从0开始单调递增的。

kafka中幂等性存在的问题

幂等性只解决了当前的会话且当前的分区的幂等性。跨分区、会话不能实现精准一次性投递写入。

当producer重启后,broker分配的PID(producer_id)会发生变化。切换分区后,Patition也发生了变化。最终导致<PID,Patition,SeqNumber>作为主键的key也会发生变化。

参考

Kafka 0.11.0.0 是如何实现 Exactly-once 语义的

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐