Kafka中所有的请求都是通过 TCP 网络以 Socket 的方式进行通信的。
如何处理请求
- 顺序处理请求,吞吐量太差,只适用于请求 发送非常不频繁的系统。
- 采用异步的方式,系统会为每个入站请求都创建单独的线程来 处理。
- 不会阻塞下一个请求
- 每个请求都创建线程开销极大
- Reactor 模式
Reactor模式
Reactor 模式是事件驱动架构的一种实现方式,特别适合应用于处理多个客户端并发向服务器端发送请求的场景
- 多个客户端会发送请求给到 Reactor
- Reactor 有个请求分发线程 Dispatcher,也就是图中的 Acceptor,它会将不同的请求下发到多个工作线程中处理。
- Acceptor 线程只是用于请求分发,不涉及具体的逻辑处理,非常得轻量级,因此有很高的吞吐量表现。
- 工作线程可以根据实际业务处理需要任意增减,从而动态调节系统负载能力。
Kafka模式
- Kafka Broker 的SocketServer 组件,类似于 Reactor 模式的 Dispatcher,它也有对应的 Acceptor 线程和一个工作线程池(网络线程池)。
- Kafka 提供了 Broker 端参数 num.network.threads(默认值是 3),用于调整该网络线程池的线程数
- Acceptor 线程采用轮询的方式将入站请求公平地发到所有网络线程中,线程通常都有相同的几率被分配到待处理请求,避免了请求处理的倾斜,实现较为公平的请求处理调度。
Acceptor 线程分发到任意一个网络线程中,进行处理的过程如下
当网络线程拿到请求后,它不是自己处理,而是将请求放入到一个共享请求队列中。 Broker 端还有个 IO 线程池,负责从该队列中取出请求,执行真正的处理。
- 如果是 PRODUCE 生产请求,则将消息写入到底层的磁盘日志中;
- 如果是 FETCH 请求,则从磁盘 或页缓存中读取消息。
IO 线程池处中的线程才是执行请求逻辑的线程。
Broker 端参数num.io.threads(默认值是 8)控制了这 个线程池中的线程数。
比如,如果你的机器上 CPU 资源非常充裕,你完全可以调大该参数,允许更多的并发请求 被同时处理。
当 IO 线程处理完请求后,会将生成的响应发送到网络线程池的响应队列中, 然后由对应的网络线程负责将 Response 返还给客户端。
- 请求队列是所有网络线程共享的
- 响应队列则是每个网络线程专属的。
这么设计的原因就在于,Dispatcher 只是用于请求分发而不负责响应回传,因此只能让每个网络线程自己发送 Response 给客户端,所以这些 Response 也就没必要放在一个公共的地方。