以下一切在Linux OS(3.10.0)的运行环境下讨论: 我们都知道,进程内存资源不足后,会OOM crash,进程退出。 然而,如果机器的物理内存资源被占用光后,在不考虑cgroup kill的情况下,会怎么样呢?其上的进程又会表现如何? 有人说,机器会宕机。 有人说,进程申请内存失败会在进程层面报错,不会伤及操作系统。 “纸上得来终觉浅,绝知此事要躬行。” 我们通过实际测试来看上面的情况具体如何。 通过这个测试,希望可以指导我们在使用大内存规格的机器时,服务进程(比如我们的内存大户,计算服务)到底该使用多少内存为宜。
测试机型:
使用系统默认glibc库申请内存
测试程序:
测试过程:
创建10个线程,每个线程申请64G内存,注意每次申请1024字节,避免glibc对于大块内存申请直接mmap
测试结果:
四个测试进程同时申请并持有了100多G的内存,整个物理机上的内存被占满
随后,四个测试进程陆续被操作系统Killed掉
查看系统sys日志,看到内存分配失败,oom-killer杀掉了测试进程
操作系统表现如何呢?
测试期间,系统运行稳定,没有出现机器hang或宕机,进程申请内存超限后会被Killed掉,保证了系统的安全运行。 说明:使用glibc库申请内存,机器的物理内存资源被占用光后,如果相关进程还继续申请内存,会因内存申请失败,被OS主动Killed掉,操作系统及物理机本身不会出现重启或宕机。
使用线上服务常用的tc_malloc库申请内存
测试程序:
与上述一致
测试过程:
创建10个线程,每个线程申请64G内存,每次仍然申请1024字节,使用tc_malloc库向操作系统申请内存资源
测试结果:
可以看到,tcmalloc在进行内部内存管理时(central_freelist),遇到了问题,持续分配内存失败。
操作系统表现如何呢?
测试过程中,操作系统发生hang,远程登录失败,以为是OS crash机器重启了,但是等测试结束后,重连机器发现,机器启动时间未变,并没有出现重启,但是测试期间,机器发生了一段时间hang,新进程因内存资源耗尽,无法fork出来,终端没有了响应。
机器确实在一段时间内发生了hang
以上是内存完全被耗尽的情况,那内存未完全占满的情况下,tc_malloc表现又如何呢? 我们希望知道系统在使用了高水位(比如80%)内存后的表现,以此辅助我们来决策我们的计算系统(吃内存的大户)究竟可以用多少物理内存比较合适。 因此,我们重新对测试程序进行调整,以我们想要使用的实际场景来模拟内存使用情况: 共分6个进程:2128G、264G、2*32G,共计448G,加上系统内存,内存水位在95.8% 在物理内存占用95%的情况下,系统运行仍然相对稳定,未有明显异常表现。 备注:前提是系统此时不再有额外的突发内存申请,这是一种极限测试,正常情况下,我们应该确保系统内存处于安全水位(80%以下)。
结论
本文针对物理内存耗尽的极限情况,对Linux操作系统(3.10.0)的内存管理和运行情况进行了实际的黑盒测试。 分别对主流的两种内存分配器glibc和tc_malloc进行了测试验证。 测试结果证明:
无论glibc还是tc_malloc,机器不会因为物理内存资源耗尽,而发生宕机重启(这个应该是由linux内核来保证的,除非内核层面出现问题,如硬件内存卡故障、软件中断异常等问题,这也正是操作系统的职责:在硬件和软件之间的一层隔离和保护)。
使用glibc内存分配器,内存资源耗尽后,进程会被Killed掉,从而释放内存,机器整体运行平稳,不会出现hang等宕机现象。
使用tcmalloc内存分配器,内存资源耗尽后,进程本身会频繁与tcmalloc内存管理模块进行交互,出现很多"allocation failed"错误,系统load增高,机器整体会发生hang,新进程可能因为无内存资源而无法fork出来,网络通信可能发生中断。
无论glibc还是tc_malloc,在物理内存使用**95%**以下,经过测试系统整体运行平稳,超过该阈值系统则面临诸多风险,包括运行hang、网络通信中断、进程因无内存资源而无法fork、内存调用频繁失败、系统load增高等等。
===================== 但同时,为了避免给读者造成认知上的偏差和误解,这里要申明: 以上是基于简单压力模型下的测试表现,不代表全部情况,比如存在超高负载场景下的表现(有很多网络IO的情况)。 经过与同事的交流,得知一个真实案例:我们的存储服务在线上实际业务高负载下,当机器内存持续上涨,在没有及时kill的情况下,多个机器因为内存oom而宕机(使用的是tcmalloc-2.8.1),即使机器没有宕机,发生十几分钟的hang也将会严重影响线上服务。 因此,我们应该合理规划机器上各个服务的内存资源分配,通过cgroup等方式严格控制内存资源的使用,保持内存在合理安全水位线下,确保安全。