从未如此简单:10分钟带你逆袭Kafka!( 六 )

  • Consumer 可以重置 Offset , 从而可以灵活消费存储在 Broker 上的消息 。
  • ⑥Partition Leader 选举范围
    当 Leader 宕机后 , Broker Controller 会从 ISR 中挑选一个 Follower 成为新的 Leader 。
    如果 ISR 中没有其他副本怎么办?可以通过 unclean.leader.election.enable 的值来设置 Leader 选举范围 。
    False:必须等到 ISR 列表中所有的副本都活过来才进行新的选举 。 该策略可靠性有保证 , 但可用性低 。
    True:在 ISR 列表中没有副本的情况下 , 可以选择任意一个没有宕机的主机作为新的 Leader , 该策略可用性高 , 但可靠性没有保证 。
    ⑦重复消费问题的解决方案
    同一个 Consumer 重复消费:当 Consumer 由于消费能力低而引发了消费超时 , 则可能会形成重复消费 。
    在某数据刚好消费完毕 , 但是正准备提交 Offset 时候 , 消费时间超时 , 则 Broker 认为这条消息未消费成功 。 这时就会产生重复消费问题 。 其解决方案:延长 Offset 提交时间 。
    不同的 Consumer 重复消费:当 Consumer 消费了消息 , 但还没有提交 Offset 时宕机 , 则这些已经被消费过的消息会被重复消费 。 其解决方案:将自动提交改为手动提交 。
    ⑧从架构设计上解决 Kafka 重复消费的问题
    我们在设计程序的时候 , 比如考虑到网络故障等一些异常的情况 , 我们都会设置消息的重试次数 , 可能还有其他可能出现消息重复 , 那我们应该如何解决呢?下面提供三个方案:
    方案一:保存并查询
    给每个消息都设置一个独一无二的 uuid , 所有的消息 , 我们都要存一个 uuid 。
    我们在消费消息的时候 , 首先去持久化系统中查询一下看这个看是否以前消费过 , 如没有消费过 , 在进行消费 , 如果已经消费过 , 丢弃就好了 。
    下图表明了这种方案:
    方案二:利用幂等
    幂等(Idempotence)在数学上是这样定义的 , 如果一个函数 f(x) 满足:f(f(x)) = f(x) , 则函数 f(x) 满足幂等性 。
    这个概念被拓展到计算机领域 , 被用来描述一个操作、方法或者服务 。 一个幂等操作的特点是 , 其任意多次执行所产生的影响均与一次执行的影响相同 。
    一个幂等的方法 , 使用同样的参数 , 对它进行多次调用和一次调用 , 对系统产生的影响是一样的 。 所以 , 对于幂等的方法 , 不用担心重复执行会对系统造成任何改变 。
    我们举个例子来说明一下 。 在不考虑并发的情况下 , “将 X 老师的账户余额设置为 100 万元” , 执行一次后对系统的影响是 , X 老师的账户余额变成了 100 万元 。
    只要提供的参数 100 万元不变 , 那即使再执行多少次 , X 老师的账户余额始终都是 100 万元 , 不会变化 , 这个操作就是一个幂等的操作 。
    再举一个例子 , “将 X 老师的余额加 100 万元” , 这个操作它就不是幂等的 , 每执行一次 , 账户余额就会增加 100 万元 , 执行多次和执行一次对系统的影响(也就是账户的余额)是不一样的 。
    所以 , 通过这两个例子 , 我们可以想到如果系统消费消息的业务逻辑具备幂等性 , 那就不用担心消息重复的问题了 , 因为同一条消息 , 消费一次和消费多次对系统的影响是完全一样的 。 也就可以认为 , 消费多次等于消费一次 。
    那么 , 如何实现幂等操作呢?最好的方式就是 , 从业务逻辑设计上入手 , 将消费的业务逻辑设计成具备幂等性的操作 。
    但是 , 不是所有的业务都能设计成天然幂等的 , 这里就需要一些方法和技巧来实现幂等 。
    下面我们介绍一种常用的方法:利用数据库的唯一约束实现幂等 。
    例如 , 我们刚刚提到的那个不具备幂等特性的转账的例子:将 X 老师的账户余额加 100 万元 。 在这个例子中 , 我们可以通过改造业务逻辑 , 让它具备幂等性 。
    首先 , 我们可以限定 , 对于每个转账单每个账户只可以执行一次变更操作 , 在分布式系统中 , 这个限制实现的方法非常多 , 最简单的是我们在数据库中建一张转账流水表 。
    这个表有三个字段:转账单 ID、账户 ID 和变更金额 , 然后给转账单 ID 和账户 ID 这两个字段联合起来创建一个唯一约束 , 这样对于相同的转账单 ID 和账户 ID , 表里至多只能存在一条记录 。
    这样 , 我们消费消息的逻辑可以变为:“在转账流水表中增加一条转账记录 , 然后再根据转账记录 , 异步操作更新用户余额即可 。 ”
    在转账流水表增加一条转账记录这个操作中 , 由于我们在这个表中预先定义了“账户 ID 转账单 ID”的唯一约束 , 对于同一个转账单同一个账户只能插入一条记录 , 后续重复的插入操作都会失败 , 这样就实现了一个幂等的操作 。