消息系统系统一般有以下的语义:

  • At most once:消息可能丢失,但不会重复投递
  • At least once:消息不会丢失,但可能会重复投递
  • Exactly once:消息不丢失、不重复,会且只会被分发一次(真正想要的)

主要以 0.11 版本作为区分:

  • 0.11 版本之前保证的语义是:至少一次 (At least once)
  • 0.11 之后版本保证的语义是:恰好一次 (Exactly once)

1. 0.11 版本之前保证的语义是:至少一次 (At least once)

1.1 At least once 说明

(1)可以做到消息不丢失 --> 可以做到发送成功的消息一定可以被消费到
(2)不能做到消息不重复

发送成功的消息,表示业务逻辑认为此消息已发送成功,即send方法已执行完成

1.2 丢消息场景
  1. 异步发送端:
    a:send之后,等待发送的时候down(消息在缓冲区中),导致消息丢失
    b:send时,缓冲区已满,导致消息丢弃
  2. 同步发送端:
    a:有限的重试
    服务端Leaderdown时,因为有与zk的超时timeout,导致在timeout之后才会进行切换,如果 重试次数 * 重试间隔 < zksessiontimeout + 切换耗时,则消息会丢失
    b:ack!=-1
    ack=0的场景,不需服务端确认,发送后,Leader down,导致消息丢失
    ack=1的场景,只需要Leader确认,Leader收到消息后,未同步到Replica之前,Leaderdown,导致消息丢失
  3. 服务端:
    a:min.insync.replicas < 2 且 unclean.leader.election.enable=true
    min.insync.replicas < 2的场景下,如果副本均落后Leader,在Leaderdown时,根据脏选开关,会选择落后的副本作为新的Leader,则落后的数据会丢失
  4. 消费端:
    a:自动offset提交
    消息处理失败,但是offset也提交了,对业务来说消息丢失
    b:先手动提交offset,后处理消息
    先提交offset,后处理消息,但是处理逻辑失败,对业务来说消息丢失
1.3 不丢失数据的方法
  1. 发送端:
    a:同步发送
    b:retries=Long.MAX_VALUE
    c:acks=-1
  2. 服务端:
    a:replicationfactor=3
    b:min.insync.replicas=2
    c:unclean.leader.election.enable=false
  3. 消费端:
    a:auto.commit.enable=false
    b:仅当消息处理成功之后再提交offset
1.4 消息重复的场景
  1. 发送端:
    a:发送端重试
    发送端发送消息后,服务端实际已接收,但是客户端因为网络或其他原因未收到确认响应,再进行消息重试发送,导致消息重复
  2. 消费端:
    a:auto.commit.enable=true
    消息处理后,进行自动offset提交之前,consumer down,恢复后从上个提交点开始消费导致消息处理重复
1.5 消息不重复的方法
  1. 发送端 --> 做不到
  2. 消费端 --> 做不到

2. 0.11 之后版本保证的语义是:恰好一次 (Exactly once)

2.1 Exactly once 说明

(1)可以做到消息不丢失 --> 可以做到发送成功的消息一定可以被消费到
(2)可以做到消息不重复

2.2 数据不重复

0.11 引入 幂等生产者及事务