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

Kafka作为高性能消息中间件,采用NIO的Reactor模式实现高并发低延迟。本文深入解析Kafka的Reactor模型架构,包括Acceptor、Processor、RequestChannel和KafkaRequestHandler,探讨其如何处理百万级并发和优化点。
摘要由CSDN通过智能技术生成

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()
      }
}

创建Acceptor及Proccessor实现逻辑:

private def createAcceptorAndProcessors(processorsPerListener: Int,
                                          endpoints: Seq[EndPoint]): Unit = synchronized {
   

    val sendBufferSize = config.socketSendBufferBytes
    val recvBufferSize = config.socketReceiveBufferBytes
    val brokerId = config.brokerId

    endpoints.foreach {
    endpoint =>
      val listenerName = endpoint.listenerName
      val securityProtocol = endpoint.securityProtocol

      val acceptor = new Acceptor(endpoint, sendBufferSize, recvBufferSize, brokerId, connectionQuotas)
      addProcessors(acceptor, endpoint, processorsPerListener)
      KafkaThread.nonDaemon(s"kafka-socket-acceptor-$listenerName-$securityProtocol-${endpoint.por
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值