深入理解kafka

1. kafka架构

在这里插入图片描述
1)Producer :消息生产者,就是向 kafka broker 发消息的客户端;
2)Consumer :消息消费者,向 kafka broker 取消息的客户端;
3)Consumer Group (CG):消费者组,由多个 consumer 组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
4)Broker :一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker可以容纳多个 topic。
5)Topic :可以理解为一个队列,生产者和消费者面向的都是一个 topic;
6)Partition:为了实现扩展性,一个非常大的 topic 可以分布到多个broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列;
7)Replica:副本,为保证集群中的某个节点发生故障时,该节点上的 partition 数据不丢失且 kafka 仍然能够继续工作,kafka 提供了副本机制,一个 topic 的每个分区都有若干个副本,一个 leader 和若干个 follower。
8)leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是 leader。
9)follower:每个分区多个副本中的“从”,实时从 leader 中同步数据,保持和 leader 数据的同步。leader 发生故障时,某个 follower 会成为新的 leader。

在这里插入图片描述

  • Kafka 中消息是以 topic 进行分类的,生产者生产消息,消费者消费消息,都是面向 topic的。topic 是逻辑上的概念,而 partition 是物理上的概念,每个partition 对应于一个 log 文件,该 log 文件中存储的就是 producer 生产的数据。Producer 生产的数据会被不断追加到该log 文件末端,且每条数据都有自己的 offset。消费者组中的每个消费者,都会实时记录自己消费到了哪个 offset,以便出错恢复时,从上次的位置继续消费。

  • 由于生产者生产的消息会不断追加到 log 文件末尾,为防止 log 文件过大导致数据定位效率低下,Kafka 采取了分片和索引机制,将每个 partition 分为多个segment。每个 segment对应两个文件——“.index”文件和“.log”文件。这些文位于一个文件夹下,该文件夹的命名规则为:topic 名称+分区序号。例如,first 这个 topic 有三个分区,则其对应的文件夹为 first-0,first-1,first-2。

00000000000000000000.index
00000000000000000000.log
00000000000000170410.index
00000000000000170410.log
00000000000000239430.index
00000000000000239430.log

2. ISR:副本同步队列

为保证 producer 发送的数据,能可靠的发送到指定的 topic,topic 的每个partition 收到producer 发送的数据后,都需要向 producer 发送ack(acknowledgement 确认收到),如果producer 收到 ack,就会进行下一轮的发送,否则重新发送数据。
在这里插入图片描述

2.1. 副本数据同步策略

全部同步完成才发送ack

2.2. ISR

设想以下情景:leader 收到数据,所有 follower 都开始同步数据,但有一个 follower,因为某种故障,迟迟不能与 leader 进行同步,那 leader 就要一直等下去,直到它完成同步,才能发送 ack。这个问题怎么解决呢?

Leader 维护了一个动态的 in-sync replica set (ISR),意为和 leader 保持同步的 follower 集合。当 ISR 中的 follower 完成数据的同步之后,leader 就会给 follower 发送 ack。如果 follower长时间 未 向 leader 同 步 数 据 , 则 该 follower 将 被 踢 出 ISR , 该 时 间 阈 值 由replica.lag.time.max.ms 参数设定。Leader 发生故障之后,就会从 ISR 中选举新的 leader。

3. 什么是AR、OSR、ISR、HW和LEO以及之间的关系

  1. 分区中的所有副本统称为AR(Assigned Replicas)。
  2. 所有与leader副本保持一定程度同步的副本(包括leader副本在内)组成ISR(In-Sync Replicas),ISR集合是AR集合中的一个子集。
  3. 与leader副本同步滞后过多的副本(不包括leader副本)组成OSR(Out-of-Sync Replicas)

3.1. ISR 与 OSR 转换、ISR集合中的副本才允许选举为leader

leader副本负责维护和跟踪ISR集合中所有follower副本的滞后状态,当follower副本落后太多或失效时,leader副本会把它从ISR集合中剔除。如果OSR集合中有follower副本“追上”了leader副本,那么leader副本会把它从OSR集合转移至ISR集合。默认情况下,当leader副本发生故障时,只有在ISR集合中的副本才有资格被选举为新的leader,而在OSR集合中的副本则没有任何机会(不过这个原则也可以通过修改相应的参数配置来改变)。ISR与HW和LEO也有紧密的关系。

3.2. HW(高水位)和LEO(最后一个偏移量)

