Kafka -- 处理请求
请求协议
- Kafka自定义了一组请求协议,用于实现各种各样的交互操作
- PRODUCE请求用于生产消息,FETCH请求用于消费消息,METADATA请求用于请求Kafka集群元数据信息
- Kafka 2.3总共定义了45种请求格式,所有请求都通过TCP网络以Socket的方式进行通讯
处理请求方案
顺序处理
实现简单,但吞吐量太差,只适用于请求发送非常不频繁的场景
1 | while (true) { |
单独线程处理
为每个请求都创建一个新的线程异步处理,完全异步,但开销极大,只适用于请求发送频率很低的场景
1 | while (true) { |
Reactor模式
- Reactor模式是事件驱动架构的一种实现方式,特别适合应用于处理多个客户端并发向服务器端发起请求的场景
- 多个客户端会发送请求给Reactor,Reactor有个请求分发线程Acceptor,将不同的请求下发到多个工作线程中处理
- Acceptor线程只用于请求分发,不涉及具体的逻辑处理,非常轻量级,有很高的吞吐量
- 工作线程可以根据实际业务处理需要任意增减,从而动态调节系统负载能力
Kafka
- Broker端有一个SocketServer组件,类似于Reactor模式中的Dispatcher
- 也有对应的Acceptor线程和一个工作线程池(即网络线程池,参数设置
num.network.threads
,默认值为3)
- 也有对应的Acceptor线程和一个工作线程池(即网络线程池,参数设置
- Acceptor线程采用轮询的方式将入站请求公平地发到所有网络线程中
- 实现简单,避免了请求处理的倾斜,有利于实现较为公平的请求处理调度
- 当网络线程拿到请求后,并不是自己处理,而是将请求放入到一个共享请求队列中
- Broker端还有一个IO线程池,负责从共享请求队列中取出请求,执行真正的处理
- 如果是PRODUCE请求,将消息写入到底层的磁盘日志中
- 如果是FETCH请求,则从磁盘或页缓存中读取消息
- IO线程池中的线程才是执行请求逻辑的线程,参数
num.io.threads
,默认值为8 - 当IO线程处理完请求后,会将生成的响应发送到网络线程池的响应队列中
- 然后由对应的网络线程负责将Response返回给客户端
- 请求队列是所有网络线程共享的,而响应队列是每个网络线程专属的
- Purgatory组件用于_缓存延时请求_
- 如
acks=all
的PRODUCE请求,必须等待ISR中所有副本都接收消息后才能返回- 此时处理该请求的IO线程必须等待其他Broker的写入结果,当请求不能处理时,就会暂存在Purgatory中
- 等到条件满足后,IO线程会继续处理该请求,并将Response放入对应网络线程的响应队列中
- Kafka将PRODUCE、FETCH这类请求称为数据类请求,把LeaderAndIsr、StopReplica这类请求称为控制类请求
- 在Kafka 2.3,正式实现了数据类请求和控制类请求的分离(完全拷贝一套组件,实现两类请求的分离)
参考资料
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.