【Flink】第七篇:记一次Flink Job物理内存不足引起checkpoint失败问题排查

2022-03-31 11:01:07 浏览数 (1)

我们组的实时数仓项目(二期:Flink SQL指标计算)进入上线阶段。所以,最近的推文我会持续更新一些线上问题排查的实战经验和思路,并尽量针对一类相似或者关联问题所涉及的关键点进行总结,抽出一些方法论分享给大家,感谢支持^^

问题简介

集群突然变得不稳定,一些作业的TaskManager出现以下问题:

  1. checkpoint failed:检查点无规律偶然失败,之后又恢复正常;
  2. NativeIoException:报Flink的netty通信层异常,Connection reset by peer;
  3. RemoteTransportException:报Flink的netty通信层异常,Connection unexpectedly closed by remote task manager xxx;
  4. yarn container物理内存限制异常:beyond the 'PHYSICAL' memory limit;
  5. JobManager报通信问题:Association witch remote system [akka. tcp://xxx] has a failed, address is now gated for [50] ms. Reason: [Disassociated];
  6. PartitionRequestQueue:Flink的netty通信层在交互分区的数据时报错,Encountered error while consuming partitions;
  7. CDH资源管理界面报检测不到jdk;
  8. OutOfMemoryException:create thread 失败,异常堆栈陷入到线程启动方法,native start0();

初步分析

以上问题是集中发生的,虽然现象很复杂,但不出意外是由某一两个根本原因导引起的一系列连锁异常,所以,尽量将他们联系在一起进行思考。

Connection reset by peer是很典型的通信异常问题,是由于TCP链接的远端发送了RST报文,这个报文的语义是远端通知本地不通过四次挥手,直接立刻关闭链接。

native标识的方法表示Java的JNI(Java Native Interface),代表着已经由JVM陷入到ddl动态链接库了,

  1. 到这里抛出的异常一般不会是由于Java代码逻辑问题造成的,故推断是远端连接异常问题导致本地收到RST;
  2. 或者是由于本地的一些JVM参数配置问题导致的。

所以,以上问题中涉及和远端通信的问题可能是核心故障衍生的二三阶的表象。进一步,还剩下物理内存超过限制的问题。

用top命令查看节点的CPU和Mem的使用情况:

知识延伸:top

代码语言:javascript复制
top
top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况

第一行,任务队列信息,同 uptime 命令的执行结果
第二行,Tasks — 任务(进程)
第三行,cpu状态信息
第四行,内存状态
第五行,swap交换分区信息
第六行,空行
第七行以下:各进程(任务)的状态监控

VIRT:virtual memory usage 虚拟内存
1、进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据等
2、假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而不是实际的使用量

RES:resident memory usage 常驻内存
1、进程当前使用的内存大小,但不包括swap out
2、包含其他进程的共享
3、如果申请100m的内存,实际使用10m,它只增长10m,与VIRT相反
4、关于库占用内存的情况,它只统计加载的库文件所占内存大小

SHR:shared memory 共享内存
1、除了自身进程的共享内存,也包括其他进程的共享内存
2、虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小
3、计算某个进程所占的物理内存大小公式:RES – SHR
4、swap out后,它将会降下来

DATA
1、数据占用的内存。如果top没有显示,按f键可以显示出来。
2、真正的该程序要求的数据空间,是真正在运行中要使用的。

在top里我们要时刻监控第五行swap交换分区的used,如果这个数值在不断的变化,说明内核在不断进行内存和swap的数据交换,这是真正的内存不够用了。

知识延伸:swap

swap是OS对磁盘进行空分复用,解决内存不够用时暂存内存数据的一种手段,是虚拟的扩展内存。所以,当频繁使用swap时,从侧面就说明了OS的内存复合比较重了。

虚拟:指通过某种技术把一个物理实体变为某个逻辑上的映射对象。

  • 时分复用(一个物理实体,分时对应多个逻辑实体,需要独占的资源只能时分复用)
    1. 虚拟处理机:多道程序分时复用CPU
    2. 虚拟设备:将一台I/O虚拟为多个I/O
  • 空分复用(一个物理实体,按空间分别对应多个逻辑实体,不需要独占的资源即可空分复用)
    1. 虚拟磁盘:将硬盘分为若干个卷,再分别安上逻辑驱动器
    2. 虚拟存储:内存分时复用;请求调入和置换功能(每次只把用户程序的一部分调入内存运行,这样实现了程序分时进入内存运行)。

但是经过top命令观察集群的大部分节点是不存在swap频繁交换的现象。但是为什么又会报物理内存不够呢?

当时,又恰巧用了一些jps、jstate命令在观察TM进程的JVM内存和GC情况,但是敲入命令时居然报没有足够的空间创建线程。

溯源而上,循序渐进

结合上面的现象和分析:

  1. 物理内存有余
  2. 进程报物理内存不足,
  3. netty报远端节点发送RST报文,或者是JM报与TM 异常 或者是 TM lost
  4. CDH报JDK找不到,运行jps等命令失败

结合之前设置过用户粒度的资源限制/etc/security/limits.conf,马上问题有了思路。

通过查看和修改limits配置文件,扩大用户资源限制上限。

知识延伸:limits.conf

Linux系统限制普通用户内存使用(ulimit)和硬盘配额空间(quota)

限制普通用户内存

第1步,首先进到Linux终端用vim编辑/etc/security/limits.conf :

代码语言:javascript复制
>sudo vim /etc/security/limits.conf

# max memory locked : means the size of the memory which cannot be changed to swap 
#@users          hard    memlock         11000000
#@users          hard    maxlogins       99
#@users          hard    data           2000000

进入后若想限制每一个用户的内存使用量不能超过20G左右,则在最下面添加

代码语言:javascript复制
* hard rss 21000000

若想限制某个用户test的内存使用量不能超过20G左右,则可添

代码语言:javascript复制
@users hard rss 21000000
  1. 加*号表示对所有用户起作用,加@users表示只对某个名叫users的用户起作用。
  2. hard说明是硬上限,你也可以改成soft,也即软上限。
  3. rss表示我们限制的是内存的使用量。
  4. 21000000(单位KB)表明我们限制的量大概是20GB。

第2步:用vi编辑/etc/pam.d/login文件,然后加上下面这行保存退出就可以。

代码语言:javascript复制
 session required /lib/security/pam_limits.so

第3步:退出账户在重新登陆,使用下述命令可以查看内存配额

代码语言:javascript复制
ulimit -a

注意:/etc/security/ulimits.conf 文件中nofile 的软硬限制的值不能超过内核参数 /proc/sys/fs/nr_open ,否则就有问题!

调整完后集群异常减少了很多,但是偶尔还存在yarn containner物理内存limit问题,这是由于yarn的配置问题,所以可以配置提升这个限制或者开启是否检查limit,但是,请先确定你的作业逻辑确实需要这么多内存。

例如,我们再检查我们的Flink SQL逻辑时发现,在做temporal left join的过程中,on条件没有按照常规的方式去join lookup hbase 维表,修改SQL逻辑后重新提交作业(感谢凯哥的分享^^),上线,运行后没有再出现任何之前的问题了!

0 人点赞