IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    kafka生产者的幂等和事务处理

    hyperxu发表于 2020-10-12 03:11:58
    love 0

    之前和大家聊过kafka是如何保证消息不丢失的,今天再讲讲在不丢消息的同时,如何实现精确一次处理的语义实现。

    消息组件对消息的可靠性保障,常见的模式有3种:

    • 最多一次(at most once):消息可能会丢失,但不会重复
    • 至少一次(at least once):消息不会丢失,但有可能重复
    • 精确一次(exactly once):消息不会丢失,且不会重复,精准一次发送

    kafka默认情况下,提供的是至少一次的可靠性保障。即broker保障已提交的消息的发送,但是遇上某些意外情况,如:网络抖动,超时等问题,导致Producer没有收到broker返回的数据ack,则Producer会继续重试发送消息,从而导致消息重复发送。
    相应的,如果我们禁止Producer的失败重试发送功能,消息要么写入成功,要么写入失败,但绝不会重复发送。这样就是最多一次的消息保障模式。
    但对于消息组件,排除特殊业务场景,我们追求的一定是精确一次的消息保障模式。kafka通过幂等性(Idempotence)和事务(Transaction)的机制,提供了这种精确的消息保障。

    幂等

    这里就不多说幂等的含义了,不清楚的自己查下资料。Producer默认不是幂等性的,向分区发送数据时,可能会出现同一条消息被发送多次导致消息重复的情况。但只需增加一些参数,即可开启幂等性。

    1
    2
    3
    props.put(“enable.idempotence”, ture)
    或者
    props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)

    开启enable.idempotence后,kafka就会自动帮你做好消息去重的一系列工作。底层具体实现原理很简单,就是用空间换时间的优化思路,即在broker端多存一些字段来标识数据的唯一性。当Producer发送了具有相同字段值的消息后,broker会进行匹配去重,丢弃重复的数据。实际的代码没这么简单,但大致是这么个处理逻辑。
    官方的这个幂等实现看似简单高效,但也存在他的局限性。他只能保证单分区上的幂等性,即一个幂等性Producer只能够保证某个topic的一个分区上不出现重复消息,无法实现多分区的幂等。此外,如果Producer重启,也会导致幂等重置。

    事务

    对于多分区保证幂等的场景,则需要事务特性来处理了。kafka的事务跟我们常见数据库事务概念差不多,也是提供经典的ACID,即原子性(Atomicity)、一致性 (Consistency)、隔离性 (Isolation) 和持久性 (Durability)。
    事务Producer保证消息写入分区的原子性,即这批消息要么全部写入成功,要么全失败。此外,Producer重启回来后,kafka依然保证它们发送消息的精确一次处理。
    事务特性的配置也很简单:

    • 和幂等Producer一样,开启enable.idempotence = true
    • 设置Producer端参数transctional.id

    事务Producer的代码稍微也有点不一样,需要调一些事务处理的API。数据的发送需要放在beginTransaction和commitTransaction之间。Consumer端的代码也需要加上isolation.level参数,用以处理事务提交的数据。示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    producer.initTransactions();
    try {
    producer.beginTransaction();
    producer.send(record1);
    producer.send(record2);
    producer.commitTransaction();
    } catch (KafkaException e) {
    producer.abortTransaction();
    }

    事务Producer虽然在多分区的数据处理上保证了幂等,但是处理性能上相应的是会有一些下降的。

    依赖redis实现幂等

    这里为什么还要额外讲通过依赖redis来实现幂等呢?因为笔者在早期维护kafka相关应用时,那会0.8系列版本的kafka还没有这些自带的幂等事务特性,只能依靠开发者自己来实现。
    常见的方式就是通过数据的业务属性来生成个uniqueId来维护到redis中,利用redis的高并发,高吞吐,分布式锁特性,让写入kafka多分区的数据前,先去redis中校验一下uniqueId等方式,来实现幂等。得益于redis的高性能,在保证幂等同时,还能不让消息数据吞吐性能下降太多。当然,因为redis的依赖引入,也增加了架构的复杂度,从运维上来说也增加了整体的故障点,其中取舍需要自己来全局判断。

    这次大概先介绍了下kafka的幂等各种实现方式,实际在事务,和依赖redis分布式锁来实现幂等的方式中,还要许多点值得我们深究来聊一下的,篇幅所限,后续再细讲



沪ICP备19023445号-2号
友情链接