Kafka的请求处理机制

概述

Kafka的请求处理机制是通过“请求/响应”的方式完成的,无论是客户端还是Broker端,它们之间的交互都是通过网络发送请求和接收响应来实现的。Kafka定义了一组协议来处理各种请求,例如PRODUCE请求用于生产消息、FETCH请求用于消费消息、METADATA请求用于请求Kafka集群的元数据信息

常用方法:

  1. 顺序处理请求与单独线程处理请求

    处理请求的两种简单方法是顺序处理和每个请求使用单独线程处理。顺序处理的实现较为简单,但吞吐量较差,因为每个请求都必须等待前一个请求处理完毕。单独线程处理每个请求则完全异步,虽然避免了阻塞,但线程创建的开销很大,在高频请求场景下难以承受(24丨请求是怎么被处理的?)。

  2. Reactor模式

    Kafka使用Reactor模式处理请求,这是一种事件驱动架构,特别适用于多个客户端并发请求的场景。Reactor模式通过一个请求分发线程(Dispatcher)将不同请求分发到多个工作线程处理。Acceptor线程用于请求分发,不涉及具体逻辑处理,因此非常轻量级,具有很高的吞吐量

    image-20240701232209613

Kafka的Reactor架构

image-20240701232308193

  • 网络线程池:Reactor 模式中的 Dispatcher,它也有对应的 Acceptor 线程和一个工作线程池,只不过
    在 Kafka 中,这个工作线程池有个专属的名字,叫网络线程池

    Kafka 提供了 Broker 端参数 num.network.threads,用于调整该网络线程池的线程数。其默认值是 3,表示每台Broker 启动时会创建 3 个网络线程,专门处理客户端发送的请求。

  • 共享请求队列:当网络线程拿到请求后,它不是自己处理,而是将请求放入到一个共享请求队列中

  • IO 线程池:负责从该队列中取出请求,执行真正的处理;如果是PRODUCE 生产请求,则将消息写入到底层的磁盘日志中;如果是 FETCH 请求,则从磁盘或页缓存中读取消息

    Broker 端参数num.io.threads控制了这个线程池中的线程数;目前该参数默认值是 8,表示每台 Broker 启动后自动创建 8 个 IO线程处理请求

  • 响应队列:响应队列则是每个网络线程专属的,因为要每个网络线程自己发送 Response 给客户端

  • Purgatory:这是 Kafka 中著名的“炼狱”组件。它是用来缓存延时请求(Delayed Request)的;所谓延时请求,就是那些一时未满足条件不能立刻处理的请求

    当请求不能立刻处理时,它就会暂存在 Purgatory 中;稍后一旦满足了完成条件,IO 线程会继续处理该请求,并将 Response放入对应网络线程的响应队列中

总结

Kafka的请求主要分为两大类:数据类请求和控制类请求,并且以单Reactor多工作线程的方式进行处理;以前的kafka对于所有请求都一视同仁,不难看出会存在问题,因为控制类请求可以使数据类请求失败;

基于这些问题,社区于 2.3 版本正式实现了数据类请求和控制类请求的分离;社区完全拷贝了原来的一套组件,实现了两类请求的分离,只是监听了不同的端口,进行了不同的处理