Linux オペレーティングシステムは、メモリが不足すると、まずメモリ回収をトリガーして他のプロセスのためにメモリを解放します。メモリ回収でメモリ不足の状態が解消されない場合、システムは Out of Memory (OOM) Killer を呼び出してプロセスを強制的に終了させます。この操作により、メモリが解放され、メモリの逼迫が緩和されます。このトピックでは、Alibaba Cloud Linux オペレーティングシステムにおける OOM Killer イベントの原因とソリューションについて説明します。
症状
以下のログスニペットは、Alibaba Cloud Linux オペレーティングシステムにおける OOM Killer イベントの例です。test プロセスが OOM Killer をトリガーしました。
565 [Sat Sep 11 12:24:42 2021] test invoked oom-killer: gfp_mask=0x62****(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), nodemask=(null), order=0, oom_score_adj=0
566 [Sat Sep 11 12:24:42 2021] test cpuset=/ mems_allowed=0
567 [Sat Sep 11 12:24:42 2021] CPU: 1 PID: 29748 Comm: test Kdump: loaded Not tainted 4.19.91-24.1.al7.x86_64 #1
568 [Sat Sep 11 12:24:42 2021] Hardware name: Alibaba Cloud Alibaba Cloud ECS, BIOS e62**** 04/01/2014
考えられる原因
OOM Killer はメモリ不足によってトリガーされます。この問題は主に、インスタンスのグローバルメモリ不足、または cgroup 内のメモリ不足という 2 つの理由で発生します。次の表では、OOM Killer イベントの一般的なシナリオと原因について説明します:
理由タイプ | シナリオ例 |
cgroup のメモリ不足 | 次のログ例では、test プロセスを含む cgroup /mm_test に対して OOM Killer がトリガーされています。 [Wed Sep 8 18:01:32 2021] test invoked oom-killer: gfp_mask=0x240****(GFP_KERNEL), nodemask=0, order=0, oom_score_adj=0
[Wed Sep 8 18:01:32 2021] Task in /mm_test killed as a result of limit of /mm_test
[Wed Sep 8 18:01:32 2021] memory: usage 204800kB, limit 204800kB, failcnt 26
原因: /mm_test cgroup のメモリ使用量が 200 MB の制限に達したため、OOM Killer がトリガーされました。 |
親 cgroup のメモリ不足 | 次のログ例では、test プロセスは cgroup /mm_test/2 に属していますが、その親 cgroup である /mm_test がメモリ制限に達したため、OOM Killer がトリガーされています。 [Fri Sep 10 16:15:14 2021] test invoked oom-killer: gfp_mask=0x240****(GFP_KERNEL), nodemask=0, order=0, oom_score_adj=0
[Fri Sep 10 16:15:14 2021] Task in /mm_test/2 killed as a result of limit of /mm_test
[Fri Sep 10 16:15:14 2021] memory: usage 204800kB, limit 204800kB, failcnt 1607
原因: 子 cgroup /mm_test/2 はメモリ制限に達していませんでしたが、親 cgroup /mm_test が 200 MB のメモリ制限に達したため、OOM Killer がトリガーされました。 |
グローバルメモリの不足 | limit of host は、インスタンスのグローバルメモリが不足していることを示します。ログは、メモリノード 0 の空きメモリ (free) が `low` ウォーターマーク (low) を下回ったことを示しています。
[Sat Sep 11 12:24:42 2021] test invoked oom-killer: gfp_mask=0x62****(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), nodemask=(null), order=0,
[Sat Sep 11 12:24:42 2021] Task in /user.slice killed as a result of limit of host
[Sat Sep 11 12:24:42 2021] Node 0 DMA32 free:155160kB min:152412kB low:190512kB high:228612kB
[Sat Sep 11 12:24:42 2021] Node 0 Normal free:46592kB min:46712kB low:58388kB high:70064kB
原因: インスタンスの空きメモリが `low` ウォーターマークを下回り、メモリ回収でメモリ不足を解消できなかったため、OOM Killer がトリガーされました。 |
メモリノードのメモリ不足 | 次のログ例では、いくつかの主要な行が問題を示しています: limit of host は、メモリノードのメモリが不足したことを示します。
インスタンスには、ノード 0 とノード 1 の 2 つのメモリノードがあります。 ノード 1 の空きメモリ (free) は、その `low` ウォーターマーク (low) を下回っています。 インスタンスには、まだ大量の合計空きメモリ (free:4111496) があります。
[Sat Sep 11 09:46:24 2021] main invoked oom-killer: gfp_mask=0x62****(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), nodemask=(null), order=0, oom_score_adj=0
[Sat Sep 11 09:46:24 2021] main cpuset=mm_cpuset mems_allowed=1
[Sat Sep 11 09:46:24 2021] Task in / killed as a result of limit of host
[Sat Sep 11 09:46:24 2021] Mem-Info:
[Sat Sep 11 09:46:24 2021] active_anon:172 inactive_anon:4518735 isolated_anon:
free:4111496 free_pcp:1 free_cma:0
[Sat Sep 11 09:46:24 2021] Node 1 Normal free:43636kB min:45148kB low:441424kB high:837700kB
[Sat Sep 11 09:46:24 2021] Node 1 Normal: 856*4kB (UME) 375*8kB (UME) 183*16kB (UME) 184*32kB (UME) 87*64kB (ME) 45*128kB (UME) 16*256kB (UME) 5*512kB (UE) 14*1024kB (UME) 0 *2048kB 0*4096kB = 47560kB
[Sat Sep 11 09:46:24 2021] Node 0 hugepages_total=360 hugepages_free=360 hugepages_surp=0 hugepages_size=1048576kB
[Sat Sep 11 09:46:24 2021] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
[Sat Sep 11 09:46:24 2021] Node 1 hugepages_total=360 hugepages_free=360 hugepages_surp=0 hugepages_size=1048576kB
[Sat Sep 11 09:46:25 2021] Node 1 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
原因: 非均一メモリ アクセス (NUMA) アーキテクチャでは、オペレーティングシステムは複数のメモリノードを持つことができます。cat /proc/buddyinfo コマンドを実行して、ノードに関する情報を表示できます。インスタンスに全体として十分な空きメモリがあっても、cpuset.mems パラメーターによって cgroup が特定のノードのメモリのみを使用するように制限されている場合、OOM Killer がトリガーされる可能性があります。 |
メモリの断片化によるバディシステムのメモリ不足 | 以下は、OOM Killer シナリオのログレコードの分析です: OOM Killer は order=3 のメモリ割り当て段階でトリガーされました。 メモリノード 0 の空きメモリ (free) は、まだ `low` ウォーターマーク (low) を上回っています。 メモリノード 0 のバディシステムには、必要なサイズ (0*32kB (M)) の利用可能なメモリブロックがありません。
[Sat Sep 11 15:22:46 2021] insmod invoked oom-killer: gfp_mask=0x60****(GFP_KERNEL), nodemask=(null), order=3, oom_score_adj=0
[Sat Sep 11 15:22:46 2021] insmod cpuset=/ mems_allowed=0
[Sat Sep 11 15:22:46 2021] Task in /user.slice killed as a result of limit of host
[Sat Sep 11 15:22:46 2021] Node 0 Normal free:23500kB min:15892kB low:19864kB high:23836kB active_anon:308kB inactive_anon:194492kB active_file:384kB inactive_file:420kB unevi ctable:0kB writepending:464kB present:917504kB managed:852784kB mlocked:0kB kernel_stack:2928kB pagetables:9188kB bounce:0kB
[Sat Sep 11 15:22:46 2021] Node 0 Normal: 1325*4kB (UME) 966*8kB (UME) 675*16kB (UME) 0*32kB (M) 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB =
理由: メモリ割り当てプロセス中にバディシステムのメモリが不足した場合、オペレーティングシステムは OOM Killer を呼び出してバディシステムのためにメモリを解放します。
説明 Linux のバディシステムは、メモリ管理のためのカーネルメカニズムです。メモリの断片化を軽減し、さまざまなサイズのメモリブロックを効率的に割り当て、割り当て解除します。 |
ソリューション
特定された OOM Killer のシナリオに基づいて、以下の手順に従って問題をトラブルシューティングし、解決します。
子または親 cgroup のメモリ不足
インスタンスでメモリを消費しているプロセスを評価し、不要なプロセスを終了させてメモリを解放します。ワークロードがより多くのメモリを必要とする場合は、インスタンスをスペックアップしてメモリ容量を増やすことができます。
インスタンスをスペックアップします。
詳細については、「インスタンス構成変更の概要」をご参照ください。
cgroup のメモリ制限を、実際のメモリ増加に合わせて手動で調整します。
sudo bash -c 'echo <value> > /sys/fs/cgroup/memory/<cgroup_name>/memory.limit_in_bytes'
<value> を cgroup の新しいメモリ制限 (バイト単位) に、<cgroup_name> をご利用の cgroup の名前に置き換えます。
グローバルメモリの不足
グローバルメモリが不足している場合は、次の領域を調査します:
`slab_unreclaimable` のメモリ使用量を確認します。
cat /proc/meminfo | grep "SUnreclaim"
`slab_unreclaimable` は、システムが回収できないメモリです。合計メモリの 10% 以上を占める場合、slab メモリリークを示している可能性があります。メモリリークが疑われる場合は、手動でトラブルシューティングを行います。詳細については、「インスタンスの slab_unreclaimable メモリの割合が高い場合の対処方法」をご参照ください。問題が解決しない場合は、チケットを送信してテクニカルサポートを依頼してください。
`systemd` のメモリ使用量を確認します。
cat /proc/1/status | grep "RssAnon"
カーネルが OOM Killer をトリガーするとき、プロセス 1 (`systemd`) はスキップされます。したがって、`systemd` のメモリ使用量は通常 200 MB を超えるべきではありません。異常に高い使用量が観察された場合は、`systemd` ツールを新しいバージョンに更新してみてください。
Transparent Huge Pages (THP) のパフォーマンスを表示します。
THP を有効にするとメモリの肥大化が発生し、OOM Killer イベントにつながる可能性があります。THP を調整してこの問題を軽減できます。詳細については、「Alibaba Cloud Linux で THP を使用してパフォーマンスを調整する方法」をご参照ください。
メモリノードのメモリ不足
特定のメモリノードのメモリ不足によって引き起こされる OOM Killer イベントを解決するには、cpuset.mems インターフェイスを再構成して、cgroup が他の利用可能なノードのメモリを使用できるようにします。
次のコマンドを実行して、システム内のメモリノードをカウントします。
cat /proc/buddyinfo
cpuset.mems インターフェイスを構成します。
sudo bash -c 'echo <value> > /sys/fs/cgroup/cpuset/<cgroup_name>/cpuset.mems'
<value> を対応するメモリノード番号に、<cgroup_name> をご利用の cgroup の名前に置き換えます。
たとえば、システムに 3 つのノード (ノード 0、ノード 1、ノード 2) があり、cgroup がノード 0 とノード 2 のメモリを使用するようにしたい場合は、<value> を0,2 に設定します。
メモリの断片化によるバディシステムのメモリ不足
メモリの断片化によって引き起こされる OOM Killer イベントを解決するには、オフピーク時にメモリコンパクションを実行します。メモリコンパクションを開始するには、次のコマンドを実行します:
sudo bash -c 'echo 1 > /proc/sys/vm/compact_memory'