【中间件】kafka

文章详细介绍了Kafka的工作原理,包括生产者的发送策略、分区机制、提高吞吐量的方法以及数据可靠性的保障;Broker的工作流程、副本管理和存储优化;消费者的工作流程、分区分配与offset管理。重点讨论了数据的分区策略和生产者如何确保数据不丢失与不重复。
摘要由CSDN通过智能技术生成

一、概述

  1. 定义:是一个分布式的基于发布/订阅模式的消息队列(MessageQueue),主要应用于大数据实时处理领域

  2. 三大功能

    • 削峰: 高峰期的消息可以积压到消息队列中,随后平滑地处理完成,避免突发访问压力压垮系统
    • 解耦: 消息队列避免模块之间的相互调用,降低各个模块的耦合性,提高系统的可扩展性
    • 异步: 发送方把消息放在消息队列中,接收方无需立即处理,可以等待合适的时间处理
  3. 基础架构:

在这里插入图片描述

组件作用
Producer消息生产者,就是向 Kafka broker 发消息的客户端
Consumer消息消费者,向 Kafka broker 取消息的客户端
Consumer Group(CG)消费者组,由多个 consumer 组成。组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。消费者组是逻辑上的一个订阅者
Broker一台 Kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个broker 可以容纳多个 topic
Topic消息主题(逻辑概念) ,生产者和消费者面向的都是一个 topic
Partition一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列
Replica副本。每个分区都有若干个副本,一个 Leader 和若干个Follower
Leader一组副本中的“主”,只有主和生产者消费者交互
Follower一组副本中的“从”,实时从 Leader 中同步数据,保持和Leader 数据的同步
SegmentPartition 物理上被分成多个 Segment,每个 Segment 1个G
Zookeeper保存元信息,现已废除

二、生产者

1. 发送原理

在这里插入图片描述

涉及到了两个线程——main 线程和 Sender 线程

  • 在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给消息队列
  • 当消息队列内的消息达到一定大小,或者达到时间限制,会通知sender线程
  • Sender 线程不断从消息队列中拉取消息发送到 Kafka Broker
    • 可以选择是异步还是同步(同步就是sender等待收到broker的ack后,再去发送新消息)

2. 生产者分区 Partition

分区好处

  1. 便于合理使用存储资源,可以把海量的数据按照分区切割成一块一块数据存储在多台Broker上。合理控制分区的任务,可以实现负载均衡的效果
  2. 提高并行度,生产者可以以分区为单位发送数据;消费者可以以分区为单位进行消费数据

分区策略

在这里插入图片描述

生产者生产消息的时候:

  1. 指明partition的情况下,直接将指明的值作为partition值;例如partition=0,所有数据写入分区0

  2. 没有指明partition值但有key的情况下,将key的hash值与topic的partition数进行取余得到partition值

    例如:key1的hash值=5, key2的hash值=6 ,topic的partition数=2,那么key1 对应的value1写入1号分区,key2对应的value2写入0号分区

  3. 既没有partition值又没有key值的情况下,Kafka采用Sticky Partition(黏性分区器),会随机选择一个分区,并尽可能一直使用该分区,待该分区的batch已满或者已完成,Kafka再随机一个分区进行使用(和上一次的分区不同)。

    例如:第一次随机选择0号分区,等0号分区当前批次满了(默认16k)或者linger.ms设置的时间到, Kafka再随机一个分区进行使用(如果还是0会继续随机)

  4. 自定义分区:定义类实现 Partitioner 接口,重写 partition()方法,方法返回分区号

3. 生产者如何提高吞吐量

  • 提高main线程创建的消息队列大小:缓存大一点
  • 提高batchsize大小:多等一些数据再传
  • 调整等待时间:双刃剑,太短一次传的消息太少,太长有延迟
  • 对传输数据做压缩:能传更多的消息

4. 数据可靠性

ACK应答级别

0:生产者发送过来的数据,不需要等数据落盘应答
1:生产者发送过来的数据,Leader收到数据后应答
-1:生产者发送过来的数据,Leader和ISR队列里面的所有节点收齐数据后应答

单纯用0或1都会导致丢数,而单纯用-1会导致多数重复

数据不丢失:ACK + ISR

ACK = -1 + 副本 >= 2 + ISR最小副本数量 >= 2

