kafka是如何做到百万级高并发低迟延的?

2020-05-22 00:00:00 客户端 线程 请求 逻辑 响应

Kafka是高吞吐低延迟的高并发、高性能的消息中间件,在大数据领域有极为广泛的运用。配置良好的Kafka集群甚至可以做到每秒几十万、上百万的超高并发写入。Kafka到底是如何做到这么高的吞吐量和性能的呢?我们今天来走进kafka的server端探究一下它的Reactor高并发网络模型机制。

1.1、Kafka Reactor模型架构

Kafka客户端和服务端通信采取的是NIO的reactor模式,它是一种事件驱动模式。那么一个常见的单线程Reactor模式下,NIO线程的职责都有哪些呢?我们整理了如下几点:

1、作为NIO服务端,接收客户端的TCP连接;

2、作为NIO客户端,向服务端发起TCP连接;

3、读取通信对端的请求或者应答消息;

4、向通信对端发送消息请求或者应答消息;

以上四点对应的一个Reactor模式的架构图如下:

对于一些小容量的业务场景,这种单线程的模式基本够用。但是对于高负载、大并发的应用场景却并不适合,主要原因如下:

性能问题1:一个NIO线程同时处理数十万甚至百万级的链路性能是无法支撑的

性能问题2:如果超时发生重试会加重服务端处理负荷,导致大量处理积压

可靠性问题:单个线程出现故障,整个系统无法使用,造成单点故障

所以一个高并发的处理服务需要对以上架构进行优化改造,例如处理采取多线程模式,将接收线程尽量简化,相当于将接收线程作为一个接入层。那么我们回到主题kafka的reactor模式架构是怎样的?

在上面这个kafka的架构图中可以看出,它包含以下几个流程:

  • 客户端请求NIO的连接器Acceptor,同时它还具备事件的转发功能,转发到Processor处理
  • 服务端网络事件处理器Processor
  • 请求队列RequestChannel,存储了所有待处理的请求信息
  • 请求处理线程池(RequestHandler Pool)作为守护线程轮训RequestChannel的请求处理信息,并将其转发给API层对应的处理器处理
  • API层处理器将请求处理完成之后放入到Response Queue中,并由Processor从Response Queue取出发送到对应的Client端

需要注意的一点是虽然Broker层包含多个Acceptor,但是kafka的reactor模式里面还是单线程Acceptor多线程handler的模式,这里的多个Acceptor是针对一个服务器下多网卡场景的,每个EndPoint就是一个网卡它对应于一个ip和port的组合,而每个Endpoint只有一个Acceptor。

1.1、Kafka Reactor模型源码详解

按照上面架构图阐述的几个流程,它分别对应着kafka里面的事件接收、处理、响应等几个阶段,我们下面从具体实现这几个阶段的源码层面来分析。

1.2.1、SocketServer

SocketServer是一个标准的NIO服务端实现,它主要包含以下变量:

  • RequestChannel:Processor和KafkaRequestHandler 之间数据交换的队列
  • Processors:processor的容器,存放的是processor的id和processor对象的映射
  • Acceptors:acceptor的容器,存放的是EndPoint和acceptor的映射
  • ConnectionQuotas:链接限制器,针对每个IP的链接数进行限制

SocketServer的启动流程如下:

部分源码如下,启动入口:

def startup(startupProcessors: Boolean = true) {
    this.synchronized {
      connectionQuotas = new ConnectionQuotas(maxConnectionsPerIp, maxConnectionsPerIpOverrides)
      createAcceptorAndProcessors(config.numNetworkThreads, config.listeners)
      if (startupProcessors) {
        startProcessors()
      }
}

相关文章