Kafka 3.6压测遇java.io.IOException: Map failed致Broker崩溃求助
问题描述
在包含3个Broker的Kafka集群中进行1000万条记录的压测时,每次触发java.io.IOException: Map failed异常后Broker都会崩溃。初始分析认为是vm.max_map_count默认值65K的问题,已将其调高至400K,但重新压测时Broker仍在处理300-400万条记录期间崩溃。
服务器配置:60GB内存,每个Broker堆内存设为6GB(xmx和xms均为6GB),数据目录剩余大量磁盘空间,进程与系统采样监控未发现性能异常。该问题自Kafka版本升级至3.x后出现,咨询是否有同类问题案例及3.x高负载压测的性能调优方案。
环境信息
Java版本
openjdk version "11.0.8" 2020-07-14 LTS OpenJDK Runtime Environment 18.9 (build 11.0.8+10-LTS)
错误堆栈
Error while appending records to LoadTestingTopic in dir /broder/log (org.apache.kafka.storage.internals.log.LogDirFailureChannel) java.io.IOException: Map failed at java.base/sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:1016) at org.apache.kafka.storage.internals.log.AbstractIndex.createMappedBuffer(AbstractIndex.java:466) at org.apache.kafka.storage.internals.log.AbstractIndex.createAndAssignMmap(AbstractIndex.java:104) at org.apache.kafka.storage.internals.log.AbstractIndex.<init>(AbstractIndex.java:82) at org.apache.kafka.storage.internals.log.OffsetIndex.<init>(OffsetIndex.java:69) at org.apache.kafka.storage.internals.log.LazyIndex.loadIndex(LazyIndex.java:239) at org.apache.kafka.storage.internals.log.LazyIndex.get(LazyIndex.java:179) at kafka.log.LogSegment.offsetIndex(LogSegment.scala:67) at kafka.log.LogSegment.canConvertToRelativeOffset(LogSegment.scala:130) at kafka.log.LogSegment.ensureOffsetInRange(LogSegment.scala:177) at kafka.log.LogSegment.append(LogSegment.scala:157) at kafka.log.LocalLog.append(LocalLog.scala:439) at kafka.log.UnifiedLog.append(UnifiedLog.scala:911) at kafka.log.UnifiedLog.appendAsLeader(UnifiedLog.scala:719) at kafka.cluster.Partition.$anonfun$appendRecordsToLeader$1(Partition.scala:1313) at kafka.cluster.Partition.appendRecordsToLeader(Partition.scala:1301) at kafka.server.ReplicaManager.$anonfun$appendToLocalLog$6(ReplicaManager.scala:1210) at scala.collection.StrictOptimizedMapOps.map(StrictOptimizedMapOps.scala:28) at scala.collection.StrictOptimizedMapOps.map$(StrictOptimizedMapOps.scala:27) at scala.collection.mutable.HashMap.map(HashMap.scala:35) at kafka.server.ReplicaManager.appendToLocalLog(ReplicaManager.scala:1198) at kafka.server.ReplicaManager.appendRecords(ReplicaManager.scala:754) at kafka.server.KafkaApis.handleProduceRequest(KafkaApis.scala:686) at kafka.server.KafkaApis.handle(KafkaApis.scala:180) at kafka.server.KafkaRequestHandler.run(KafkaRequestHandler.scala:149) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: java.lang.OutOfMemoryError: Map failed at java.base/sun.nio.ch.FileChannelImpl.map0(Native Method) at java.base/sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:1013)
同类问题案例与调优方案
同类问题案例
Kafka 3.x版本升级后,不少用户遇到过类似的Map failed异常,核心触发场景包括:
- 3.x版本对日志索引的内存映射策略做了调整,默认索引文件的映射逻辑变化,导致单进程内存映射区域占用超出预期;
- 即便调高了
vm.max_map_count,如果进程的虚拟内存限制(ulimit -v)设置过低,依然会触发映射失败; - Kafka依赖直接内存处理索引和网络IO,若JVM直接内存配置不足,堆内存正常但直接内存耗尽时也会引发该异常。
性能调优方案
1. 内存相关调优
- 调整JVM直接内存限制:在Kafka启动参数中添加
-XX:MaxDirectMemorySize=16G(建议设置为物理内存的1/4~1/3,根据服务器配置调整),避免直接内存耗尽导致映射失败; - 解除进程虚拟内存限制:执行
ulimit -v unlimited取消进程虚拟内存限制,或调高至足够大的值; - 优化日志索引配置:
- 调大
log.index.size.max.bytes(默认10MB),减少索引文件数量,降低内存映射区域的占用; - 启用3.x新增参数
log.index.optimization.enable,优化索引文件的内存映射管理逻辑。
- 调大
2. Kafka核心参数调优
- 调整日志段大小:设置
log.segment.bytes=1G(可根据压测需求调整),减少Segment数量,间接降低索引文件的映射次数; - 调整副本同步策略:压测期间临时设置
replica.lag.time.max.ms=300000,避免因同步延迟引发额外资源消耗; - 优化请求处理线程数:根据CPU核心数设置
num.io.threads=16、num.network.threads=8(建议为核心数的1~2倍),提升请求处理能力。
3. 系统层面调优
- 确认
vm.max_map_count生效:执行sysctl vm.max_map_count确认值为400K,若未生效则写入/etc/sysctl.conf并执行sysctl -p持久化; - 调整磁盘IO调度策略:针对SSD磁盘,将调度器设置为
noop或deadline,执行echo noop > /sys/block/sda/queue/scheduler; - 关闭透明大页:执行
echo never > /sys/kernel/mm/transparent_hugepage/enabled,避免大页内存对内存映射的负面影响。
内容的提问来源于stack exchange,提问作者ChristDist
相关产品推荐
相关产品推荐