HW是High Watermark的缩写,俗称高水位
为了更好地理解ISR集合,以及HW和LEO之间的关系,下面通过一个简单的示例来进行相关的说明。如图所示,假设某个分区的ISR集合中有3个副本,即一个leader副本和2个follower副本,此时分区的LEO和HW都为3。消息3和消息4从生产者发出之后会被先存入leader副本
在这里插入图片描述
注意:只有在HW之前的数据,才是对consume可见的
当leader挂掉后,选取新的leader,其余follower会从水位处切开,再补齐和leader一样,保证了数据的一致性,但是数据可能会重复
在这里插入图片描述
如何解决数据重复问题?
将服务器的 ACK 级别设置为-1,可以保证 Producer 到 Server 之间不会丢失数据,即 AtLeast Once(至少发送一次) 语义,保证数据不会丢失,不能保证数据不重复。
相对的,将服务器 ACK 级别设置为 0,可以保证生产者每条消息只会被发送一次,即 At Most Once 语义,保证数据不重复,但是数据可能会丢失。

4. kafka消费者

  1. consumer 采用 pull(拉)模式从 broker 中读取数据。
    push(推)模式很难适应消费速率不同的消费者,因为消息发送速率是由 broker 决定的。
  2. pull 模式不足之处是,如果 kafka 没有数据,消费者可能会陷入循环中,一直返回空数据。针对这一点,Kafka 的消费者在消费数据时会传入一个时长参数 timeout,如果当前没有数据可供消费,consumer 会等待一段时间之后再返回,这段时长即为 timeout。

4.1. 分区分配策略

4.1.1. RoundRobin(轮巡)

在这里插入图片描述
在这里插入图片描述
但是这样会有一个问题,当一个消费者组消费多个topic的时候,那么该如何分配呢?
答:把多个topic当成一个topic,用TopicAndPartition类处理其中的分区,获取这几个分区的Hash值,形成一个新的列表,以那个列表为准,来进行轮巡。

  • 好处:每一个消费者的分区数的差距都很小
  • 坏处:我们来看看以下情况,当A消费者的订阅和B消费者的订阅不一样的时候
    在这里插入图片描述
    这种情况轮巡分配就会出问题了,有可能把T3分配给了A,把T1分配给了B
4.1.2. Range(默认策略)

好处:按照单个主题分配
在这里插入图片描述
在这里插入图片描述
问题:会造成消费者消费的分区数不对等的情况。

5. kafka特点

  1. 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic
  2. 可以分多个partition, consumer group 对partition进行consume操作。
  3. 可扩展性:kafka集群支持热扩展
  4. 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
  5. 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
  6. 高并发:支持数千个客户端同时读写

6. kafka数据积压

Kafka消息积压的典型场景:

  1. 实时/消费任务挂掉
    比如,我们写的实时应用因为某种原因挂掉了,并且这个任务没有被监控程序监控发现通知相关负责人,负责人又没有写自动拉起任务的脚本进行重启。
    那么在我们重新启动这个实时应用进行消费之前,这段时间的消息就会被滞后处理,如果数据量很大,可就不是简单重启应用直接消费就能解决的。

  2. Kafka分区数设置的不合理(太少)和消费者"消费能力"不足
    Kafka单分区生产消息的速度qps通常很高,如果消费者因为某些原因(比如受业务逻辑复杂度影响,消费时间会有所不同),就会出现消费滞后的情况。
    此外,Kafka分区数是Kafka并行度调优的最小单元,如果Kafka分区数设置的太少,会影响Kafka consumer消费的吞吐量。

  3. Kafka消息的key不均匀,导致分区间数据不均衡
    在使用Kafka producer消息时,可以为消息指定key,但是要求key要均匀,否则会出现Kafka分区间数据不均衡。

那么,针对上述的情况,有什么好的办法处理数据积压呢?
一般情况下,针对性的解决办法有以下几种:

  1. 实时/消费任务挂掉导致的消费滞后

a.任务重新启动后直接消费最新的消息,对于"滞后"的历史数据采用离线程序进行"补漏"。
此外,建议将任务纳入监控体系,当任务出现问题时,及时通知相关负责人处理。当然任务重启脚本也是要有的,还要求实时框架异常处理能力要强,避免数据不规范导致的不能重新拉起任务。

b.任务启动从上次提交offset处开始消费处理
如果积压的数据量很大,需要增加任务的处理能力,比如增加资源,让任务能尽可能的快速消费处理,并赶上消费最新的消息

  1. Kafka分区少了

如果数据量很大,合理的增加Kafka分区数是关键。如果利用的是Spark流和Kafka direct approach方式,也可以对KafkaRDD进行repartition重分区,增加并行度处理。

