kafka基础入门(三)

三. kfk的架构深入

3.4 kfk的消费者

主要研究消费者的消费方式 和 消费者组的分区分配策略

3.4.1 消费者的消费方式

  • consumer采用pull拉取的方式从broker中拉取数据.
    push, broker推送数据的方式很难适应不同的消费者, 因为不同消费者的消费速率不同.
  • pull模式的缺点是如果kfk中没有数据, 消费者可能陷入循环, 一直返回空数据.
    • 针对这一点, kfk的消费者在消费数据时会传入一个时长参数timeout, 如果当前没有数据可供消费, consumer会等待一段时间之后再返回, 这段时长即为timeout.

3.4.2 分区分配策略

  • 一个consumer group中有多个consumer, 一个topic有多个partition, 所以必然会涉及到partition的分配问题, 即确定哪个partition由哪个consumer来消费.

  • 同一个消费者组中的不同消费者, 能同时消费同一个topic, 不能同时消费同一个partition.

  • kfk有两种消费者分区分配策略: RoundRobin 和 Range(默认).

  • RoundRobin是按照组来划分的, Range是按照主题来划分的.

3.4.2.1 RoundRobin轮询
  • 1个topic, 7个partition
    • 在这里插入图片描述

  • 2个topic, 每个topic有3个partition
    • 在这里插入图片描述

    • 假设消费者组同时订阅了两个topic(如上图). 那么在kfk轮询的策略中, 会把topic1和topic2中所有的partition看做一个整体, 根据每个partition的哈希值, 将这6个partition排序, 然后再轮询分配给consumer group中的两个consumer.

    • 在API中, 每个partition都会被封装成一个TopicAndPartition对象, 使用的是这个对象的哈希值.

    • 这样做的优点是consumer group中每个consumer 分配的partition的数量的差值最多差1个, 因为是轮询嘛. 即保证了每个consumer分配到的partition数量尽可能相同.

    • 这样做的缺点是假如同一个consumer group中的consumer-a订阅了topic1和topic2, consumer-b订阅了topic2和topic3, 那么轮询策略会把topic1 topic2 topic3中所有的partition看做一个整体, 轮询分配到consumer-a和consumer-b中, 这样的话consumer-a可能分配到topic3中的partition, consumer-b可能分配到topic1中的partition. 如下图.

    • 在这里插入图片描述

    • 如果consumer-a消费topic1, consumer-b消费topic2, 那么按照轮询的分配策略, 会将topic1 topic2中的所有partition看做一个整体轮询分配到每个consumer中, 那么consumer-a可能分配到topic2中的partition, consumer-b可能分配到topic1中的partition. 如下图.

    • 在这里插入图片描述

    • 所以使用轮询的分区分配策略的前提是: 必须保证consumer group中consumer订阅的topic是相同的(可以是多个).

    • 正是由于有上述的问题, 因此kfk默认的分区分配策略是Range.

3.4.2.2 Range范围(默认)
  • 这种策略按照topic分, 而不是按照partition分.
  • 1个topic, 7个partition
    • 在这里插入图片描述

    • 按照 7/3 将partition分配到每个consumer中.

    • 这种策略的缺点是有的consumer分配的partition太多, 有的consumer分配的partition太少. 即consumer group中每个consumer分配的partition数量不均匀.

  • 2个topic, 每个topic有3个partition
    • 在这里插入图片描述

    • 随着订阅的topic越多, 不同consumer中分配的partition数差距将越大.

  • 结论
    • RoundRobin策略优点是能让consumer group中每个consumer尽量分配到相同数量的partition, 缺点是当consumer group中consumer订阅的topic不同时会出问题, 因为所有的topic会被看做一个整体.
    • Range策略的优点是RoundRobin策略的缺点, Range策略的缺点是RoundRobin策略的优点.
    • 两种策略按照实际业务场景选择, 默认Range.
3.4.2.3 什么时候会用到分区分配策略

分区策略在API中就是一个方法. 这个方法何时被调用? 即何时会触发策略的执行? 即策略的触发时机是什么时候?

  • 当consumer group中消费者个数变化时就会重新触发分区策略. 即使消费者数量增加到比分区数量还多时, 仍然会触发分区策略.

