消息队列学习笔记————kafka原理分析

一、kafka是什么

Kafka是LinkedIn公司开发的一款分布式消息发布和订阅系统,它的特点是高性能、高吞量。kafka一开始设计的目标就是作为一个分布式、高吞吐量的消息系统,所以也适合运用在大数据传输场景。
由于kafka具有更好的吞吐量、内置分区、冗余及容错性的优点(kafka每秒可以处理几十万消息),让kafka成为了一个很好的大规模消息处理应用的解决方案,一般用在用户行为跟踪、日志收集等场景。

二、kafka的架构构成

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

名词解释
(1)broker
Kafka集群包含一个或多个服务器,这种服务器被称为broker。broker端不维护数据的消费状态,提升了性能。直接使用磁盘进行存储,线性读写,速度快:避免了数据在JVM内存和系统内存之间的复制,减少耗性能的创建对象和垃圾回收。
(2)Producer
生产者,负责生产(发布)消息到broker上。
(3)Consumer
消费者,负责消费broker中的消息。Consumer通过拉取(pull)的方式从broker上获得消息
(4)Topic
主题。可以理解为kafka上的消息的类别。物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上,但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处。
(5)Partition
分区,相同Topic的消息应该存在相同的文件上,但是当消息数量过多,文件太大会影响读取的效率,所以kafka在实际存储消息时使用了Partition,每个Topic包含一个或多个Partition,同一Topic下的不同分区包含的消息是不同的。Partition是在物理上的划分,每个Partition在物理上对应一个文件夹,该文件夹下存储这个Partition的所有消息和索引文件。
(6)Consumer Group
消费者组,每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)
(7)offset
偏移量,每个消息在被添加到分区时,都会被分配一个offset。它是消息在此分区中的唯一编号,kafka通过offset保证消息在分区内的顺序,offset的顺序不跨分区,即kafka只保证在同一个分区内的消息是有序的。
(8)zookeeper
kafka使用了zookeeper来做master选举以及数据的维护。

三、消息的分发与消费

1、kafka消息分发策略

消息是kafka中最基本的数据单元,在kafka中,一条消息由key、value两部分构成,在发送一条消息时,我们可以指定这个key,那么producer会根据key和partition机制来判断当前这条消息应该发送并存储到哪个partition中。我们可以根据需要进行扩展producer的partition机制。
默认情况下,kafka采用的是hash取模的分区算法。如果Key为null,则会随机分配一个分区。随机值根据参数”metadata.max.age.ms”设置的时间周期性变化。默认是每十分钟更新一次。在参数设置的时间范围内,随机值不会变化。

2、kafka消息消费策略

在实际生产过程中,每个topic都会有多个partitions,多个partitions的好处在于,一方面能够对broker上的数据进行分片有效减少了消息的容量从而提升io性能。另外一方面,为了提高消费端的消费能力,一般会通过多个consumer去消费同一个topic ,也就是消费端的负载均衡机制。
kafka的consumer group(组)就是用在多个consumer消费同一个topic的场景。通过设置相同的group.id将多个consumer加入到同一个group中,组内的所有消费者协调在一起来消费订阅主题的所有分区。在同一个group内,每一个分区只能由一个consumer来消费,而一个consumer可以消费多个分区。
所以一个Topic的partition的数量应该比消费它的group的consumer数量多。因为为kafka的设计是在一个partition上是不允许并发的,所以consumer数不要大于partition数,否则会造成资源浪费。
如果consumer从多个partition读到数据,不保证数据间的顺序性,kafka只保证在一个partition上数据是有序的,但多个partition,根据你读的顺序会有不同。

3、consumer的rebalance(平衡)策略

当consumer,broker,partition的数量发生变化时(新增consumer、主动停机或者宕机、Topic增加了分区)会触发rebalance机制,重新进行分区分配。
rebalance的策略:
(1)RangeAssignor(范围分区)
Range策略是对每个主题而言的,首先对同一个主题里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。

假设n = 分区数/消费者数量
m= 分区数%消费者数量
那么前m个消费者每个分配n+l个分区,后面的(消费者数量-m)个消费者每个分配n个分区

假设我们有10个分区,3个消费者,排完序的分区将会是0, 1, 2, 3, 4, 5, 6, 7, 8, 9;消费者线程排完序将会是C1-0, C2-0, C3-0。则n=3,m=1,那么C1-0 将消费 0, 1, 2, 3 分区,,C2-0 将消费 4, 5, 6 分区,C3-0 将消费 7, 8, 9 分区。

(2)RoundRobinAssignor(轮询分区)
轮询分区策略是把所有partition和所有consumer线程都列出来,然后按照hashcode进行排序。最后通过轮询算法分配partition给消费线程。如果所有consumer实例的订阅是相同的,那么partition会均匀分布。
(3)StrickyAssignor(叫粘滞策略)
粘滞策略主要有两个目的:分区的分配尽可能的均匀、分区的分配尽可能和上次分配保持相同。当两者发生冲突时, 第 一 个目标优先于第二个目标。

四、kafka的消息同步机制

1、副本

Kafka的每个topic都可以分为多个Partition,并且多个partition会均匀分布在集群的各个节点下。虽然这种方式能够有效的对数据进行分片,但是对于每个partition来说,都是单点的,当其中一个partition不可用的时候,那么这部分消息就没办法消费。所以kafka为了提高partition的可靠性而提供了副本的概念(Replica),通过副本机制来实现冗余备份。

每个分区可以有多个副本,并且在副本集合中会存在一个leader的副本,所有的读写请求都是由leader副本来进行处理。剩余的其他副本都做为follower副本,follower副本会从leader副本同步消息日志。这个有点类似zookeeper中leader和follower的概念,但是具体的时间方式还是有比较大的差异。所以我们可以认为,副本集会存在一主多从的关系。

一般情况下,同一个分区的多个副本会被均匀分配到集群中的不同broker上,当leader副本所在的broker出现故障后,可以重新选举新的leader副本继续对外提供服务。通过这样的副本机制来提高kafka集群的可用性。
在这里插入图片描述
需要注意的是,kafka集群中的一个broker中最多只能有一个副本,leader副本所在的broker节点的分区叫leader节点,follower副本所在的broker节点的分区叫follower节点。

2、副本的leader选举

Kafka提供了数据复制算法保证,如果leader副本所在的broker节点宕机或者出现故障,或者分区的leader节点发生故障,这时就需要用到leader选举。leader选举中的名词解释;
leader副本:响应clients端读写请求的副本
follower副本:被动地备份leader副本中的数据,不能响应clients端读写请求。
ISR集合:包含了leader副本和所有与leader副本保持同步的follower副本。
LEO:即日志末端位移(log end offset),记录了该副本底层日志(log)中下一条消息的位移值。注意是下一条消息!也就是说,如果LEO=10,那么表示该副本保存了10条消息,位移值范围是[0, 9]。另外,leader LEO和follower LEO的更新是有区别的。
HW:即上面提到的水位值。对于同一个副本对象而言,其HW值不会大于LEO值。小于等于HW值的所有消息都被认为是“已备份”的(replicated)。同理,leader副本和follower副本的HW更新是有区别的

副本协同机制
消息的读写操作都只会由leader节点来接收和处理。follower副本只负责同步数据以及当
leader副本所在的broker挂了以后,会从follower副本中选取新的leader。写请求首先由Leader副本处理,之后follower副本会从leader上拉取写入的消息,这个过程会有一定的
延迟,导致follower副本中保存的消息略少于leader副本,但是只要没有超出阈值都可以忍。但是如果一个follower副本出现异常,比如宕机、网络断开等原因长时间没有同步到消息,那这个时候,leader就会把它踢出去。kafka通过ISR集合来维护一个分区副本信息。

一个新leader被选举并被接受客户端的消息成功写入。Kafka确保从同步副本列表中选举一个副本为leader;leader负责维护和跟踪ISR(in-Sync replicas , 副本同步队列)中所有follower滞后的状态。当producer发送一条消息到broker后,leader写入消息并复制到所有follower。消息提交之后才被成功复制到所有的同步副本。

ISR包含的副本
ISR表示目前“可用且消息量与leader相差不多的副本集合,这是整个副本集合的一个子集”。具体来说,ISR集合中的副本必须满足以下条件:

  1. 副本所在节点必须维持着与zookeeper的连接
  2. 副本最后一条消息的offset与leader副本的最后一条消息的offset之间的差值不能超过指定的阈值(replica.lag.time.max.ms) replica.lag.time.max.ms:如果该follower在此时间间隔内一直没有追上过leader的所有消息,则该follower就会被剔除isr列表

