kafka源码阅读-【1、概念介绍】

1、kafka介绍

kafka是一种分布式,发布/订阅消息系统,基于Scala语言实现。为什么使用Scala语言?传言是作者刚好在学习Scala,所以才使用Scala。kafka具有快速可扩展可持久化等特点。kafka最初由LinkedIn开发,并于2011年初开源,2012年从Apache孵化器毕业,成为Apache基金会顶级项目。随着时间发展,越来越多公司的大型分布式系统支持与kafka集成,例如:Apache StormSpark等等,也有越来越多的公司基于kafka建立起近乎实时的信息处理平台,例如:LinkedInNetfixUberVerizon。在国内也有很多互联网公司在生产环境使用kafka作为其消息中间件。

kafka之所以收到大家的追捧主要有以下几个原因:

  • kafka具有几乎实时性的消息处理能力,即使面对海量数据也能高效的存储消息和查询消息。kafka将消息保存在磁盘,通过顺序读写的方式,提高了磁盘的访问能力。
  • kafka支持批量处理消息,同时也支持批量的消息压缩,无论是生产者消费者服务端,都能批量处理消息,而不是一个一个消息处理,这样能有效的提高kafka本身的吞吐量,同时也提高了压缩效率。
  • kafka支持消息分区,每个分区中保证消息的顺序传递,不同的分区之间是独立的,可以达到负载均衡的效果,也能提高kafka的吞吐量。
  • kafka支持在线增加分区,支持在线水平扩展。
  • kafka支持为每个分区创建多个副本,其中只有一个Leader副本负责与客户端独写,其它副本只负责与Leader副本进行同步,这种方式提高了数据的容灾能力。kafka会将Leader副本均匀的分布在集群中的服务器上面,实现容灾性能最大化

总而言之,kafka基本上具备了:高性能高容灾能力高吞吐量近实时性数据持久化同分区顺序保证异步通信,等等特点,同时嫩在微服务盛行的年代,kafka能让服务与服务之间解耦合,从而实现系统间的高内聚低耦合。

2、核心概念

下面开始介绍kafka有关的基本概念

2.1、消息

消息是kafka基本数据单元。消息由一串字节构成,其中主要由keyvalue构成,key和value也都是byte数组。key的主要作用是根据一定策略,将此消息路由到指定的分区中,这样就可以保证包含同一key的消息全部写入同一个分区中,key可以是null。消息的真正有效负载是value部分的数据。为了提高网络的存储的利用率,生产者会批量发送消息到kafka,并在发送之前对消息进行压缩,具体的细节在本书后面的章节会详细介绍。
如下图所示:
在这里插入图片描述

2.2、Topic 与 Log

Topic是用于划分消息所属的逻辑概念,是一种消息体的集合,可以类比表结构中的表。每个Topic可以有多个生产者向其推送消息(Push),也可以有多个消费者消息其消息,如下图所示:
在这里插入图片描述

  • 每个Topic可以划分多个分区(partition),同一个Topic下的不同分区包含的消息是不同的。每个消息在被添加到分区时,都会被分配一个offset,它是消息在此分区中的唯一编号,kafka通过offset保证消息在分区内的顺序,offset的顺序性不跨分区,即kafka只能保证在同一个分区底下的消息是有序的;同一个topic底下的不同分区并不能保证其顺序性。

  • 同一个Topic的不同分区会分配在不同的Broker上面(下面会介绍)。分区是kafka水平扩展的基础,我们可以通过增加服务器的partition来进行横向扩展,来提高kafka的吞吐量。

  • 分区在逻辑上对应着一个Log,生产者将消息写入分区的时候,其实是先写入分区对应的Log。Log是一个逻辑概念,每个Log都对应着磁盘上的一个文件夹。Log由多个Segment组成,每个Segment对应着一个日志文件索引文件。在面对海量数据的时候,为了避免出现超大文件,会对日志文件进行切分,当数据大小超过文件最大大小,会生成一个新的Segment继续提供写入操作。

  • 此外因为kafka是顺序IO,所以只向着最新的Segment写入数据。为了权衡文件大小,索引速度、占用内存大小等多方面因素,索引文件采用稀疏索引的方式,占用内存不大,可以将索引缓存在内存中,以便提高效率。

2.3、保留策略 与 日志压缩

无论消费者是否已经消费了消息,kafka都会一直保存着这些消息,但并不会像数据库那样长期持久化。为了避免磁盘被沾满,kafka会配置相应的保留策略,以实现周期性的删除历史消息。 kafka有两种保留策略:按照消息保留时间按照Topic数据大小

  • 按照消息保留时间,当消息在kafka中保存的时间超时其指定的时间限制时,就会被后台线程删除。
  • 按照Topic数据大小,当Topic所占的日志文件大小大于一个阈值的时候,则后台线程会从最旧的消息开始删除。

这两种策略配置也比较灵活,可以全局配置也可以部分Topic进行配置。

此外kafka还会进行日志压缩,主要是针对消息的value进行压缩,当开启kafka的日志压缩功能,kafka会在后台开启一个线程,定期将相同key的消息进行合并,只保留最新的值(我个人理解为幂等处理),但是近期正在发送的消息,并不会被合并,因为后台线程来不及。

2.4、Broker 与 副本

  • broker 是一个单独的kafka 服务端就是一个broker。broker主要任务就是接收生产者发送过来的消息,分配offset,之后保存到磁盘上;同时,接收消费者,以及其它broker的请求,根据请求类型进行相应的处理后返回响应。在一般的生产环境中,一个Broker独占一台物理机器。

  • 副本 是kafka对消息进行了冗余,每个partition可以有多个副本,每个副本中包含的消息是一样的 (前提是offset不超过HW)。每个分区至少有一个副本,当分区中只有一个副本的时候,只有Leader副本,没有Follower副本。此外每个副本集合中,都会选择出一个副本作为Leader,kafka在不同的情况下会选择不同的选举策略。当前客户端请求到该partition都由Leader副本进行处理响应,Follower负责同步Leader,如下图所示:
    在这里插入图片描述

2.5、ISR集合

ISR集合表示的是目前可用的消息量与Leader相差不多的可用副本集合,这是整个副本集合的子集。要符合属于ISR集合的副本需要满足两个条件:

  • 副本所在节点必须维持着和Zookeeper的连接。
  • 副本最后一条消息的offset与lLeader副本的最后一条消息的offset之间的差值不能超过阈值。

ISR集合由每个partitionLeader来维护。所有的请求会统一发送到Leader副本处理,然后Follower会从Leader上拉取消息,整个过程是是有延迟的,所以会出现Follower上的offset略少于Leader,但只要没超过阈值都是可以接受的。但是如果其中某一台机器发生了动荡,比如掉线或者GC等等,必然会导致消息差距拉大,甚至超过阈值,这个时候Leader会将该Follower机器踢出ISR集合。往后,如果该Follower恢复状态,并且成功同步消息并且追上Leader,这个时候Leader会将其重新纳入ISR集合中,通过利用ISR集合的逻辑,巧妙中和了同步复制异步复制的特点。

  • 同步复制 由于所有副本都需要同步复制,如果出现一个副本宕机了,会导致整个副本集群被拖垮
  • 异步复制 虽然异步复制不会导致副本集群被拖垮的情况,但是如果Follower全部都没有跟上Leader此时,Leader宕机必然也会导致消息丢失的情况。

2.6、HW 与 LEO

  • HW(俗称高水位)和LEO以及上面提到的ISR集合密切相关。HW标记了一个特殊的offset,当消费者消费消息的时候,只能拉取到不大于HW的offset的消息,HW之后的消息对消费者不可见。同样HW也是由Leader副本管理的。当ISR集合中全部的Follower副本都拉取到HW当前指定的消息后,Leader副本才会递增HW的值,kafka官方称这种方式为commit,其含义是消息在多个副本中存在,当Leader遭到损坏的时候也不会出现数据丢失。

  • LEO(Log End Offset)是每个副本都会有的一个offset标记,它标记的是当前副本的最后一个消息的offset。当有生产者生产消息的时候,LEO标记会递增,同时当Follower同步到来自Leader的消息的时候LEO也会递增。
    下图是一个描述HW和LEO关系的示意图:
    在这里插入图片描述

2.7、Cluster 与 Controller

多个Broker可以做成 一个Cluster集群对外提供服务,每个Cluster当中会选举出一个Broker来担任Controller,Controller是kafka集群的指挥中心,而其它Broker则听从Controller的调度实现相应的功能。Controller负责管理集群的:分区中副本的状态监听zookeeper变化选举等工作。Controller是一主多从的结构,所有的Broker都会监听Controller Leader的状态,当Leader Controller出现故障的时候,会重新选举Controller Leader。

2.8、生产者

生产者,想必很多人都熟悉,(Producer)其主要工作是负责生产消息,并将消息按照一定的规则发送(push)到Topic的分区上,(自定义partition策略)。生产者可以更具自己的需要去实现或者选择消息的分区方式。

2.9、消费者 与 消费者组

  • 消费者(Consumer)的主要工作是从Topice(pull)拉取消息,并对消息进行消费。某个消费者消费到parttion的哪个位置的相关信息,是Consumer自己维护的,此外通过pull的方式可以避免消费者被消息压垮的情况。

  • 消费者组(Consumer Group)是由多个消费者同时组成的一个组集合,一个Consumer只能同时存在一个组内,在消费组内,Topic的分区(partition)会根据当前组的消费者情况,进行一个分配,让每一个消费者都能消费属于自己的一个或者多个组。在组内,一个消息只能被一个消费者消费,但是在组与组之间,一条消息会被多个组的一个消费者消费到,通过这种方式,可以很灵活的切换为广播,和点对点的方式进行消息消费。如下图所示 (官方图片)
    在这里插入图片描述
    (图中的p0,p1,p2,p3来源同一个topic的不同分区)

  • 重平衡(rebalance)从上图中也可以看出,kafka消费者组的消费者数量是可变化的,当有2个消费者和4个消费者,每个消费者消费的分区和其数量也是不一样的,为了达到这一状态,kafka内部有机制进行分区 分配 (后面的文章会详细介绍),当然消费者的数量也不是一成不变的,可能会出现消费者的上线或者下线。每当发生消费者数量变化,或者topic分区变化 *(增加partition)*的时候,原有的分配结果会被打破,需要为每个消费者重新分配分区,其中这个过程就是 重平衡

3、总结

本篇文章介绍了kafka的一些基本概念,同时也简单介绍了为什么kafka会有那么高的吞吐量,同时为后面的文章做铺垫。那么整体来说kafka的可以用如下几个官网的图片来阐述。

首先,kafka的Topic是多分区的(横向拓展),每个分区的不同副本为了高可用,分配在不同的broker机器上面,如下图:
在这里插入图片描述
其次,生产者通过其自身的分区策略,将消息发送到不同的分区(实现了Topic的横向拓展):
在这里插入图片描述
最后每个consumer group通过分配策略,让其consumer消费其中的一个或者几个分区,并且分配策略会随着消费者数量的变化而变化:
在这里插入图片描述
后面的文章也会陆续到来

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章