01

概述

kafka集群中的某些broker会随机重启,并且重启没有什么规律。broker重启对于client端使用层面是无感知的,但是在数据一致性、稳定性方面存在风险。broker重启时,连接在这台broker的连接会重连到其他正常的broker,增加集群中其他broker的压力。同时这个broker上的leader partition也会触发切主操作,频繁切主会影响该partition的一致性和可用性。partition的变动也会触发消费端的重平衡,从而影响消费端的稳定性。

通过查看 kafka 服务端日志,并未发现明显的 ERROR 级别日志。通过和运维同学的共同排查,最终定位并解决了这个问题,由于这个问题比较典型,因此通过这篇文章记录问题排查和定位过程。

02

找问题现场

1、分析 java core dump 文件:/tmp/hs_err_pid128144.log ,在文件头中发现以下线索,每次crash都是由OOM触发导致。

      2、在 core dump 文件头部和尾部找到内存分配的细节:分配 12288Byte 空间失败,然而物理内存还剩余 461984KB,显然可以排除 crash 不是内存不够导致。


Native memory allocation (mmap) failed to map 12288 bytes for committing reserved memory.

Memory: 4k page, physical 131519612k(461984k free), swap 0k(0k free)


3、在core dump文件的线程调用栈中发现分配page相关的函数 os::pd_create_stack_guard_pages,我们进入到 os::Linux::commit_memory_impl 函数,发现其实是做了一次mmap系统调用。

4、从上面代码进入到  warn_fail_commit_memory 方法,理论上,日志中会打印 warning 内容,kafka集群的日志为INFO级别,因此 warning 日志就看不到了。如果日志能看到的话,至少我们知道mmap发生的具体errorno是什么,从而断定mmap到底是为什么失败了。由于线上集群规模较大,修改日志级别重启broker数量较多,为了不影响业务,暂时选择不重启。到现在好像基本上断了思路,只能等待修改日志级别之后看看其效果。

03

分析gc日志

1、查看 grafana 监控指标,在进程内存占用发现线索。通过下图的gc监控情况,我们可以发现 gc 过后有个别机器内存占用大幅减少,甚至可以观察到某些broker明显重启了。此时观察gc异常的broker已经crash了,因此我们可以判断crash可能和gc有关。

2、通过分析gc日志,full gc之前新生代、老生代使用率都不高,gc次数也不是很频繁,因此 GC Locker 基本没有可能,那么最有可能的就是System GC了。那什么情况下会发生 System GC 呢?

  • 代码显示调用;

  • RMI(Remote Method Invocation)里定时调用;

  • 堆外内存不够导致的调用;

这几种情况基本都可以排除:

  • kafka 为 scala 语言写的,通过翻看kafka代码,未发现System GC的显示调用;

  • RMI(Remote Method Invocation)也不可能,因为我们从线程列表里看不到GC Deamon线程,因此不存在RMI调用;

  • 堆外内存主要是说 DirectByteBuffer,这也不太可能。因为我们从 JVM 参数来看,第一没有设置最大值MaxDirectMemorySize,第二Xmx设置为40G,那默认堆外内存最大值差不多也这么大。通过下图我们发现 DirectByteBuffer 占用不到200MB,所以堆外内存满了而导致的System GC也基本可以排除。

3、kafka由scala语言编写,依赖了JDK。通过翻看 JDK 代码,寻找可能抛出 System GC 的情况,结果发现了 `sun.nio.ch.FileChannelImpl` 的 map 方法里有类似的逻辑。

04

确定问题现场

1、我们看下 sun.nio.ch.FileChannelImpl.map0 的 native 方法实现 Java_sun_nio_ch_FileChannelImpl_map0,因为这是触发 crash 的地方,然后看到下面的逻辑。因为 crash 的时候确实是抛出了一个 OOM 的异常,因此我们完全可以确定 mmap 返回的 errno 是 ENOMEM 。所以我们在前面提出的,warning日志中没有打印出来的具体 mmap 异常,从这个地方也基本可以确认 mmap 异常返回了 ENOMEM 这个错误码。

2、下面是 mmap 的手册里关于 ENOMEM 的介绍

ENOMEM:没有可用的内存。

ENOMEM将超过该进程的最大映射数。当在现有映射的中间取消映射区域时,munmap() 也可能发生此错误,

因为这会导致在该区域的任一侧取消两个较小的映射。

3、我们确认了物理内存是足够的,因此我们只能怀疑是否达到了 mappings 的最大个数,我们再结合下 kernel 里的 mmap 的实现(`mm/mmap.c:do_mmap`)。通过 mmap 的实现,我们发现当 mmap 的 vma(virtual memory areas) 个数达到了最大值的时候确实会返回 ENOMEM,于是确认了下 `/proc/sys/vm/max_map_count` 的值为 65530。也就是说我们 mmap 的 vma(virtual memory areas)最多只能是 65530 个,再统计下  java core dump 文件里虚拟地址映射的个数(Dynamic libraries下面的条数)正好为 65531,刚好达到这个上限。

经过上面的分析过程,我们确定了案发现场:

kafka 做了很多索引文件的内存映射,并且这些索引文件一直占着内存没有释放,随着索引文件数的增多,而慢慢达到了内存的一个上限。每次创建一个索引文件都会触发 mmap 系统调用,而在 mmap 的时候 check 是否达到了 vma(virtual memory areas)的最大限制,也就是  /proc/sys/vm/max_map_count 里的 65530,如果超过了,就直接 crash 了。

