簡體   English   中英

Docker 長時間運行命令 memory 消耗隨時間增長

[英]Docker long-running command memory consumption grows over time

我正在嘗試在 docker 中運行一個長時間運行的命令,並且我看到在命令執行期間 memory 消耗增加。

我在 Laravel 應用程序的上下文中運行一個由 741 個測試和 3390 個斷言組成的測試套件,其中 PHPUnit。 這些測試中的大多數是使用數據庫連接、redis 和 docker-compose 中的 s3 服務的集成測試。 我正在使用此測試運行生成代碼覆蓋率報告。 這是我運行的確切命令

docker-compose run phpunit --verbose --testdox --colors=never --stop-on-error --stop-on-failure --coverage-clover coverage.xml

我嘗試了很多方法來查看 memory 的泄漏位置(是 Docker、PHP 還是 Z23EBCCFD347939F4094E6) 以下是我設置的 memory 報告及其結果:

  1. PHPUnit 默認在運行結束時報告他的 memory 使用情況。 -> 它總是在 80-100MB 左右,這很好。
  2. 我使用了teardown function 並打印了memory_get_peak_usage -> 它與之前的 80-100 非常相似,在后來的測試中它略微增加到 120MB。 看起來不錯
  3. 我在teardown function 中添加了passthru('ps -o pid,user,%mem,command ax | sort -b -k3 -r | head') -> 我可以看到我的 memory 消耗以非常快的速度上升。 我認為它與第 4 行匹配的百分比相同,因此推斷它在運行結束時接近 6.5G。 唯一使用 RAM 的進程是phpunit
  4. 在我的主機上,我會運行docker stats --format "table {{.Name}}\t{{.MemPerc}} - {{.MemUsage}}\t{{.BlockIO}}" -> 同樣的事情,memory在運行結束時增加到 6.5 GB 的 RAM。 唯一增加 memory 使用量的容器是運行 phpunit 的容器。 docker-compose 的其他容器沒有移動(數據庫、redis、s3 等)。
  5. 在我的主機上,我會運行watch -n 1 free -m來報告我整個計算機上的 RAM 使用情況 -> 同樣的事情,memory 在運行結束時增加到 6.5 GB 的 RAM。 命令完成后,6.5 GB 的 RAM 立即釋放。

我的問題與這個問題非常相似: Docker 在使用 PHP 創建和刪除文件后不釋放 memory 我已經嘗試過提出的解決方案。 我以privileged模式運行echo 3 > /proc/sys/vm/drop_cachessync && sysctl -w vm.drop_caches=3 memory 的使用沒有什么不同,但我可以看到 BlockIO 現在的增長速度與 memory 的使用速度相同,如果沒有這些命令之一,它就不會這樣做。

2021 年 4 月 28 日更新:它最終不是 Docker 的問題,而是 PHPUnit 的問題。 當使用processIsolation=false運行測試時,PHPUnit 似乎正在泄漏。 我的理解是processIsolation=true ,每個測試用例都會啟動一個新進程。 所以 memory 在每次測試之間被釋放,但是執行需要更多時間。

processIsolation=false :快速但泄漏 memory

processIsolation=true :緩慢但泄漏 memory 在測試之間發布

Docker 進程不是使用 memory 的進程,docker 是報告使用的進程。 memory 由容器中的進程和 kernel 模塊使用。 根據問題中的信息,我認為您沒有問題,而是您對 memory 由 kernel 管理的方式感到困惑,所以我將嘗試在非常高的層面上解釋發生了什么。

Kernel 命名空間

現代 Kernel 允許創建分區(命名空間),其中分配給此分區的進程可以半隔離(與用戶空間中的所有其他進程隔離,但不是與所有 kernel 子系統/模塊隔離)。 Docker 正在使用 kernel 的此功能來創建容器。

該容器在所謂的kernel namespace中運行。 kernel 命名空間與運行 docker 應用程序的 docker 的 memory 空間關系不大。 The docker application is responsible only for the orchestration of the namespaces (creating new namespaces, assigning containers to namespaces, setting the resource limits, provisioning network infrastructure, etc.), so Docker, after creating the kernel namespace is not involved if further memory management其中。

因此,當您啟動一個容器時,Docker 會為容器創建一個新的命名空間,消除所有資源限制,准備網絡並在該命名空間中啟動進程。 我故意為這個對話過度簡化了容器的創建,所以如果你需要更多信息,你可以查看這個帖子:

緩沖區和緩存真的是個問題嗎

kernel 會盡量使用“未使用的內存”作為緩存。 這很有意義。 未使用的 memory 處於空閑狀態,因此將其用作緩存來加速進程是一個非常好的策略。 這有助於對 I/O 綁定的進程產生巨大的影響(主要是當進程有很多 IO 讀取操作時)。 文章Linux 頁面緩存基礎知識提供了很好的文本作為入口點,以了解有關 kernel 緩存的更多信息。

kernel 將傾向於將“免費” memory 重新用於緩存和緩沖區。 如前所述,這是一個非常好的功能,可以幫助所有進程更快地運行。 一旦 memory 壓力在命名空間中開始增長,這意味着在命名空間中運行的進程需要更多 memory,kernel 將開始縮小緩存,以便通過找到它們使用最少的區域並釋放它們來分配給它們的進程。 這在 kernel 文檔中有所描述。

kernel不會急着釋放緩存,除非有memory壓力。 因此,除非需要 memory,一旦分配到緩存,kernel 將保留它。 從 kernel 的角度來看,這也是一個非常好的策略,因為它避免了釋放緩存和將來可能重新填充緩存的額外工作。

因此,除非我們談論 kernel 或 kernel 模塊中的缺陷,否則緩沖區/緩存使用的 memory 是一件好事,而不是問題

通過使用sync && echo 3 > /proc/sys/vm/drop_caches這在 kernel 文檔部分Documentation for /proc/sys/vm/中進行了解釋,系統被迫刪除盡可能多的緩存對象,這將導致我/O 性能問題,直到重新填充緩存。 這對於調試和分析很有用,但在正常生產中不是一個好的做法。 清理緩存后,kernel 將需要重新填充(因為還有其他進程確實需要此緩存),這會導致額外的 IO。

管理 memory

Docker 提供了管理容器如何使用 memory 和與容器相關的限制的機制。 您可以在 docker 的文檔中查看更多關於 Memory、CPU 和 GPU 的運行時選項

除非有特殊用例需要對 memory 進行特殊處理,否則 Docker 提供的資源管理功能足以確保容器的平穩運行。

memory 故障排除

有時我們可以通過 kernel / kernel 模塊或容器中的應用程序來處理 memory 泄漏問題。

故障排除的第一步是確定誰在真正使用 memory 以及它是如何增長的。 為了識別有問題的代碼,我們需要對 memory 分配進行故障排除,並了解在達到 memory 壓力時是否存在不斷增長且未釋放的區域。 除了freeps之外,有關 memory 生命周期的更好信息可以在sysfs上找到。

sysfs將 kernel 的內部結構公開為用於讀取和發送信號的文件系統。 /proc/sys/vm也是稱為procfs的同一機制的一部分。 /sys/fs/cgroup/memory是memory分配信息和統計信息所在的文件夾。 Docker 創建了自己的cgroup稱為Docker ,因此所有 docker 容器的統計信息將在/sys/fs/cgroup/memory/docker/中找到此外,docker 將為/sys/fs/cgroup/memory/docker/<<container id>>下的每個容器創建一個cgroup

要查找有關容器的 memory 使用情況的 kernel 統計信息,您可以檢查sysfs中的文件,如下所示:

  • /sys/fs/cgroup/memory/docker/<<container id>>/memory.stat關於 memory 使用情況的統計信息(類似於free但有更多詳細信息
  • /sys/fs/cgroup/memory/docker/<<container id>>/memory.limit_in_bytes當前為容器設置的限制(以字節為單位)
  • /sys/fs/cgroup/memory/docker/<<container id>>/memory.kmem.slabinfo的區域和緩存/緩沖區對象的使用

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM