Kafka学习笔记 --- Kafka是如何实现高吞吐率的?

Kafka的高吞吐率是一个使用起来很不错的性能,其中有如下几点原因:

一、Broker NIO异步消息处理,实现了IO线程与业务线程分离

Kafka的网络通信模型是基于NIO的Reactor多线程模型来设计的,这里先引入Kafka源码中注释。

An NIO socket server. The threading model is

1 Acceptor thread that handles new connections.

Acceptor has N Processor threads that each have their own selector and read requests from sockets.

M Handler threads that handle requests and produce responses back to the processor threads for writing.

看到代码中的注释信息可以知道,Kafka的网络通信模型,主要采用了1(1个Acceptor线程)+ N(N个Processor线程)+ M(M个业务处理线程)。

可以看出Kafka的Broker NIO异步并发处理消息,实现了IO线程异步并发处理消息的机制;大大提升的数据的吞吐量。

下面表格列举了一些:

线程数

线程名

线程具体说明

1

kafka-socket-acceptor_%x

Acceptor线程,负责监听Client端发起的请求

N

kafka-network-thread_%d

Processor线程,负责对Socket进行读写

M

kafka-request-handler-_%d

Worker线程,处理具体的业务逻辑并生成Response返回

Kafka的完整通信框架如下:

梳理一下上面的几个重要概念:

  • Acceptor: 1个接收线程,负责监听新的连接请求,同时注册OP_ACCEPT 事件,将新的连接按照“round robin”方式交给对应的Processor线程处理。

  • Processor: N个处理器线程,其中每个Processor都有自己的selector,它会向Acceptor分配的SocketChannel注册相应的OP_READ事件,N的大小由“num.networker.threads”决定;

  • KafkaRequestHandler: M个请求处理线程,包含在线程池-KafkaRequestHandlerPool内部,从RequestChannel全局请求队列RequestQueue中获取了请求数据并交给KafkaApis处理,M的大小由“num.io.threads”决定;

  • RequestChannel:其为Kafka服务端的请求通道,该数据结构包含了一个全局的请求队列RequestQueue和多个Processor处理器相对应的响应队列ResponseQueue,提供给Processor与请求处理线程kafkaRequestHandler和KafkaApis交换数据的地方。

  • NetworkClient:其底层是对Java Nio的封装,位于Kafka的网络接口层。Kafka消息生产者对象-KafkaProducer的send方法主要是调用NetWorkClient完成消息发送;

  • SocketServer:其实一个NIO的服务,他同时启动一个Acceptor接收线程和多个Processor处理线程。提供了一种典型的Reactor多线程模式,将接收客户端请求和处理请求相分离。

  • KafkaServer: 代表一个Kafka Broker的实例;其startup方法为实例启动的入口;

  • KafkaApis: kafka的业务逻辑处理Api,负责处理不同类型的请求;比如说“发送消息”、“获取消息偏移量-offset”和“处理心跳请求”等;

二、顺序读写

Kafka的消息时不断追加到文件中的,这特性使得Kafka可以充分的利用磁盘的顺序读写性能;

顺序读写不需要磁盘次头的寻道时间,只需要很少的扇区旋转时间,所以速度远快于随机读写;

Kafka的设计确实有助于实现顺序写的模式。每个topic有不同的分区,而每个分区下包含若干个只能追加写的提交日志:新消息被追加到文件的最末端。最直接的证明就是Kafka源码中只调用了FileChannel.write(ByteBuffer),

而没有调用过带offset参数的write方法,说明它不会执行随机写操作。

三、零拷贝

先了解到文件系统的操作流程,例如一个程序要把文件内容发送到网络。

这个程序是工作在用户空间,文件和网络socket属于硬件资源,两者之间有一个内核空间。

在操作系统内部,整个过程为:

在Linux kernel2.2之后出现了一种叫做“零拷贝(zero-copy)”系统调用机制,就是跳过“用户缓冲区”的拷贝,建立一个磁盘空间和内存的直接映射,数据不再复制到“用户态缓冲区”。

系统上下文切换减少为2次,可以提升一倍的性能;

四、文件分段

Kafka的队列Topic被分为多个Partition,每个Partition又分为多段segment,所以一个队列中的消息实际上是保存在N个多个片段文件中;

通过分段的方式,每次文件操作都是对一个小文件的操作,非常轻便,同时也增加了并行处理的能力;

五、批量发送

Kafka允许进行批量发送消息,先将消息缓存在内存中,然后一次请求批量发送出去比如可以指定缓存的消息达到某个量就发出去,

或者缓存了固定的时间后就发送出去,如100条消息就发送一次,或者每5秒发送一次。这种策略将大大减少服务端的I/O次数

六、数据压缩

Kafka还支持对消息集合进行压缩,Producer可以通过GZIP或Snappy格式对消息集合进行压缩,压缩的好处就是减少传输的数据量,减轻对网络传输的压力。

Producer压缩之后,在Consumer需要进行解压,虽然增加了CPU的工作,但是在大数据处理上瓶颈在网络,而不是在CPU,这个成本比较值得。

发布了1959 篇原创文章 · 获赞 696 · 访问量 360万+

猜你喜欢

转载自blog.csdn.net/u012965373/article/details/105121905