乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 消息队列与 Kafka 概述

    • 章节导读
    • 消息队列基础
    • Kafka 概述
    • Kafka 为什么快
  • 第2章 快速上手:单机环境搭建

    • 章节导读
    • 环境准备与安装
    • 快速启动
    • Topic 管理
  • 第3章 核心概念:主题、分区与日志

    • 章节导读
    • Topic
    • Partition
    • Offset
    • Segment 与存储结构
  • 第4章 生产者详解

    • 章节导读
    • Producer 概述
    • Producer 发送机制
    • Producer 分区策略
    • Producer 幂等与事务
    • Producer 配置
  • 第5章 消费者与消费组

    • 章节导读
    • Consumer 概述
    • Consumer Group 消费组
    • Consumer 分区分配策略
    • Consumer Offset 提交
    • Consumer 多线程
    • Consumer 配置
  • 第6章 Broker 与控制器

    • 章节导读
    • Broker 概述
    • Broker 配置
    • Controller
    • KRaft 共识协议
  • 第7章 副本与数据可靠性

    • 章节导读
    • 副本机制
    • ISR 与副本同步
    • Leader 选举
    • ACK 与一致性保证
    • 高水位与 Leader Epoch
  • 第8章 存储与性能优化

    • 章节导读
    • 存储架构
    • 日志清理与压缩
    • Page Cache 与零拷贝
    • Producer 性能优化
    • Consumer 性能优化
    • Broker 性能优化
  • 第9章 生产环境运维与监控

    • 章节导读
    • Topic 管理
    • Kafka 运维工具
    • 监控
    • 常见故障排查
  • 第10章 Kafka生态与面试考点

    • 章节导读
    • Kafka 生态全景
    • 面试高频 30 题

Page Cache 与零拷贝

定义与作用

Kafka 高性能的底层秘密在于两个操作系统特性:Page Cache(页缓存) 和 Zero Copy(零拷贝)。Kafka 不使用 JVM 堆缓存数据,而是将数据直接写入 OS 的 Page Cache 中,利用 sendfile 系统调用实现从磁盘到网络的高效数据传输,避免了不必要的内存拷贝。

核心原理

传统数据路径 vs Kafka 路径

链路对比:

传统零拷贝(sendfile)
DMA Copy22
CPU Copy20
上下文切换42
JVM 堆参与是(GC 压力)否

Page Cache 工作原理

Page Cache 的好处:

  • 热数据(最近写入/频繁读取)保留在内存中,读命中率高
  • 不占 JVM 堆内存,不受 GC 影响
  • 依赖 OS 管理,Kafka 代码简化

零拷贝的实际效果

场景:1GB 消息发送给 Consumer,JVM 堆 6GB

传统方式:
  - 需要将 1GB 数据读到 JVM 堆 → 触发 Full GC
  - 再从 JVM 堆拷贝到 Socket → 额外的 CPU 消耗
  - 内存带宽消耗:2GB(读+写)

零拷贝:
  - 数据不走 JVM 堆,直接 Page Cache → Socket
  - 不会触发 GC
  - 内存带宽消耗:仅页表映射开销

完整示例

示例一:验证 Page Cache 对读写的影响

场景:写入 1GB 数据后,测试 Consumer 首轮读取(冷读)和再次读取(热读)的差异。

# 1. 写满 Page Cache
bin/kafka-producer-perf-test.sh --topic cache-test --num-records 10000000 \
  --record-size 100 --throughput -1 --producer-props bootstrap.servers=localhost:9092

# 2. 清空 Page Cache(需要 root)
echo 3 | sudo tee /proc/sys/vm/drop_caches

# 3. 冷读:Consumer 从磁盘读
bin/kafka-consumer-perf-test.sh --topic cache-test --messages 10000000 \
  --bootstrap-server localhost:9092
# start.time, end.time, data.consumed.in.MB, MB.sec
# 2026-06-13 ..., ..., 953.674, 120.5  (冷读速度)

# 4. 热读:Consumer 从 Page Cache 读(不清理缓存)
bin/kafka-consumer-perf-test.sh --topic cache-test --messages 10000000 \
  --bootstrap-server localhost:9092
# 2026-06-13 ..., ..., 953.674, 850.3  (热读速度 ~7x)

示例二:监控 Page Cache 使用

# 查看 Kafka 数据目录的 Page Cache 占用
# Linux
vmtouch /data/kafka/topic-orders-0/
#           Files: 12
#     Directories: 1
#  Resident Pages: 262144/524288  4G/8G  50%
#         Elapsed: 0.012 seconds

# 或使用 fincore
fincore /data/kafka/topic-orders-0/00000000000000000000.log

# Windows
# 查看 Standby Cache / Modified Page List (PerfMon)

易错场景

易错 1:给 JVM 堆分配太多内存,排挤 Page Cache

场景:32GB 物理内存,JVM 堆 -Xmx28G。

后果:只剩 4GB 给 Page Cache。Kafka 大量数据需要从磁盘读,性能严重下降。

最佳实践:

  • JVM 堆:6GB-8GB(Kafka 对堆内存需求不大,主要是元数据和网络缓冲)
  • 剩余内存给 OS Page Cache:24GB-26GB
  • 遵循 60-70% 物理内存归 OS 的原则

易错 2:禁用 Swap 的副作用

场景:vm.swappiness=0 + 内存不够时 OOM Killer 直接杀 Kafka。

正确做法:

# /etc/sysctl.conf
vm.swappiness=1       # 极少使用 swap,但不完全禁用
vm.dirty_ratio=10     # 脏页占内存 10% 即开始写回
vm.dirty_background_ratio=5

面试高频考点

Q:Kafka 为什么不自己管理缓存(像数据库那样),而是依赖 OS Page Cache?

A:

  1. 避免双重缓存:如果 Kafka 自己做内存缓存 + OS 也有 Page Cache → 数据被缓存两次 → 浪费内存
  2. 利用顺序 I/O 的特性:Kafka 的读写模式高度顺序化,与 Page Cache 的预读(read-ahead)机制天然契合
  3. 简化堆管理:Kafka 是 JVM 应用,大量数据放堆会导致 GC 暂停。Page Cache 不占堆内存
  4. OS 比自己更懂磁盘:Page Cache 的淘汰策略(LRU)、脏页写回时机等由 OS 根据全局内存压力优化,比应用层"盲猜"更优

代价:跨机房/副本同步时,如果数据量超过 Page Cache,性能会急剧下降("缓存悬崖"效应)。

上一页
日志清理与压缩
下一页
Producer 性能优化