最近,我开始监控咱们始终在开发的 Node.js 应用程序。一段时间后,我发现它的内存使用率增长迟缓,3 天就增长了 20%。在以下 Node.js 代码中测量了内存应用状况。
const os = require("os");
const total = os.totalmem();
const free = os.freemem();
const usage = ((free - total) / total) * 100;
所以,它们基本上来自操作系统,在这种状况下是 Docker 上的 Alpine Linux。侥幸的是,我还记录了应用程序过程的内存应用状况,但它们并没有减少。那么为什么操作系统内存使用量会减少呢?
缓冲区和缓存内存
我应用了 top 命令 Shift+m(按内存应用状况排序)并比拟了长时间运行的服务器上的过程和新部署的服务器上的过程。单方的流程简直雷同。惟一的区别是,buffers 并且 cached Mem 在长期运行的状况下很高。
通过一些钻研或谷歌搜寻后,我得出结论,这不是问题。当应用程序过程要求更多内存时,大部分 buffers 和 cached Mem 被放弃。
其实 free - m 命令提供了一行 used,并 free 采取缓冲区和缓存的思考。
$ free -m
total used free shared buffers cached
Mem: 3950 285 3665 183 12 188
-/+ buffers/cache: 84 3866
Swap: 1896 0 1896
那么,它们到底是什么?依据的手册 /proc/meminfo,这是一个伪文件和 的数据源 free,top 还有敌人:
Buffers %lu
Relatively temporary storage for raw disk blocks that
shouldn't get tremendously large (20MB or so).
Cached %lu
In-memory cache for files read from the disk (the page
cache). Doesn't include SwapCached.
我依然不确定到底 Buffers 蕴含什么,但它蕴含文件的元数据等,而且它的大小绝对微不足道。Cached 蕴含缓存的文件内容,称为页面缓存。操作系统保留页面缓存,而 RAM 有足够的可用空间。这就是为什么即便过程没有透露内存,内存使用量也在减少。
如果您有趣味,/proc/meminfo 输入中的 Buffers 和 Cached 列有什么区别?在 Quora 上有对于 Buffers 和的更多详细信息 Cached。
可用内存
那么,咱们应该应用 free + buffers + cached? /proc/meminfo 有一个更好的指标,称为 MemAvailable。
MemAvailable %lu (since Linux 3.14)
An estimate of how much memory is available for
starting new applications, without swapping.
$ cat /proc/meminfo
MemTotal: 4045572 kB
MemFree: 3753648 kB
MemAvailable: 3684028 kB
Buffers: 13048 kB
Cached: 193336 kB
...
它的背景在 Linux Kernel 中的提交中失去了很好的解释,但实质上它排除了不可开释的页面缓存并包含可回收的平板内存。Linux v4.12-rc2 中的以后实现看起来依然简直雷同。
free - m 有 available 列的一些实现。例如,在 Boot2Docker 上:
$ free -m
total used free shared buff/cache available
Mem: 3950 59 3665 183 226 3597
Swap: 1896 0 1896
它也能够通过 –mem-avail 标记在 AWS CloudWatch 指标上应用。
对于 Docker 的一些背景
我的另一个问题是“Docker 中的这些指标是否雷同?”。在深入探讨这个问题之前,让咱们检查一下 docker 是如何工作的。
依据 Docker 概述:底层技术,Docker 容器中的过程间接在其主机操作系统中运行,没有任何虚拟化,但因为这些 Linux 内核个性,它们与主机操作系统和其余容器无效隔离:
命名空间:隔离 PID、主机名、用户 ID、网络拜访、IPC 等。
- cgroups:限度资源应用
- UnionFS : 隔离文件系统
因为命名空间的起因,pscommand 除了列出宿主操作系统中的其余过程外,还列出了 Docker 容器的过程,而它不能列出宿主操作系统或 docker 容器中其余容器的过程。
默认状况下,Docker 容器没有资源限度。所以,如果你在一台主机上运行一个容器,并且不限度容器的资源应用,这就是我的状况,容器的“闲暇内存”与主机操作系统的“闲暇内存”是一样的。
Docker 容器上的内存指标
如果您想从容器内部监控 Docker 容器的内存应用状况,这很容易。您能够应用 docker stats.
$ docker stats
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
fc015f31d9d1 0.00% 220KiB / 3.858GiB 0.01% 1.3kB / 0B 0B / 0B 2
然而,如果您想获取容器中的内存应用状况或获取更具体的指标,就变得复杂了。Linux 容器内的内存详细描述了艰难。
/proc/meminfo 和 sysinfo,由 Node.js 应用 os.totalmem()和应用 os.freemem(),不是孤立的,如果您在 Docker 容器中应用 top 和等一般实用程序,您将取得主机操作系统的指标 free。
要获取特定于 Docker 容器的指标,您能够在 /sys/fs/cgroup/memory/. 不过,它们并未依据 Linux 容器内的内存进行标准化。
$ cat /sys/fs/cgroup/memory/memory.usage_in_bytes
303104
$ cat /sys/fs/cgroup/memory/memory.limit_in_bytes
9223372036854771712
memory.limit_in_bytes 如果没有限度,则返回一个十分大的数字。在这种状况下,您能够应用 /proc/meminfo 或应用它的命令找到主机操作系统的总内存。
论断
这是一段比我最后设想的更长的旅程。我的要点是:
- Available Memory > Free Memory 即:容许应用内存 > 闲暇内存
- 能用 MemAvailable 时,用 MemAvailable
- Docker 容器中的过程间接在主机操作系统中运行
- 精确理解您正在测量的内容,尤其是在 Docker 容器中