05

解决方案

通过排查我们的解决方案有下面两种思路:

  • 增大系统限制 /proc/sys/vm/max_map_count;

  • kafka 的索引文件是否不需要一直有?是否可以限制一下?kafka 在读取消息时,要通过索引文件中的索引定位消息。如果对于读取频率相对低的消息释放索引文件的引用,当读取历史数据时需要重新遍历数据文件重建索引,这个过程磁盘IO开销比较大,会严重影响 kafka 的吞吐。因此我们选择增大系统参数 /proc/sys/vm/max_map_count ;

记一次kafka集群频繁crash的排查过程相关推荐

  1. 记一次 Kubernetes 集群 Pod Eviction 问题排查过程

    声明: 本博客欢迎转发,但请保留原作者信息! 新浪微博:@Lingxian_kong; 微信公众号:飞翔的尘埃; 内容系本人学习.研究和总结,如有雷同,实属荣幸! 现象:一个普通的 k8s 集群,3 ...

  2. 记一次Kafka集群的故障恢复

    女主宣言 本文是作者根据实际经验总结出的关于Kafka集群的故障恢复相关的总结,希望对大家有所帮助. PS:丰富的一线技术.多元化的表现形式,尽在"HULK一线技术杂谈",点关注哦 ...

  3. k8s kafka集群 连接不上_图解 K8s 核心概念和术语

    我第一次接触容器编排调度工具是 Docker 自家的 Docker Swarm,主要解决当时公司内部业务项目部署繁琐的问题,我记得当时项目实现容器化之后,花在项目部署运维的时间大大减少了,当时觉得这玩 ...

  4. kafka集群under replicated分析

    近期随着业务消息量增大,现网几套kafka集群频繁收到under repliacted告警,集合近期定位分析过程,主要有以下几个方面: 1. 查看是否有主机挂掉,或近期是否有主机重启,通过kafdro ...

  5. kafka集群broker频繁挂掉问题解决方案

    kafka集群broker频繁挂掉问题解决方案 参考文章: (1)kafka集群broker频繁挂掉问题解决方案 (2)https://www.cnblogs.com/itfly8/p/1068841 ...

  6. 记学编程以来第一次找错费时一天的经历——kafka集群创建主题时报错

    错误如下: Exception in thread "main" joptsimple.UnrecognizedOptionException: bootstrap-server ...

  7. 完美避坑!记一次Elasticsearch集群迁移架构实战

    作者介绍 李猛(ynuosoft),Elastic-stack产品深度用户,ES认证工程师,2012年接触Elasticsearch,对Elastic-Stack开发.架构.运维等方面有深入体验,实践 ...

  8. kafka 丢弃数据_20条关于Kafka集群应对高吞吐量的避坑指南

    Apache Kafka是一款流行的分布式数据流平台,它已经广泛地被诸如New Relic(数据智能平台).Uber.Square(移动支付公司)等大型公司用来构建可扩展的.高吞吐量的.高可靠的实时数 ...

  9. ELK+Kafka集群日志分析系统

    因为是自己本地写好的word文档复制进来的.格式有些出入还望体谅.如有错误请回复.谢谢! 一. 系统介绍 2 二. 版本说明 3 三. 服务部署 3 1) JDK部署 3 2) Elasticsear ...

最新文章

  1. 【Linux网络编程】TCP三次握手和四次挥手
  2. 数据挖掘需要学习的内容
  3. linux下php、apache、mysql、curl环境搭建
  4. k8s核心技术-Helm(概述)---K8S_Google工作笔记0044
  5. Python实现删除字符串中的字符
  6. Boring Game (10 分)
  7. python xml转字典_python xml转成dict
  8. 强化学习从入门到放弃的资料
  9. 公众号零基础,只需10分钟,你的公众号也能5天500+粉丝
  10. 博弈论战略式表述和扩展式表述
  11. python画樱花树教程_Python画樱花树❀
  12. 微信小程序:扫描身份证读取身份信息
  13. 个人计算机是国产芯片,全球最纯国产PC诞生!所有芯片/系统都是国产
  14. 基于C/C++的hex、s19文件相互转换
  15. 跨考计算机考研华科还是中科大,2018中科大计算机考研经验贴
  16. docker修改服务器参数怎么办,Docker(32)- 如何修改 docker 容器的启动参数
  17. 高效学习的 36 种思维
  18. 如何评价谭浩强(转自知乎)
  19. Java基础or介绍骚话
  20. 关于bool operator< (const Edge W)const

热门文章

  1. Android下结束进程的方法
  2. 抽象类和普通类主要有三点比较大的区别,super
  3. MyBatis中使用LIKE关键字模糊查询
  4. conda install 换源_科学网—Anaconda 报错Multiple Errors Encountered和添加国内镜像以及换源和恢复默认源 - 张伟的博文...
  5. Java使用Springboot集成Es官方推荐(RestHighLevelClient)
  6. c语言微秒级延时,linux下写个C语言程序,要求有0.5微秒以下的延时,要怎样写...
  7. python获取股票历史数据_量化交易之如何获取股票历史数据并存为csv
  8. 为什么说Pravega是流处理统一批处理的最后一块拼图?
  9. ZOJ2724_Windows Message Queue(STL/优先队列)
  10. background-origin:规定 background-position 属性相对于什么位置来定位