Kafka之Borker的基本模块

1. SocketServer

SocketServer主要包括:
(1)Acceptor:主要用于监听socket连接
(2)Processor:主要用于转发Socket的请求和响应
(3)RequestChannel:主要用于缓存Socket的请求和响应

1.1 Acceptor的初始化过程:

(1)开启socket服务
(2)注册Accept事件
(3)监听此ServerChannel上的ACCEPT事件,当其发生时,将以轮询的方式把对应的SocketChannel转交给Processor处理线程

1.2 Processor的初始化过程:

(1)当有新的SocketChannel对象进来的时候,注册其上的OP_READ事件以便接收客户端的请求
(2)从RequestChannel中的响应队列获取对应客户端请求的响应,然后产生OP_WRITE事件。
(3)监听selector上的事件。
如果是读事件,说明有新的request到来,需要转移给RequestChannel的请求队列;
如果是写事件,说明之前的request已经处理完毕,需要从RequestChannel的响应队列中获取响应并发送回客户端;
如果是关闭事件,说明客户端已经关闭了该Socket连接,此时服务端也应该释放响应的资源。

1.3 RequestChannel

RequestChannel内部包含1个Request阻塞队列和numProcessors(默认为3个)个Response阻塞队列。

Processor线程通过监听OP_READ事件将Request转移到RequestChannel内部的Request阻塞队列。KafKaRequestHandlerPool内部的KafkaRequestHandler线程从RequestChannel内部的Request阻塞队列中取出Request进行处理,然后将对应的Response放回至RequestChannel内部的Response阻塞队列,并触发Processor线程监听的OP_WRITE事件,最后由Processor线程将Response发送至客户端。

2 KafkaRequestHandlerPool

本质就是一个线程池。

KafkaRequestHandlerPool在内部启动了若干KafkaRequestHandler处理线程,并将RequestChannel对象和KafkaApis对象传递给了KafkaRequestHandler处理线程,应为KafkaRequestHandler需要从前者的requestQueue中取出Request,并且要利用后者完成具体的业务逻辑。

KafkaRequestHandler的主要步骤如下:
(1)调用requestChannel.receiveReuqest从RequestChannel的Request阻塞队列中获取请求,如果获取不到,则一直在while循环中不断尝试,直至获取到新的请求为止。
(2)判断请求的类型:
如果是RequestChannel.AllDone类型的话,则退出线程;
否则调用apis完成请求的处理,并由apis负责将对应的响应放入reqeustChannel的Response阻塞队列

因此,SocketServer的Processor线程和KafkaRequestHandlerPool的KafkaRequestHandler线程利用SocketServer 的RequestChannel实现了一个简单的生产者消费者模型。

3 KafkaApis

KafkaApis负责具体的业务逻辑。

KafkaApis主要依赖以下四个组建完成具体的业务逻辑:
(1)LogManager:日志的读取和写入
(2)ReplicaManager:Topic的分区副本的同步功能
(3)OffsetManager:便宜量的管理功能
(4)KafkaScheduler:定时任务的调度和管理功能

3.1 LogManager

3.1.1 Kafka的日志组成

LogManager利用logs来管理Broker Server内部的日志。
private val logs = new Pool[TopicAndPartition,log]()
通过TopicAndPartition来索引不同Topic的不同Patition数据。

Log利用segments来管理Partition数据,里面包含多个日志段,即LogSegment。

3.1.2 Kafka的消息读取

(1)根据startOffset定位位于哪个LogSegment。segments的数据结构为ConcurrentSkipListMap(是跳表数据机构)
(2)读数据
<1> 通过startOffset找到位于log中的具体的物理位置,以字节为单位
<1.1> 通过二分法找到小于等于startOffset的最近索引记录位置
<1.2> 打开log文件,返回真实的物理偏移量
<2> 组装offset元数据信息
<3> 如果设置了maxOffset,则根据其具体值计算实际需要读取的字节数
<4> 通过FileMessageSet提供的指定物理便宜量和长度的read方法读取相应的数据

3.1.3 LogManager的启动

(1)初始化logs
Broker Server的每个日志目录下都有一个recovery-point-offset-checkpoint文件。这个文件记录了该目录下所有日志文件的状态,即TopicAndPartition和Offset的对应关系。通过这个文件来初始化logs,也就是PoolTopicAndPartition,Log对象。

(2)开启后台定时任务和维护线程
<1> cleanupLogs:负责删除过时的和冗余的数据
删除数据的最小单位是LogSegment。Kafka通过配置时间和大小来实现消息的循环覆盖功能。
<2> flushDirtyLogs:定时刷新脏数据,刷新数据的最小单位是LogSegment(LogSegment里面包含数据文件和索引文件)
<3>checkpointRecoveryPointOffsets:定时刷新logs包含的元数据至recovery-point-offset-checkpoint文件,即TopicAndPartition和偏移量。

3.2 ReplicaManager

AR(Assign Repicas):已经分配给Patition的副本
ISR(In-Sync Replicas):处于同步状态的副本

ReplicaFetcherThread(数据副本拉取线程)是位于Broker Server上的线程。单个ReplicaFetcherThread只负责某个Broker Server上的部分TopicAndPartition的Replica的同步,单个ReplicaFetcherThread不会负责跨多个Broker Server上的TopicAndPartition的Replica同步。

HighWatermark(高水位线):本质上代表的是ISR中所有replicas的last commited message的最小起始便宜量,即在这偏移之前的数据都被ISR中的replicas接收,但是在这偏移之后的数据被ISR中的部分replicas所接收。

becomeLeaderOrFollower处理流程

当Broker Server被分配Replica的时候,该Replica有可能成为Leader状态的Replica或者Follower的状态的Replica,也有可能发生两者之间的切换,此时就会进入becomeLeaderOrFollower处理流程。

(1)判断request的时效性,如果request的内部时钟小于当前的时钟,则这条request就已经过时了。
(2)如果当前的leader时钟小于请求的leader时钟,则说明当前的状态是有效的
(3) 筛选出Broker Server上即将成为Leader 的Replica
(4) 筛选出该Broker Server上即将成为Follower 的Replica
(5) 进入成为Leader的流程;
进入成为Follwer的流程;
(6) 开启highwatermark-checkpoint线程,该线程负责将HighWatermark刷新
(7) 关闭空闲的Fetch线程。

makeLeaders:成为Leader的流程
(1) 如果是leader的话,删除针对该Replica的Fetch请求
(2) 尝试生成AR(assign replicas)的结构化信息,不存在则生成,存在则获取
(3) 删除已经不存在的Replica
(4) 初始化Leader状态的Replica的LogOffsetMetadata;
初始化Follower状态的Replica的LogOffsetMetadata;
(5) 初始化Leader状态的Replica的和Watermark

makeFollowers:

发布了306 篇原创文章 · 获赞 46 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/kaikai_sk/article/details/90344697
今日推荐