Ember-cliのビルドメモリ使用量が最小インスタンスサイズで失敗する(OOM)リスク

アップグレード中、メモリ(RAM+swap)に最も大きな負荷がかかるのは、‘ember’ プロセスが実行されているときです。アップデートを実行するたびに以前よりも大きくなっているように思われ、推奨最小サイズのコンピューターで実行できなくなる寸前まで来ています。

実際に失敗する前に、この問題について調査することをお勧めします。(コストの理由から、推奨最小サイズを増やすという回答にならないことを願っています。ディスク容量が許せば、スワップを増やすことで改善されるでしょう。原理的には、より高価な大容量RAMインスタンスに一時的に移行することも可能です。)

私は小規模なインスタンスで2つの適度なサイズのフォーラムを実行しています。どちらも推奨最小値内にあると信じています。どちらの場合も、RAM+swap=3Gです。一方は1G RAMと2GスワップのDigital Oceanインスタンス、もう一方は2G RAMと1GスワップのHetznerインスタンスです。

以下は、DOマシンで ps auxc を使用した ember プロセスの3つのスナップショットです。

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 87.7 65.1 32930460 657936 ?     Rl   16:57   2:23 ember

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 84.9 60.7 43572204 612668 ?     Rl   16:57   2:57 ember

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 81.2 55.2 43405220 557128 ?     Rl   16:57   3:40 ember

明らかに、43GBのプロセスサイズ全体が仮想メモリに存在するわけではありません。利用可能なのは3Gだけです。RSSのRAMサイズの65%を使用するのは印象的ですが、それ自体は問題ではありません。空きメモリと空きスワップの量は、マシンがメモリ不足(OOM)状態に近づいていることを示しており、これはおそらく何らかのプロセスが終了され、アップデートが不体裁に終わる結果となるでしょう。

以下は、ある時点での free のスナップショットです。

# free
              total        used        free      shared  buff/cache   available
Mem:        1009140      863552       72768        6224       72820       34868
Swap:       2097144     1160628      936516

失敗に最も近い状況を捉えようと、vmstat 5 を使用しました。

# vmstat 5 5
procs -----------memory----------    ---swap-- -----io----  -system-- ------cpu-----
 r  b   swpd    free   buff  cache    si    so    bi    bo   in    cs us sy id wa st
 3  0 1392140  61200  11632  76432    41    32   117    93    0     1  2  1 97  0  0
 1  1 1467220  63416    324  67284  8786 20499 13178 20567 2539  8924 77 13  0 10  0
 0  2 1593340  57916   1096  53832 24262 46868 29986 46889 5377 18534 44 22  0 34  0
 4  0 1155632 120680   2772  86280 39111 35424 54768 37824 6987 25174 38 27  0 35  0
 3  0 1102988  74096   2852  85276 11261   246 12610   271 1879  6365 86  6  0  8  0

多くのコンテキストスイッチ(cs)、多くのディスクアクティビティ(bi、bo)、そして多くのスワップアクティビティ(si、so)に気づくでしょう。しかし、最も重要なのは、スワップ使用量が1.6Gに達し、空きメモリが60Mに減少し、バッファ使用量が54Mしかないことです。これは、利用可能な3Gの仮想メモリの約2.6Gが使用されていることを意味します。これは容量の87%です。(5秒ごとにサンプリングしているため、実際にはもう少し悪いかもしれません。)

8月にアップデートした際、状況は(2G使用時で、今日はそれほどクリティカルではなかった)心配なものでした。

# vmstat 5 5
procs -----------memory----------    ---swap-- -----io----  -system-- ------cpu-----
 r  b    swpd   free   buff  cache    si    so    bi    bo   in    cs us sy id wa st
 3  0  700404  62740   1956  48748    35    29   108    92    3     8  2  1 96  0  1
 1  0  741000  65996   1880  44360  3708 11190  3982 11191  643  1437 92  4  0  3  1
 1  0  834836  70452   1480  53856   528 18969  4274 18974  532  1575 93  6  0  1  0
 4  1 1010144  82192   4644  44400 30065 38803 35455 39946 4432 19267 28 26  0 39  7
 1  0  644116 307764   1644  55348 24406 21154 27724 21945 2551  8672 52 22  0 21  6
「いいね!」 4

こんにちは、@Ed_S さん。これらのテストでは、どのバージョンの Discourse を使用していましたか? ember-cli とそのアドオンは定期的に更新しているため、同じものを参照していることを確認したいと思います。

また、VM の CPU コア数はいくつですか? 1 つですか? (コンソールで lscpu を実行して確認できます)

全員が同じデータで作業できるように、以下を実行してみてください。

/var/discourse/launcher enter app
cd /var/www/discourse/app/assets/javascripts/discourse
apt-get update && apt-get install time
NODE_OPTIONS='--max-old-space-size=2048' /usr/bin/time -v yarn ember build -prod

私のテスト用ドロップレット (CPU 1、RAM 1GB、スワップ 2GB) では、次のようになります。

Command being timed: "yarn ember build -prod"
	User time (seconds): 369.74
	System time (seconds): 22.62
	Percent of CPU this job got: 81%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 8:02.73
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 774912
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 253770
	Minor (reclaiming a frame) page faults: 1158920
	Voluntary context switches: 519269
	Involuntary context switches: 383328
	Swaps: 0
	File system inputs: 7521784
	File system outputs: 316304
	Socket messages sent: 0
	Socket messages received: 0
	Signals delivered: 0
	Page size (bytes): 4096
	Exit status: 0

