零拷贝、page cache、顺序写、分区、分段与索引、批量处理、压缩

Topic 和分区多

阿里云中间件团队测试过,在一个 topic 八个分区的情况下,超过 64 个 topic 之后,Kafka 性能就开始下降了。

段文件

每一个分区都对应多个段文件,放在同一个目录下。Kafka 根据 topic 和分区就可以确定消息存储在哪个目录内。每个段文件的文件名就是偏移量,假设为 N,那么这个文件第一条消息的偏移量就是 N+1。所以 Kafka 根据偏移量和文件名进行二分查找,就能确定消息在哪个文件里。

高性能原因

image.png

## 高性能 Kafka
- 前置知识
  - 分段和索引
    - 基本概念
      - 一个 topic 有多个分区(在 Kafka 上,不同分区就是不同的目录,内部放着消息)
      - 每个分区有多个段(segment)文件
      - 每个段文件有两个索引文件
        - 偏移量索引文件
        - 时间戳索引文件
        - 这两个都要放入内存
    - 查找步骤
      - 根据 topic 和分区确定对应的目录
      - 根据偏移量确定文件:二分查找
      - 查找索引文件
        - 如果恰好有这个索引项,直接读对应位置的数据
        - 如果没有这个索引项,就找到最接近目标偏移量索引项吗,向后遍历
  - 零拷贝
    - 零拷贝是指 CPU 参与的拷贝次数为 0
    - 传统 IO
      - 步骤
        - 从磁盘读到内核读缓存
        - 内核读缓存拷贝到应用缓存
        - 应用缓存拷贝到内核写缓存
        - 写缓存拷贝到 NIC 缓存
      - 要点
        - 2 次 CPU 拷贝、2 次 DMA 拷贝、4 次用户态与内核态切换
    - 零拷贝 IO
      - 步骤
        - 1. 从磁盘读到内核缓存
        - 2. 内核缓存拷贝到 NIC 缓存
      - 要点
        - 0 次 CPU 拷贝、2 次 DMA 拷贝、2 次上线文切换
  - 批量处理
    - 非批量处理(N 个请求)
      - N 次系统调用、N * 2 次用户态与内核态切换、N 次网络传输开销
    - 批处理
      - 1 次系统调用、2 次用户态与内核态切换、1 次网络传输开销
- 面试思路
  - 零拷贝
    - Kafka 用的是 send_file
  - page cache
    - 注意写入语义
  - 顺序写
    - WAL,类似的技术还有 AOF
  - 分区
    - 分区过多的问题——忽略分区、合并 topic
    - 缩小并发粒度,提升性能
  - 分段和索引
    - 基本概念、查找过程
  - 批量处理
    - 高性能原因、兜底技术
  - 压缩
    - 注意是端到端的压缩

优化

image.png

## Kafka 性能优化
- 前置知识
  - 压缩算法选择
    - 压缩比
    - 压缩速率(影响吞吐量)
    - 呈反比
  - swap 交换区
    - 追求性能的都要避免交换
- 优化措施
  - 优化生产者
    - 优化 acks:追求消息不丢失的不能用
    - 优化批次:适当调大,但不是越大越好
    - 优化缓冲池
      - 解决缓冲池溢出生产者阻塞问题
    - 优化压缩
      - 启用压缩
      - 更换压缩算法
  - 优化 broker
    - 优化 swap
    - 优化网络读写缓冲
      - `net.core.rmem_default`
      - `net.core.wmem_default`
      - `net.core.rmem_max`
      - `net.core.wmem_max`
      - `net.ipv4.tcp_wmem`
      - `net.ipv4.tcp_rmem`
    - 优化磁盘 IO
      - 使用 XFS:性能好
      - 禁用 atime
    - 优化主从同步
      - `num.replica.fetchers`
      - `replica.fetch.min.bytes`
      - `replica.fetch.max.bytes`
      - `replica.fetch.wait.max.ms`
    - 优化 JVM
  - 优化消费者
    - 解决消息积压
- 中间件优化思路
  - 优化操作系统参数
    - 优化内存、网络 IO、磁盘 IO
  - 优化本身参数
  - 优化 JVM
  - 优化客户端

文件系统XFS

文件系统

除了选择合适的磁盘硬件设备和使用RAID外,文件系统是性能影响的另一个重要因素。有很多中文件系统可供选择,不过对于本地文件系统来说,EXT4(第四代可扩展文件系统)和XFS最为常见。近来,XFS称为很多Linux发行版默认的文件系统,因为它只需要做少量的调优即就可以承担大部分的工作负荷,比EXT4具有更好的表现。EXT4也可以做得很好,但需要做更多的调优,存在较大的风险。其中包括设置设置更长的时间间隔(默认是5)一边降低刷新的频率。EXT4还引入了块分配延迟,一旦系统崩溃,更容易造成数据的丢失和文件系统损坏。XFS也使用分配延迟算法,不过比EXT4的要安全些。

XFS为Kafka提供了更好的性能,除了有文件系统提供的自动优化之外,无需额外的调优。批量写入具有更高的效率,可以提升整体的I/O吞吐量。换句话说,这种性能的提升主要影响的是Kafka的写入能力。根据官网的测试报告,使用XFS的写入时间大约是160ms,而使用Ext4大约是250ms。因此生产环境中最好使用XFS文件系统。

不管使用哪一种文件系统来存储日志片段,最好要对挂在点的noatime参数进行合理的设置。文件元数据包括三个时间戳:创建时间(ctime),最后修改时间(mtime)以及最后访问时间(atime)。默认情况下,每次文件被读取后,都会更新atime,这会导致大量的磁盘读写操作,而且atime属性用处不大,除非某些应用程序想要某个文件在最后一次修改后有没有访问过(这种情况可以使用retime)。Kafka用不到该属性,所以完全可以把它禁用掉。为挂载点设置noatime参数可以防止更新atime,但不会影响ctime和mtime。

对于XFS用户而言,推荐设置largeio参数,该参数将影响stat调用返回的I/O大小。对于大数据量的磁盘写入操作而言,它能够提升一定的性能。largeio是标准的mount属性,故可使用与nobh相同的方式设置。

资料

https://www.cnblogs.com/yinzhengjie/p/9993719.html