使用 Docker 可以减少或避免 CPU 使用率达到 100% 的容器

有一个使用foreach循环来监视Server-Sent Events的Docker容器。我启动了容器后没多久,机器开始呼哧呼哧地响起来。我用docker stats命令确认后发现CPU使用率已经超过了100%。我该怎么办?

由于在Qiita文章中无法找到”Docker CPU 使用率 100% コンテナ 軽減”的相关结果,所以我将其作为我的搜索能力。

简介:TL;DR(今北産業)

条件により空ループ(何も処理をしないでループする)箇所が発生していないか確認する。(for/foreach/while ループなど)
該当ループ処理の最後に支障をきたさない範囲で sleep を入れる。(1 〜 0.5 秒入れるだけでも劇的に変わる)
上記を確認した上で Docker もしくは docker-compose の設定で最大使用率に制限をかけるのがベター

TS; DR (kwsk)

对于强制限制(Docker版本),只需一个选项。

最初,Docker 已經提供了一個 –cpus 選項,用於限制每個容器的 CPU 最大使用率。換句話說,我們可以指定容器所使用的 CPU 數量,以便分配資源,用於對症治療。

举例来说,如果有4核心的CPU,将CPU分配给两个任务可以将使用率限制在最高50%。

docker run -it --cpus="2" ubuntu /bin/bash

如果要将其限制在最多80%的情况下,可参考以下选项:

docker run -it --cpus="3.2" ubuntu /bin/bash
    • 参考文献

Configure the default CFS scheduler | CPU @ Docker 公式ドキュメント

Docker コンテナの CPU 使用率を制限する Tips @ Qiita

对于docker-compose,强制进行限制

如果想要在 docker-compose 中添加限制,请在 deploy 指令中指定 cpus。

version: '3.8'

services:
  my-service:
    container_name: my-cont1
    build: .
    deploy:
      resources:
        limits:
          cpus: "3.2"
在使用docker-compose up命令时,需要添加–compatibility选项。这是因为docker-compose.yaml文件中的deploy部分通常是为Docker Swarm进行配置的。换句话说,在docker-compose命令中,它将被默认忽略。为了使其在docker-compose中可用,需要添加–compatibility标志选项以在兼容模式下运行。
- docker-compose up myservice
+ docker-compose --compatibility up myservice
    • 参考文献:

docker-compose –help

How to specify Memory & CPU limit in docker compose version 3 @ StackOverflow

这个设置是为了预先控制容器失控时的损害范围,换句话说,它们只是对容器进行了限制。

反过来说,即使正常运行,也不能使用超过CPU资源以上的资源。

如果不徹底地降低 CPU 使用率,資源將被浪費到限制值。很可能大部分情況下不是 Docker 的問題,而是程式結構的問題可以輕易想像出來。

重新审视程序

本次程序本身非常简单,仅通过SSL连接的套接字读取数据,接收Server-Sent Events的消息并进行字符串替换处理。甚至没有文件访问。

そうなると、メッセージ読み取りと文字列処理のループ箇所が臭います。

そこで、VS Code のデバッグ機能を使いステップインで1行ずつ実行を確認してみます。

玛丽、玛丽、、、玛丽、、、哎呀…

看起来,在数据没有流入的情况下,存在一个部分发生了”空循环”,即执行最快速的循环而没有进行任何处理,我对这一点表示理解,这就是为什么 CPU 使用率会达到100%。

$read = false;
while ($read === false) {
    $read = readLine($socket); // データが届いてない間は false で高速ループ
}

因此,我根据PHP的“循环处理时的CPU负载”和.NET的“避免CPU使用率达到100%的方法”作为参考,在循环的最后尝试了一个1秒的睡眠。

$read = false;
while ($read === false) {
    $read = readLine($socket);
    sleep(1);
}

这真是太有效了!使用率从100〜110%降低到了0.00〜0.01%的波动。即使睡眠只有0.5秒,负载也只达到了0.01〜0.03%左右。

在上述中,不仅限于PHP,首先我认为通过步骤执行等方法来检查循环部分,并在循环不受阻碍的范围内插入sleep是有效的。此外,作为保险措施,我认为使用docker或docker-compose的cpus选项来限制最大值更为稳妥。

引用资料

Dockerのメモリ使用量を確認したい @ Qiita

Dockerリソース使用状況の確認方法 @ Qiita

ループ処理を行った際のCPUの負荷 @ Qiita

CPU使用率100%を回避する方法 | 旧@IT会議室 @ @IT

广告
将在 10 秒后关闭
bannerAds