ここでは非常に標準的な ember ツールを使用しているため、メモリ使用量を削減するための設定という点では、あまりできることはないと思います。長期的な目標は、Embroider を使用することです。これにより、より多くの選択肢が得られる可能性があります。

「いいね!」 1

@david 様、ありがとうございます。Ember がそれ自体で一つのものであることを理解しました。

これらのコマンドを実行しました。

# /var/discourse/launcher enter app
x86_64 アーキテクチャが検出されました。

警告: Discourse のベースイメージのダウンロードを開始します。
このプロセスは、ネットワーク速度によって数分から1時間かかる場合があります。

しばらくお待ちください。

2.0.20220720-0049: discourse/base からプルしています
ダイジェスト: sha256:7ff397003c78b64c9131726756014710e2e67568fbc88daad846d2b368a02364
ステータス: discourse/base:2.0.20220720-0049 の新しいイメージをダウンロードしました
docker.io/discourse/base:2.0.20220720-0049

これは本番環境のインストールなので、昨日までは最新の状態でした。現在、以下のバージョンが表示されています。

インストール済み 2.9.0.beta12 (8f5936871c)

これはシングルCPUインスタンスで、 yours と同様に RAM は 1G、スワップは 2G です。

time コマンドの結果は以下の通りです。

完了まで 303.21 秒。

    実行中のコマンド: "yarn ember build -prod"
    ユーザー時間 (秒): 222.71
    システム時間 (秒): 17.17
    このジョブが取得した CPU の割合: 78%
    経過時間 (壁時計時間) (h:mm:ss または m:ss): 5:04.15
    平均共有テキストサイズ (キロバイト): 0
    平均非共有データサイズ (キロバイト): 0
    平均スタックサイズ (キロバイト): 0
    平均合計サイズ (キロバイト): 0
    最大常駐セットサイズ (キロバイト): 702292
    平均常駐セットサイズ (キロバイト): 0
    メジャー (I/O を必要とする) ページフォルト: 348190
    マイナー (フレームの再要求) ページフォルト: 1152689
    自発的コンテキストスイッチ: 617736
    非自発的コンテキストスイッチ: 774189
    スワップ: 0
    ファイルシステム入力: 5001936
    ファイルシステム出力: 318280
    ソケットメッセージ送信: 0
    ソケットメッセージ受信: 0
    配信されたシグナル: 0
    ページサイズ (バイト): 4096
    終了ステータス: 0

直前に、ホストを更新して再起動したので、コンテナ内のすべてが新しく再起動されたはずです。

別のウィンドウで実行していた vmstat が報告したメモリ使用量の最悪の値は次のとおりです。

# vmstat 1
プロセッサ  -----------メモリ----------    ---スワップ--  -----I/O----   -システム------CPU-----
 r  b    swpd   free   buff  cache    si     so    bi     bo    in    cs us sy id wa st
 2  0  704000 136044  24136 158144  1517   3503  8256   4377   886  3564 43  8 43  6  0
...
 5  0 1451436  71604   1248  50196 55016 110236 73204 121060 13152 45971 29 60  0 10  1
「いいね!」 2

Nodeの許容ヒープを500Mから2Gに明示的に増やしたようですが、これはやりすぎで、1.5Gの方が良いかもしれません。

Emberはマシン上で実行されている唯一のものではなく、RAM+swapのグローバルリミットに達していることに注意することが重要です。そのため、マシンの履歴と他のすべての実行中のプロセスのニーズが関係してきます。私の再起動は、昨日と比較して低い最高値を達成するのに役立った可能性があります。

上記のプルリクエストは、
Failed to upgrade discourse instance to Feb 15 2022
で参照されており、そこでも再起動によって解決されたメモリ不足があったことを指摘しています。

timeコマンドがピークメモリ使用量を報告しないのは残念です。おそらく、RAMが3G以上でスワップがないマシンでは、RSSカウントがEmberのピーク使用量を教えてくれるでしょう。あるいは、別の戦術を使用することもできます。いくつかの戦術がここに概説されており、ここにもいくつかのアイデアがあります。

厄介なのは、多くの人がRAM使用量に関心を持っているのに対し、私たちは実際にメモリ使用量に関心があることです。これは異なる問題です。

「いいね!」 3

このフラグを追加した理由は、Node自体のOOM killerがビルドを終了させていたためです。500Mでは不十分でした。1.5Gに調整してみることは喜んで行います。実際に私のドロップレットで試したところ、問題なく動作しているようです。実際、1.0Gでも十分なようです。

max_heapサイズを変更してメモリ使用量を追跡してみました。

(while(true); do (free -m -t | grep Total | awk '{print $3}') && sleep 0.5; done) | tee 1000mb.csv

ビルド中の使用量は以下のようになります。

ビルド時間にはほとんど差がありませんでしたが、1GBと1.5GBの制限では全体的な使用量が明らかに少なくなります。予想通り、timeの出力では、ノードの制限が低い場合に「Major page faults」が大幅に少なくなっています。

1.5GBと1GBの違いがこれほど小さいのは興味深いですね。:face_with_monocle:

いずれにせよ、制限を減らすことは良い考えだと思います。高スペックのマシンでのビルドパフォーマンスに影響を与えないようにするため、制限が高すぎる場合にのみ上書きし、それ以外の場合はNodeのデフォルトを使用できるようにすべきだと思います。

こちらがPRです。近いうちにマージされるようにします。@Ed_S、提起していただきありがとうございます!

「いいね!」 4

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.