跳到主要内容

Kafka

Kafka高性能原理

发送消息高性能:

  • 批量发送消息:Kafka采用批量发送的方式,通过将多条消息按照分区进行分组,然后每次发送一个消息集合,从而大大减少了网络传输的负载。
  • 消息压缩:消息压缩的目的是为了进一步减少网络传输带宽。对多条消息进行压缩,能大幅减少数据量。
  • 内存池复用:消息都会先写入 Producer 的内存中进行缓冲,直到多条消息组成了一个 Batch,才会通过网络把 Batch 发给 Broker。 Producer 会占用一个固定大小的内存块(默认:32MB),然后将它划分成多个小内存块(默认:16KB)。 当需要创建一个新的 Batch 时,直接从内存池中取出一个内存块即可,然后往里面不断写入消息,接着将 Batch 发送给 Broker ,此时该内存块就可以还回到缓冲池中继续复用了,根本不涉及垃圾回收。

持久化高性能:

  • 分区:每个 Topic 都包含一个或多个 Partition,不同 Partition 可位于不同节点,因此可以充分利用集群优势,实现机器间的并行处理。即使多个 Partition 位于同一个节点,也可通过配置让同一节点上的不同 Partition 置于不同的 disk drive 上,从而实现磁盘间的并行处理,充分发挥多磁盘的优势。
  • 顺序读写:Kafka 的整个设计中,Partition 相当于一个非常长的数组,而 Broker 接收到的所有消息顺序写入这个大数组中。同时 Consumer 通过 Offset 顺序消费这些数据,并且不删除已经消费的数据,从而避免了随机写磁盘的过程。
  • Page Cache:利用了操作系统本身的缓存技术,在读写磁盘日志文件时,其实操作的都是内存,然后由操作系统决定什么时候将 Page Cache 里的数据真正刷入磁盘。使用页缓存还避免了GC。 Page Cache 缓存的是最近会被使用的磁盘数据,利用的是「时间局部性」原理,依据是:最近访问的数据很可能接下来再访问到。而预读到 Page Cache 中的磁盘数据,又利用了「空间局部性」原理,依据是:数据往往是连续访问的。 而 Kafka 作为消息队列,消息先是顺序写入,而且立马又会被消费者读取到,无疑非常契合上述两条局部性原理。

消费消息高性能:

  • 基于索引文件的查询:Kafka通过索引文件提高对磁盘上消息的查询效率。索引文件映射偏移量到文件的物理位置,它不会对每条消息都建立索引,所以是稀疏的。偏移量是有序的,查询指定的偏移量时,使用二分查找可以快速确定偏移量的位置。
  • mmap:稀疏索引可以通过内存映射方式,将整个索引文件都放入内存,加快偏移量的查询。
  • 零拷贝:零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷贝次数,减少用户应用程序地址空间和操作系统内核地址空间之间因为上下文切换而带来的开销,从而有效地提高数据传输效率。
  • 批量拉取:消息者批量拉取消息,每次拉取一个消息集合,从而大大减少了网络传输的负载。

零拷贝原理

传统IO操作:

传统IO操作

  • 用户应用进程调用read函数,向操作系统发起IO调用, 上下文从用户态转为内核态(切换1)
  • DMA控制器把数据从磁盘中,读取到内核缓冲区。
  • CPU把内核缓冲区数据,拷贝到用户应用缓冲区, 上下文从内核态转为用户态(切换2),read函数返回
  • 用户应用进程通过write函数,发起IO调用, 上下文从用户态转为内核态(切换3)
  • CPU将用户缓冲区中的数据,拷贝到socket缓冲区
  • DMA控制器把数据从socket缓冲区,拷贝到网卡设备, 上下文从内核态切换回用户态(切换4),write函数返回

sendfile实现的零拷贝:

sendfile

  • 用户进程发起sendfile系统调用, 上下文(切换1)从用户态转向内核态
  • DMA控制器,把数据从硬盘中拷贝到内核缓冲区。
  • CPU将读缓冲区中数据拷贝到socket缓冲区
  • DMA控制器,异步把数据从socket缓冲区拷贝到网卡,
  • 上下文(切换2)从内核态切换回用户态,sendfile调用返回。

参考:

Kafka如何保证消息不丢失

Kafka的分区分配策略

Kafka重平衡过程

Kafka的副本同步机制

Kafka集群选主

Kafka的缓冲池机制