3.4.3 offset的维护

  • 由于consumer在消费过程中可能会出现断电宕机等故障, consumer恢复后, 需要从故障前的位置继续消费, 所以需要consumer实时记录自己消费到了哪个offset, 以便故障恢复后继续消费.

  • kfk0.9前偏移量保存在zk, kfk0.9开始偏移量保存在kfk.

  • 从kfk0.9开始, consumer默认将offset保存在kfk一个内置的topic中, 该topic为_consumer_offsets.

  • offset由3个部分唯一确定: consumer group + topic + partition. offset是按照consumer group保存的而不是按照consumer保存的, 这样的好处就是如果一个consumer挂了, offset不至于丢失. 如果consumer-a保存了10条msg, 这是consumer group中新加consumer-b(此时触发分区策略), 这就能保证consumer-b能从第11条msg接着消费.

  • 查看zk中维护的offset

    • 创建一个topic名为topic100, 2个partition, 每个partition都有2个副本

      /opt/kafka/kafka/bin/kafka-topics.sh --create --topic topic100 --zookeeper localhost:2181 --partitions 2 --replication-factor 2
      
    • 启动一个生产者

      /opt/kafka/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic topic100
      
    • 启动一个消费者. 使用zk存储offset.

      /opt/kafka/kafka/bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic topic100
      
    • 生产者输入 “hello”

    • 进入zk

      # 进入zk
      /opt/zookeeper/zookeeper/bin/zkCli.sh
      
      # 展示根节点. 
      
      # 根节点下面的内容, 除了zookeeper, 其他都是和kfk相关的. 其中的controller是kfk中的控制节点, 哪个broker先抢到资源, 哪个broker就是controller, 一般先启动的broker会成为controller. controller的作用和其他broker的作用相同, 只不过controller可以和zk进行交互. 
      
      # brokers下面有ids,topics,seqid. 其中ids中记录了kfk的broker-id. 只要是注册到ids中的, 都是kfk集群中的一个节点. kfk并没有组织集群, 而是zk帮kfk组织了集群; /brokers/topics记录了kfk中所有的topic. 
      
      # /consumers中存储了消费者向zk写的数据. 如下的"console-consumer-68063", 这实际上是消费者组, 以控制台的形式启动消费者, 会被默认分配到一个组, 组名就是"console-consumer-随机数". 如果使用API, 必须手动指定消费者组名, 不会自动创建. 
      
      # 消费者组中有offset, offset中有topic, topic中有分区, 获取分区中值就能得到offset的值. 
      
      [zk: localhost:2181(CONNECTED) 0] ls /
      [cluster, controller_epoch, controller, brokers, zookeeper, admin, isr_change_notification, consumers, latest_producer_id_block, config]
      
      [zk: localhost:2181(CONNECTED) 3] ls /consumers
      [console-consumer-68063, console-consumer-39547, console-consumer-47083]
      
      [zk: localhost:2181(CONNECTED) 4] ls /consumers/console-consumer-68063
      [ids, owners, offsets]
      
      [zk: localhost:2181(CONNECTED) 8] ls /consumers/console-consumer-39547/offsets
      [topic100]
      
      [zk: localhost:2181(CONNECTED) 9] ls /consumers/console-consumer-39547/offsets/topic100
      [0, 1]
      
      [zk: localhost:2181(CONNECTED) 10] get /consumers/console-consumer-39547/offsets/topic100/0
      0 # 消息偏移量 
      cZxid = 0x649
      ctime = Sat Dec 05 16:39:13 CST 2020
      mZxid = 0x649
      mtime = Sat Dec 05 16:39:13 CST 2020
      pZxid = 0x649
      cversion = 0
      dataVersion = 0
      aclVersion = 0
      ephemeralOwner = 0x0
      dataLength = 1
      numChildren = 0
      

在这里插入图片描述
在这里插入图片描述

  • 查看kfk本地维护的offset

    • 由于kfk中存储offset的主题是kfk内置的主题_consumer_offsets, 因此我们需要改一些配置才能消费这个topic中的数据.

      # 修改consumer.properties. 不除外内置的topics. 
      exclude.internal.topis=false
      
    • 读取offset

      • kfk0.11之前的版本
      • kfk0.11开始的版本

3.4.4 消费者组案例

  • 测试同一个消费者组中的消费者, 同一时刻只能有一个消费者消费.

  • 使用控制台的consumer时, 每次启动一个consumer都会分配到一个新的consumer group中, 组名随机分配. 我们可以通过修改consumer.properties文件, 将group.id修改为任意, 那么启动任意个控制台的consumer就都会在同一个consumer group中了. group.id就是组名.

3.5 kfk高效读写数据的原因

研究集群版kfk中单个节点的读写效率为什么比其他mq效率高; 研究单台kfk的读写效率为什么比单台其他mq的效率高.

  • 集群读写高效原因

    1. kfk是分布式的, 能并发读写.
    2. 顺序写磁盘. 顺序写磁盘省去了大量磁头寻址的时间.
    3. 零拷贝技术.
  • 单节点读写高效原因

    1. 顺序写磁盘. 顺序写磁盘省去了大量磁头寻址的时间.
    2. 零拷贝技术.
  • 不用零拷贝
    在这里插入图片描述

  • 使用零拷贝
    在这里插入图片描述

3.6 zk在kfk中的作用

  • kfk集群中有一个broker会被选举为controller, 负责管理集群broker的上下线, 所有topic的分区副本分配leader选举等工作. broker被选为controller的策略是抢占资源, 谁先抢到谁就是controller, 一般最先启动的broker将成为controller.
  • controller的管理工作都是依赖于zk的.
  • leader选举流程:
    在这里插入图片描述

3.7 Range策略再分析

在这里插入图片描述

  • 上述使用的策略是Range
  • 使用轮询的话, 看消费者组, 看整个组订阅了哪些topic, 然后将这些topic中的所有partition作为一个整体 进行轮询. 所以上述的情况不能使用轮询策略, 否则consumer-A可能会分配到topic2的partition.

3.8 kfk事务

3.8.1 producer事务

  • 保证跨分区跨会话级别的精准一次性.

3.8.2 consumer事务

  • 保证消费者消费的数据是只消费一次的. (这一块很少聊, 关键还是生产者那边的事务)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值