首先是hadoop部分涉及到的虚存问题
关于虚存限制,Hadoop 有两个参数控制,第一个参数决定是否打开虚存检查,默认为 true,第二个参数指出虚存的 Limit 的计算规则是申请实存的 2.1 倍,这解释了为什么实存设置的小了之后虚存也小了。
yarn.nodemanager.vmem-check-enabled | true | Whether virtual memory limits will be enforced for containers. |
---|---|---|
yarn.nodemanager.vmem-pmem-ratio | 2.1 | Ratio between virtual memory to physical memory when setting memory limits for containers. Container allocations are expressed in terms of physical memory, and virtual memory usage is allowed to exceed this allocation by this ratio. |
什么是虚存
虚存本质上是 OS 对内存资源的超售,技术上来说从 OS 角度有 Demand Paging,从进程角度有 Overcommit。而 Overcommit 是 OOM 的根源,内核对进程对内存的使用做了较为乐观的估计和假设,所以像 JVM 这种一起来就申请 (malloc) 巨大内存的情况虽然很多,但由于 Overcommit 机制所以能很好的运行。 又因为这种假设并不能放之四海而皆准,所以当遇到进程真的挤兑资源的时候(与 Overcommit 假设不符),操作系统会通过 OOM - Killer 机制来挽救。挽救的方式是使用一些特殊的策略来随机的杀死进程,在进程的角度看到的就是跑的好好地被 OOM Killed 了。
当然,日常使用中还存在另一种 OOM,不同于 Overcommit 策略被挤兑时才出现,在 CGroup 生效的时候进程通过 cgroup 与内核协商了最大的资源限制,一旦 RSS(实存) 超过此限制后同样会被 OOM Killed。
理解memory overcommit的关键:commit(或overcommit)针对的是内存申请,内存申请不等于内存分配,内存只在实际用到的时候才分配。
内核参数 vm.overcommit_memory 接受三种取值:
- 0 – Heuristic overcommit handling. 这是缺省值,它允许overcommit,但过于明目张胆的overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存。Heuristic的意思是“试探式的”,内核利用某种算法(对该算法的详细解释请看文末)猜测你的内存申请是否合理,它认为不合理就会拒绝overcommit。
- 1 – Always overcommit. 允许overcommit,对内存申请来者不拒。
- 2 – Don’t overcommit. 禁止overcommit。
“sar -r”是查看内存使用状况的常用工具,它的输出结果中有两个与overcommit有关,kbcommit 和 %commit:
kbcommit对应/proc/meminfo中的 Committed_AS;
%commit的计算公式并没有采用 CommitLimit作分母,而是Committed_AS/(MemTotal+SwapTotal),意思是_内存申请_占_物理内存与交换区之和_的百分比。
1 | sar -r |