数据不重复:幂等性

  1. 数据语义

    • 最多一次:ACK = 0
    • 至少一次:ACK = -1 + 副本 >= 2 + ISR最小副本数量 >= 2
    • 精确一次:幂等性 + 至少一次
  2. 重复数据的判断标准:具有 <PID, Partition, SeqNumber> 相同主键的消息提交时,Broker只会持久化一条

    • PID是Kafka每次重启都会分配一个新的Producer ID
    • Partition 表示分区号
    • Sequence Number是单调自增的

    所以幂等性只能保证的是在单分区单会话内不重复

    全局不重复需要开启事务

数据有序

  • 生产者有序发送消息
    • 一个一个消息的发:一个 Topic 下的同一个 Partition 一定是有序的
    • 不是一个一个发:需要开启幂等性且一次发不能超过5个,这样如果乱序到达的话,broker会自己排序
  • 消费者有序消费
    • 一个分区只让一个消费者来消费,即能保证

三、broker

1. 工作流程

  1. 生产者将消息发送给分区 Leader
  2. Leader 将消息写入本地文件
  3. 对应的 Follower 从 Leader 拉取消息并写入本地文件
  4. Follower 向 Leader 发送 ACK
  5. Leader向生产者回复
  • leader的维护由保存在paitition内的Controller来做,Controller也是分布式的,他会监听brokers节点的变化,在节点挂掉的时候辅助选举新leader,选举规则:在ids列表内按顺序选择

2. 副本相关

  1. 定义:每个partition都有多份,叫副本,来提高可靠性

    • 副本分为Leader和Follower,只有Leader和生产者和消费者交互
    • 副本AR = ISR + OSR
  2. Leader 和 Follower 故障处理

    • Follower故障:被踢出ISR,恢复后再加入ISR
    • Leader故障:从ISR中选出一个新的Leader,恢复后去除旧数据,和新Leader进行同步(只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复)
  3. 副本分区分配

    尽可能的把Leader散开,否则会对某一个broker产生很大的压力

3. 底层存储

partition下进一步将数据分为Segment,每个1G

  • Segment分为

    • log:存具体数据,以追加的方式
    • index:索引,稀疏索引,4KB记一条索引
    • 时间戳:过期删除用的
      在这里插入图片描述
  • 删除方法

    • 删除:直接删除
    • 压缩:相同key只保留最新的

4. 高效读写数据

  • Kafka 本身是分布式集群,可以采用分区技术,并行度高
  • 读数据采用稀疏索引,可以快速定位要消费的数据
  • 顺序写磁盘
  • 页缓存 + 零拷贝技术
    • 页缓存PageCache:重度依赖底层操作系统提供的PageCache功能,写的时候直接交给页缓存,读的时候先读页缓存,没有再读磁盘
    • 零拷贝:消息从磁盘里读出来之后不走应用层代码,直接走网卡,不占用CPU
      在这里插入图片描述

四、消费者

1. 工作流程

在这里插入图片描述

  • 消费者可以分组,一个分区只能由组内的一个消费者消费,消费者组是逻辑上的一个订阅者
  • 用offset标识消费的位置,由消费者提交,保存在主题内,由coordinator管理,这也是个分布式

在这里插入图片描述
主要就是从broker里拉取数据

2. 分区分配和重平衡

分区分配问题:一个consumer group中有多个consumer组成,一个 topic有多个partition组成,问题是,到底由哪个consumer来消费哪个partition的数据

  • 分区分配策略

    • Range:对每个 topic 而言, partitions数/consumer数来决定,会产生数据倾斜
    • RoundRobin:针对集群中所有Topic而言,所有的 partition轮询分配
    • Sticky:尽量均匀地分配分区,根据上次的分配结果尽量减少变动

3. offset 位移

  1. 位移保存方式:存在__consumer_offsets里,采用 key 和 value 的方式存储数据。key 是 group.id+topic+分区号,value 就是当前 offset 的值

  2. 位移的提交方式

    • 自动提交(可能造成重复消费)

      重复消费:已经消费了数据,但是 offset 没提交
      比如每隔5s,下一轮过了2s挂了,会重复消费这2s的内容

    • 手动提交(可能造成漏消费)

      漏消费:先提交 offset 后消费,有可能会造成数据的漏消费
      比如消费者取了,还在内存里,刚提交还没来得及落盘就挂了,没落盘的就漏消费了

    不管是重复消费还是漏消费,都是提交和落盘的间隙出现宕机的情况,可以开启事务,把这两个动作原子绑定

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值