3 .由于Kafka消息key设置的不合理,导致分区数据不均衡

可以在Kafka producer处,给key加随机后缀,使其均衡。

7. kafka高吞吐低延迟是如何实现的

  1. 顺序读写
      Kafka将消息记录持久化到本地磁盘中,实际上不管是内存还是磁盘,快或慢关键在于寻址的方式,磁盘分为顺序读写与随机读写,内存也一样分为顺序读写与随机读写。基于磁盘的随机读写确实很慢,但磁盘的顺序读写性能却很高。
  2. Page Cache
      为了优化读写性能,Kafka利用了操作系统本身的Page Cache,即利用操作系统自身的内存而不是JVM空间内存。这样做的好处有:
  1. 避免Object消耗:如果是使用 Java 堆,Java对象的内存消耗比较大,通常是所存储数据的两倍甚至更多
  2. 避免GC问题:随着JVM中数据不断增多,垃圾回收将会变得复杂与缓慢,使用系统缓存就不会存在GC问题
  1. 零拷贝
      Linux操作系统 “零拷贝” 机制使用了sendfile方法, 允许操作系统将数据从Page Cache 直接发送到网络,只需要最后一步的copy操作将数据复制到 NIC 缓冲区, 这样避免重新复制数据 。
  2. 分区分段+索引
      Kafka的message是按topic分类存储的,topic中的数据又是按照一个一个的partition即分区存储到不同broker节点。每个partition对应了操作系统上的一个文件夹,partition实际上又是按照segment分段存储的。符合分布式系统分区分桶的设计思想。
      通过这种分区分段的设计,Kafka的message消息实际上是分布式存储在一个一个小的segment中的,每次文件操作也是直接操作的segment。为了进一步的查询优化,Kafka又默认为分段后的数据文件建立了索引文件,就是文件系统上的.index文件。这种分区分段+索引的设计,不仅提升了数据读取的效率,同时也提高了数据操作的并行度。
  3. 批量读写
      Kafka数据读写是批量的而不是单条的。在向Kafka写入数据时,可以启用批次写入,这样可以避免在网络上频繁传输单个消息带来的延迟和带宽开销。假设网络带宽为10MB/S,一次性传输10MB的消息比传输1KB的消息10000万次显然要快得多。
  4. 批量压缩
    Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO损耗,提高I/O速度

8. kafka精准一次性

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

kafka幂等性实现
究其原因,Kafka加入了以下两个标记值:

PID,在Producer初始化时分配,作为每个Producer会话的唯一标识;
序列号(sequence number),Producer发送的每条消息(更准确地说是每一个消息批次,即ProducerBatch)都会带有此序列号,从0开始单调递增。Broker根据它来判断写入的消息是否可接受。
Broker会为每个TopicPartition组合维护PID和序列号。对每条接收到的消息,都会检查它的序列号是否比Broker所维护的值严格+1,只有这样才是合法的,其他情况都会丢弃。

9. kafka为什么高吞吐低延迟

  1. 顺序读写:众所周知Kafka是将消息记录持久化到本地磁盘中的,磁盘分为顺序读写与随机读写,。基于磁盘的随机读写确实很慢,但磁盘的顺序读写性能却很高。
  2. Page Cache:Kafka利用了操作系统本身的Page Cache,就是利用操作系统自身的内存而不是JVM空间内存。这样做的好处有:
    避免Object消耗:如果是使用 Java 堆,Java对象的内存消耗比较大,通常是所存储数据的两倍甚至更多。
    避免GC问题:随着JVM中数据不断增多,垃圾回收将会变得复杂与缓慢,使用系统缓存就不会存在GC问题。
  3. 零拷贝:linux操作系统 “零拷贝” 机制使用了sendfile方法, 允许操作系统将数据从Page Cache 直接发送到网络,只需要最后一步的copy操作将数据复制到 NIC 缓冲区, 这样避免重新复制数据 。
  4. Kafka的message是按topic分类存储的,topic中的数据又是按照一个一个的partition即分区存储到不同broker节点。每个partition对应了操作系统上的一个文件夹,partition实际上又是按照segment分段存储的。这也非常符合分布式系统分区分桶的设计思想。
    通过这种分区分段的设计,Kafka的message消息实际上是分布式存储在一个一个小的segment中的,每次文件操作也是直接操作的segment。为了进一步的查询优化,Kafka又默认为分段后的数据文件建立了索引文件,就是文件系统上的.index文件。这种分区分段+索引的设计,不仅提升了数据读取的效率,同时也提高了数据操作的并行度。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若能绽放光丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值