• 消息队列 随笔 5-kafka深入


    0. 我想玩玩小块儿地…

    看完这篇Kafka,你也许就会了Kafka
    SpringBoot集成kafka全面实战

    1. 分区 Paritition

    为了实现扩展性,一个非常大的Topic可以分布到多个Broker上,一个Topic可以分为多个Partition,每个Partition是一个有序的队列(分区有序,不能保证全局有序)

    1.1 分区底层关系

    Topic是逻辑上的概念,Partition是物理上的概念,每个Partition对应着一个log文件,该log文件中存储的就是producer生产的数据

    1.1.1 分区数据的持久化

    • Kafka文件存储也是通过本地落盘的方式存储的,主要是通过相应的log与index等文件保存具体的消息文件
      逻辑上,log由多个分片(segment)构成
    • 1个分片(segment)由.index、.log文件构成(分片和索引的机制快速定位大文件——二分查找)
      .index文件存储的消息的offset+真实的起始偏移量
      .log中存放的是真实的数据。

    1.2 分区 与 生产/消费

    • Producer生产的数据会被不断的追加到该log文件的末端,且每条数据都有自己的offset
    • consumer组中的每个consumer,都会实时记录自己消费到了哪个offset,以便出错恢复的时候,可以从上次的位置继续消费。

    1.3 分区内部结构

    1.3.1 Leader

    每个分区多个副本的主角色,生产者发送数据的对象,以及消费者消费数据的对象都是Leader。

    1.3.2 Follower

    每个分区多个副本的从角色,实时的从Leader中同步数据,保持和Leader数据的同步,Leader发生故障的时候,某个Follower会成为新的Leader。

    1.4 分区分配规则

    1.4.1 消息产出时的分区分配规则

    1. 由消息的生产者指定分区
    2. 上述条件不存在时,若消息有Key,则取 key的hash对分区总数 取模
    3. 上述条件不存在时,第一次调用时产生一个随机数,后续调用时在这个随机上++,然后将其对分区数取模(round-robin算法)

    1.4.2 消息被消费时的分区分配规则

    1.4.2.1 先解释一波为什么消费方式:Pull

    • kafka消费消息采用pull的方式(非push)的好处:
      不同消费者的消费速率可能不同
      push的速率由broker来决定

    • kafka缓解的pull所带来的空轮询的性能损耗:
      消费者支持传入一个timeout

    1.4.2.2 进入正题

    一个cusomer group中如何决定某条消息由哪个实例消费:

    • round robin

    请添加图片描述

    做法
    	这里并未使用随机数,而是按照分区的字典值 对 分区、消费者实例 排序
    	循环遍历,遇到自己订阅的topic则消费,否则向下轮询
    坏处
    	订阅多的消费者实例,压力大,总的说就是不均衡
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • range

    请添加图片描述

    做法:
    	topicX-PartitionY按先topic后partition的方式分配
    	如果多出1个则分配给字典值靠前的 消费者实例
    坏处
    	如果topic多的话,字典值靠前的 消费者实例 可能压力大
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 数据可靠性

    2.1 客户端提交消费

    消费者每次调用poll()方法,它总是返回由生产者写入Kafka但没有被消费者读取过的记录,我们因此可以知道哪些消息是被群组里的哪个消费者读取的。Kafka不会像JMS队列那样需要得到消费者的确认,消费者使用broker里的MetaData来追踪消息在分区里的位置(offset)

    提交方式:自动提交、手动提交(又分为 同步、异步)

    2.1.1 自动提交

    定时

    2.1.2 手动提交

    2.1.2.1 同步方式

    2.1.2.2 异步方式

    相比 同步 多了一个 回调方法

    但二者都可能出现 漏消费、重复消费(由rebalance引起):
        提交offset后消费,有可能造成数据的漏消费,而先消费再提交offset,有可能会造成数据的重复消费

    2.1.3 rebalance

    2.1.3.1 什么是 rebalance

    • 当有新的消费者加入消费者组、已有的消费者退出消费者组或者订阅的主体分区发生了变化,会触发分区的重新分配操作,重新分配的过程称为Rebalance。

    • 消费者发生Rebalace之后,每个消费者消费的分区就会发生变化,因此消费者需要先获取到重新分配到的分区,并且定位到每个分区最近提交的offset位置继续消费。(High Water高水位)

    2.1.3.2 如何解决 rebalance 问题

    • rebalance发生前回调 -> 先将offset提交
    • rebalance发生之后回调 -> 找到最新的offset位置继续消费即可

    2.1.4 消费者保存offset的方式

    • Kafka0.9版本之前,offset存储在zookeeper中,0.9版本及之后的版本,默认将offset存储在Kafka的一个内置的topic中(_consumer_offsets),以便故障恢复后继续消费。除此之外,Kafka还可以选择自定义存储offset数据。offse的维护相当繁琐,因为需要考虑到消费者的rebalance过程

    • 消费者会向_consumer_offset的特殊主题发送消息,消息里包含每个分区的offset。如果消费者一直处于运行状态,offset就没什么用处,用处体现在发生rebalance的时候

    2.2 生产者

    2.2.1 生产者动态ISR(in-sync replica set,副本集同步策略)

    “动态” 指的是:
    follower长时间没有向leader同步数据,则将其从ISR中踢出

    2.2.2 生产者的ack

    对于某些不太重要的数据,对数据的可靠性要求不是很高,能够容忍数据的少量丢失,所以没有必要等到ISR中所有的follower全部接受成功。

    kafka 提供了 三种级别的 ack

    0 	
    	producer不等待broker的ack,这一操作提供了最低的延迟,broker接收到还没有写入磁盘就已经返回,当broker故障时有可能丢失数据
    1
    	producer等待broker的ack,partition的leader落盘成功后返回ack,如果在follower同步成功之前leader故障,那么将丢失数据。(只是leader落盘)
    -1
    	producer等待broker的ack,partition的leader和ISR的follower全部落盘成功才返回ack,但是如果在follower同步完成后,broker发送ack之前,如果leader发生故障,会造成数据重复。(这里的数据重复是因为没有收到,所以继续重发导致的数据重复)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3. 数据一致性

    3.1 副本集中leader与followers的一致性

    3.1.1 引入的概念

    • LEO(Log End Offset):每个副本末端的偏移量
    • HW(High Watermark):高水位,指代消费者能见到的最大的offset,ISR队列中最小的LEO。

    请添加图片描述

    3.1.2 如果解决follower和leader故障

    • follower故障:
    1. 踢出ISR
    2. follower恢复
    3. follower截掉故障前HW后面的部分
    4. follower重新同步leader
    5. follower追上leader后,再次加入到ISR

    • leader故障:
    1. ISR的followers中重新选举出一个新的leader
    2. 其余follower将各自log中HW后面的部分截掉
    3. 截掉后,重新向新的leader同步

    这些个做法只能保证副本间的数据一致性,无法保证数据 不漏 或 不重

    3.1.3 ExactlyOnce:解决不漏、不重的问题

    At least Once:生产者ack=-1
    at most once:生产者ack=0

    3.1.3.1 具体实现方案

    借组 kafka-v0.11引入 幂等性:

    • 需要手动开启
    • 将去重的操作放到了上游做(给生产者分配一个PID,对PDI&Partition&SeqNumber去重)
    • 配合 at least once的语义,可以做到 exactly once

    4. 高性能读写

    • Kafka的producer生产数据,需要写入到log文件中,写的过程是追加到文件末端,顺序写的方式

    • 底层借助 零拷贝技术

    5. Zookeeper的作用

    Kafka集群中有一个broker会被选举为Controller,Controller的工作管理是依赖于zookeeper的:

    1. 负责管理集群broker的上下线
    2. 所有topic的分区副本分配和leader的选举等工作。

    请添加图片描述

    6. 事务

    kafka从0.11版本开始引入了事务支持,事务可以保证Kafka在Exactly Once语义的基础上,生产和消费可以跨分区的会话,要么全部成功,要么全部失败。

    6.1 Producer事务

    为了按跨分区跨会话的事务,需要引入一个全局唯一的Transaction ID,并将Producer获得的PID(可以理解为Producer ID)和Transaction ID进行绑定,这样当Producer重启之后就可以通过正在进行的Transaction ID获得原来的PID。

    为了管理Transaction,Kafka引入了一个新的组件Transaction Coordinator,Producer就是通过有和Transaction Coordinator交互获得Transaction ID对应的任务状态,Transaction Coordinator还负责将事务信息写入内部的一个Topic中,这样即使整个服务重启,由于事务状态得到保存,进行中的事务状态可以恢复,从而继续进行。

    6.2 Consumer事务

    对于Consumer而言,事务的保证相比Producer相对较弱,尤其是无法保证Commit的信息被精确消费,这是由于Consumer可以通过offset访问任意信息,而且不同的Segment File声明周期不同,同一事务的消息可能会出现重启后被删除的情况。

    7. API生产者流程

    Kafka的Producer发送消息采用的是异步发送的方式,在消息发送的过程中,设计到了两个线程main线程和Sender线程,以及一个线程共享变量RecordAccumulator,main线程将消息发送给RecordAccumulator,Sender线程不断从RecordAccumulator中拉取消息发送到Kafka broker中。


    就是一个buff:

    请添加图片描述

  • 相关阅读:
    10、内网安全-横向移动&域控提权&NetLogon&ADCS&PAC&KDC&永恒之蓝
    【0143】 System V共享内存(Shared Memory)
    自动化抢票 12306
    2023.10.03
    玩转DIY可视化打造专属小程序
    数据分析与Excel
    目标检测算法——工业缺陷数据集汇总2(附下载链接)
    OpenSees学习心得:RC框架的时程分析【一】
    MySQL 执行计划参数
    学会这些Jmeter插件,才能设计出复杂性能测试场景
  • 原文地址:https://blog.csdn.net/weixin_43638238/article/details/126276164