Leader副本的选举过程

  1. KafkaController会监听ZooKeeper的/brokers/ids节点路径,一旦发现有broker挂了,执行下面的逻辑。这里暂时先不考虑KafkaController所在broker挂了的情况,KafkaController挂了,各个broker会重新leader选举出新的KafkaController
  2. leader副本在该broker上的分区就要重新进行leader选举,目前的选举策略是
    a) 优先从isr列表中选出第一个作为leader副本,这个叫优先副本,理想情况下有限副本就是该分区的leader副本
    b) 如果isr列表为空,则查看该topic的unclean.leader.election.enable配置。为true则代表允许选用非isr列表的副本作为leader,那么此时就意味着数据可能丢失,为 false的话,则表示不允许,直接抛出NoReplicaOnlineException异常,造成leader副本选举失败。
    c) 如果上述配置为true,则从其他副本中选出一个作为leader副本,并且isr列表只包含该leader副本。一旦选举成功,则将选举后 的leader和isr和其他副本信息写入到该分区的对应的zk路径上。

五、消息的存储以及清除策略

1、消息的存储

kafka是使用日志文件的方式来保存生产者和发送者的消息,每条消息都有一个offset值来表示它在分区中的偏移量。Kafka中存储的一般都是海量的消息数据,为了避免日志文件过大,Log并不是直接对应在一个磁盘上的日志文件,而是对应磁盘上的一个目录,这个目录的命名规则是<topic_name>_<partition_id>。

一个topic按照个partition来分开存储,每个partition是一个文件夹。包含日志文件、索引文件和时间索引文件。
在这里插入图片描述kafka是通过分段的方式将Log分为多个LogSegment,LogSegment是一个逻辑上的概念,一个LogSegment对应磁盘上的一个日志文件和一个索引文件,其中日志文件是用来记录消息的。索引文件是用来保存消息的索引。

LogSegment
假设kafka以partition为最小存储单位,那么我们可以想象当kafka producer不断发送消息,必然会引起partition文件的无限扩张,这样对于消息文件的维护以及被消费的消息的清理带来非常大的挑战,所以kafka 以segment为单位又把partition进行细分。每个partition相当于一个巨型文件被平均分配到多个大小相等的segment数据文件中(每个segment文件中的消息不一定相等),这种特性方便已经被消费的消息的清理,提高磁盘的利用率。

segment file由2大部分组成,分别为index file和data file,此2个文件一一对应,成对出现,后缀".index"和“.log”分别表示为segment索引文件、数据文件.segment文件命名规则:partion全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值进行递增。数值最大为64位long大小,20位数字字符长度,没有数字用0填充。

segment中index和log的对应关系
为了提高查找消息的性能,为每一个日志文件添加2个索引索引文件:OffsetIndex 和 TimeIndex,分别对应.index以及.timeindex, TimeIndex索引文件格式:它是映射时间戳和相对offset
在这里插入图片描述
如图所示,index中存储了索引以及物理偏移量。 log存储了消息的内容。索引文件的元数据执行对应数据文件中message的物理偏移地址。举个简单的案例来说,以[4053,80899]为例,在log文件中,对应的是第4053条记录,物理偏移量(position)为80899.

查找消息
查找的算法是

  1. 根据offset的值,查找segment段中的index索引文件。由于索引文件命名是以上一个文件的最后一个offset进行命名的,所以,使用二分查找算法能够根据offset快速定位到指定的索引文件。
  2. 找到索引文件后,根据offset进行定位,找到索引文件中的符合范围的索引。(kafka采用稀疏索引的方式来提高查找性能)
  3. 得到position以后,再到对应的log文件中,从position出开始查找offset对应的消息,将每条消息的offset与目标offset进行比较,直到找到消息

比如说,我们要查找offset=2490这条消息,那么先找到00000000000000000000.index, 然后找到[2487,49111]这个索引,再到log文件中,根据49111这个position开始查找,比较每条消息的offset是否大于等于2490。最后查找到对应的消息以后返回。

2、清除策略

日志的清理策略有两个

  1. 根据消息的保留时间,当消息在kafka中保存的时间超过了指定的时间,就会触发清理过程
  2. 根据topic存储的数据大小,当topic所占的日志文件大小大于一定的阀值,则可以开始删除最旧的消息。kafka会启动一个后台线程,定期检查是否存在可以删除的消息通过log.retention.bytes和log.retention.hours这两个参数来设置,当其中任意一个达到要求,都会执行删除。默认的保留时间是:7天。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值