kafka学习笔记04-消费者

1. kafka消费者概念

1.1 消费者和消费者群组

    一个消费者可以从属于一个群组,一个群组可以有一个或多个消费者。一个群组里的消费者订阅的是同一个主题,每个消费者接收主题一部分分区的消息。假设一个主题有4个分区,如果群组里有一个消费者,那么这一个消费者负责消费4个分区里的数据,如果群组里有2个消费者,那么每个消费者消费2个分区,如果有4个消费者,那么每个消费者消费一个分区。如果消费者个数多余分区,那么有些消费者就没有分区可以读取。一般有多少个分区,就建议在群组里添加多少个消费者。

1.2 消费者群组和分区再均衡

    当新增加分区、群组里消费者数量发生变化、订阅主题数发生变化时,就会触发分区再均衡,分区的所有权从一个消费者转移到另一个消费者,这样的行为被称为再均衡。在再均衡期间,消费者无法读取消息,造成整个群组一小段时间的不可用。

    消费者通过向群组协调器的broker发送心跳来维持它们和群组的从属关系以及它们对分区的所有权关系。

    分配分区过程:

    当消费者加入一个群组时,它会向群组协调器发送一个加入群组的请求。

    第一个加入群组的消费者将成为群主,群主从协调器获取群组的成员列表,并负责给每个消费者分配分区。

    分配完毕后,群主把分配情况发送给群组协调器,群组协调器再把这些信息发送给所有消费者。每个消费者只能看到自己的分配信息。

2. 创建消费者

    和创建生产者代码类似,如下图所示:

新增的group.id,指定了消费者所属群组的名字。

3. 订阅主题

    一个消费者群组可以订阅一个或多个主题,代码如下:

    也可以使用正则表达式方式订阅相关主题,如:consumer.subscribe("test.*");

4. 轮询

    一旦消费者订阅了主题,轮询就会处理所有的细节,包括群组协调、分区再均衡、发送心跳和获取数据。代码如下所示:

consumer.poll(100):这行代码我们称消费者对kafka的轮询。

    轮询的作用:获取数据。第一次轮询时,消费者查找群组协调器,加入群组,接收分配的分区。发生心跳。因此我们要确保在2次轮询之间,尽可能快的处理读取到的数据。

    注意:在同一个群组里,不能让一个线程运行多个消费者,也无法让多个线程安全的共享一个消费者,即消费者是线程不安全的对象。最佳实践为一个消费者使用一个线程。如果一个群组里有多个消费者,那么可以使用线程池,让线程和消费者一一对应。

5. 消费者的配置

    fetch.min.bytes:消费者从服务器获取记录的最小字节数。

    fetch.max.wait.ms:消费者从服务器获取数据的等待时间,默认为500毫秒。和最小字节数参数一起,看那个条件先满足。

    max.partition.fetch.bytes:服务器从每个分区里返回给消费者的最大字节数。默认1M。

    max.poll.records:单次调用poll方法返回的记录数,可以控制在轮询里需要处理的数据量。

    session.timeout.ms:超时时间,即消费者在多长时间没有向群组协调器发送心跳,就被认为已经死亡。一般heartbeat.interval.ms心跳时间是超时时间的1/3。

    auto.offset.reset:消费者读取没有偏移量或偏移量无效时的行为表现,默认为latest,表示读取最新记录。earliest表示从起死位置读取记录。

    enable.auto.commit:是否自动提交偏移量,默认为true,auto.commit.interval.ms自动提交偏移量的频率。

    partition.assignment.strategy:分区分配给消费者的策略

    1)range:把主题的若干个连续分区分配给消费者。

        apache.kafka.clients.consumer.RangeAssignor。

    2)roundrobin:把主题的所有分区逐个分配给消费者。            

          apache.kafka.clients.consumer.RangeRobinAssignor

6. 提交和偏移量

    消费者往一个叫_consumer_offset的特殊主题发送消息,消息包含每个分区的偏移量。老版本中是提交到zookeeper中。

    如果没有发生再均衡,那么偏移量是否被提交没有影响。如果发生了再均衡,消费者需要读取每个分区最后一次提交的偏移量,然后从偏移量指定的地方继续处理。

6.1 自动提交

    enable.auto.commit参数配置为true,auto.commit.interval.ms配置自动提交频率。

    消费者每次在进行轮询时会检查是否该提交偏移量,如果是,那么就会提交从上一次轮询返回的偏移量。

    问题:假设提交频率为5S,在最近一次提交后的3S发生了再均衡,那么就有3秒的消息会被重复处理。

6.2 同步提交当前偏移量

    设置自动提交为false。让应用程序决定何时提交偏移量。使用commitSync方法提交。这个方法提交有poll方法返回的最新偏移量,提交成功立即返回。

    注意:commitSync提交的是poll方法返回的最新偏移量,所以在处理完所有记录后要确保commitSync调用成功,否则也可能会丢失消息。同步提交只要没有发生不可恢复的错误,会一直重试,直到提交成功。

6.3 异步提交

    同步提交在kafka对请求做出回应之前,应用程序会阻塞,降低了系统的性能,可以使用异步方式提交偏移量。即commitAsync方法,如下代码展示了异步提交+回调方式:

 注意:异步提交不会进行重试,可以在回调中进行错误信息和偏移量的记录。

6.4 同步和异步组合提交

    一般情况下,偶尔提交失败,不进行重试不会有太大问题,但如果发生了再均衡,则可能造成数据重复处理。因此消费者在关闭前一般会组合使用同步异步2种方式。

正常情况下使用异步方式,消费者退出轮询后使用同步方式,确保偏移量正常提交

6.5 提交特定的偏移量

    提交偏移量的频率与处理消息批次的频率是一样的,但如果想更频繁提交怎么办?同步异步方法可以传入希望提交的分区和偏移量的map。

   上述代码展示了每1000条数据提交一次偏移量。

    map的key为主题 和分区,值为最大的一个偏移量。

7. 再均衡监听器

    在消费者调用订阅 方法时,可以指定一个再均衡监听器ConsumerRebalanceListerner的实例。该实例需要实现如下2个方法:

    onPartitionsRevoked:在再均衡开始之前和消费者停止读取消息之后被调用,如果在这里提交偏移量,下一个接管分区的消费者就知道该从哪里开始读取数。

    onPartitionsAssigned:在重新分配分区之后和消费者开始读取消息之前被调用。

注意:

        在onPartitionsRevoked方法中,我们提交的是最近处理过的偏移量,而不是poll返回的最新偏移量。

        在订阅主题时,需要将在均衡器传给消费者。

8. 从特定偏移量处开始处理记录

    如果你想从分区的起始位置开始读取消息,或者直接跳到分区的末尾开始读取消息, 可以使用seekToBeginning和seekToEnd两个方法。如果想从任意偏移量处读取消息,那么可以使用seek方法。

    上述所有提交偏移量方式都有一个缺点,即数据保存成功但还未提交偏移量时,程序异常退出,那么程序重启后,也会读取到重复数据。如果能将数据保存和提交偏移量做成一个事务,就能保证消息有且只有一次被执行。因此可以将数据和偏移量提交到数据库里,利用数据库的事务解决这个问题。

    如下代码是将数据和偏移量提交到数据库,实现2者之间事务关系的伪代码。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值