最近,我開始監控咱們一直在開發的 Node.js 應用程序。一段時間後,我發現它的內存使用率增加緩慢,3 天就增加了 20%。在如下 Node.js 代碼中測量了內存使用狀況。docker
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採起緩衝區和緩存的考慮。app
$ 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還有朋友:ui
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。code
那麼,咱們應該使用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 容器中的進程直接在其主機操做系統中運行,沒有任何虛擬化,但因爲這些 Linux 內核特性,它們與主機操做系統和其餘容器有效隔離:
命名空間:隔離 PID、主機名、用戶 ID、網絡訪問、IPC 等。
默認狀況下,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或使用它的命令找到主機操做系統的總內存。
這是一段比我最初想象的更長的旅程。個人要點是: