【EC2 – ELB】ヘルスチェック失敗の原因と対策: OOM と Swap

Blog-Thumbnail_KUDs-01 AWS

はじめに

先日、ELB がヘルスチェックに失敗し、EC2 インスタンスが終了・新規作成されました。
まず、構成は以下の通りです。

draw.io「AWS 2d architecture for KUDs Blog WordPress」
draw.io「AWS 2d architecture for KUDs Blog WordPress」

こちらは、本ブログ KUDs Blog をホストしている構成です。
WordPress を使用しています。

なお、AutoScaling はシングルインスタンス構成ですので、EC2 の再作成は期待通りです。
しかし、ヘルスチェック失敗はもちろん期待通りではありません

この記事では、インスタンス再作成時のログから原因を確認します。
また、それに応じた対策を検討、実行します。

インスタンスが終了したからログが見られない!という方は、こちらの記事を参照してください。

EC2 のシステム/アプリログを CloudWatch Logs に出力する方法

こちらの記事では、システムログを CloudWatch Logs に出力する方法を記載しています。
AutoScaling を利用している場合、インスタンスが削除されてしまい、ログが確認できないことが多々あります。
ログがない状況で原因を追究するのは困難ですので、ログ退避は実装しておきましょう。

問題の概要

前述の通り、EC2 では WordPress をホストしています。
通常時には問題なく動作していました。
しかし、突如として ELB のヘルスチェックに失敗してしまいました。
そう、「何もしてないのに壊れた」のです!

ヘルスチェックとは

AWS が提供するサービスの一つで、アプリケーションが正常に応答しているかを定期的に確認します

特に、ELB のヘルスチェックは、ロードバランサーからターゲットとなるインスタンスに対して定期的にリクエストを送り、その応答に基づいてインスタンスのヘルス状態を評価します。
このヘルスチェックが失敗すると、通常はアプリケーションに何らかの問題があることを示しています。

問題の原因を特定するためには、CloudWatch メトリクスや、アプリケーションログ、システムログを詳細に確認する必要があります。

トラブルシューティングの方法については、AWS 公式の記事も参考になります。

ERROR: The request could not be satisfied

原因の特定:OOMの発生

AWS の EC2 インスタンスで発生したヘルスチェックの失敗。
まず、その原因を特定するために確認したのはシステムログです。
そして、そのログからは、OOM エラーを確認できました。
※OOM: Out Of Memory

kernel: oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/,task=httpd,pid=7981,uid=48
kernel: Out of memory: Killed process 7981 (httpd) total-vm:604720kB, anon-rss:40696kB, file-rss:0kB, shmem-rss:88kB, UID:48 pgtables:876kB oom_score_adj:0
kernel: httpd invoked oom-killer: gfp_mask=0x100cca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

OOM (Out Of Memory) とは?

OOM はシステムが物理的なメモリーを超えてメモリを消費したときに発生します。
この状況は通常、システムによって自動的に管理され、最も重要性が低いと判断されるプロセスが終了されることでメモリを解放します。

ただし、この自動的なプロセスの終了は、適切な監視とログ記録がなされていない場合、突然のアプリケーションの停止やサービスの中断を引き起こす可能性があります。

OOM について詳しく知りたい方は、kernel.org もご参照ください。

Out Of Memory Management

メモリ使用量の監視

OOM が発生した場合、最初に確認すべきはインスタンスのメモリ使用量です。

AWS の CloudWatch はデフォルトで多くのメトリクスを提供します。
しかし、残念ながらメモリ使用量はデフォルトでは含まれていません。

このため、freeコマンドやtopコマンドを使用してリアルタイムでメモリ使用量を確認したり、CloudWatch Agentを使用してメモリ使用量を定期的に監視するなどの手段が必要となります。

以下は、top コマンド実行時の結果です。

top - 05:03:06 up  2:18,  1 user,  load average: 0.00, 0.00, 0.00
Tasks: 109 total,   1 running,  65 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.3 st
KiB Mem :   975596 total,   113940 free,   772996 used,    88660 buff/cache
KiB Swap:        0 total,        0 free,        0 used.    86752 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                                                                                                           
 3332 apache    20   0  708148  78772  10428 S  0.0  8.1   0:33.51 httpd
 3084 apache    20   0  707876  78676  10428 S  0.0  8.1   0:33.41 httpd
 3340 apache    20   0  707876  78660  10428 S  0.0  8.1   0:32.90 httpd
 3621 apache    20   0  937276  78640  10584 S  0.0  8.1   0:20.39 httpd
 3614 apache    20   0  707840  78624  10584 S  0.0  8.1   0:19.77 httpd
 3634 apache    20   0  707688  78464  10436 S  0.0  8.0   0:20.78 httpd
 3635 apache    20   0  707828  78460  10436 S  0.0  8.0   0:20.93 httpd
 3323 apache    20   0  707972  78416  10428 S  0.0  8.0   0:33.07 httpd
 3339 apache    20   0  707828  78308  10428 S  0.0  8.0   0:33.66 httpd
 3314 apache    20   0  707852  78296  10428 S  0.0  8.0   0:33.13 httpd
 3167 root      24   4  641736  54932   5532 S  0.3  5.6   0:39.20 aws
 2971 root      20   0  520032  18424  11796 S  0.0  1.9   0:00.43 httpd
 3243 root      20   0  723848  10300   2940 S  0.0  1.1   0:00.28 ssm-agent-worke
 3166 root      20   0  255592   9004   3224 S  0.0  0.9   0:00.39 rsyslogd

こちらは OOM 発生時ではありませんが、メモリ使用率が高いことが確認できます。

Swap 領域もないため、いつ OOM が発生してもおかしくない状況ですね。

解決策:Swap領域の作成

メモリ不足によるOOMの発生を解決するための方法はいくつかあります。
例えば、水平 / 垂直スケーリングは常套手段です。
※インスタンスタイプをアップグレードする
※インスタンス数を増やして負荷分散する

しかし、これらの方法は追加のコストが発生します。

今回は、コストを抑えつつメモリ不足に対処するために、Swap 領域を作成します。

Swap 領域とは

Swap 領域はハードドライブの一部を仮想メモリとして利用するものです。
物理メモリが不足した場合にオペレーティングシステムが利用します。
そのため、メモリ不足という問題を緩和する手段として有効です。

しかし、物理メモリよりもアクセス速度は遅い点は注意が必要です。
頻繁にスワッピングが発生する場合、パフォーマンスは低下します。

Swap 領域の作成方法

AWS 公式の記事も参考になりますので、是非ご参照ください。

ERROR: The request could not be satisfied

Linux 系の OS の場合、次の手順で Swap 領域を作成できます。
ここでは、例として 1 GB の Swap 領域を作成します。

スワップファイルを作成

$ sudo dd if=/dev/zero of=/swapfile count=1024 bs=1M
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 15.5141 s, 69.2 MB/s

スワップファイルのパーミッションを変更

$ sudo chmod 600 /swapfile

スワップエリアを設定

$ sudo mkswap /swapfile
Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
no label, UUID=ff0be66d-a38d-4eb5-91ff-2aca65ddf2a0

スワップ有効化

$ sudo swapon /swapfile

自動マウント設定

$ echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
/swapfile swap swap defaults 0 0

スワップが正しく作成されたことを確認

$ sudo swapon --show
NAME      TYPE  SIZE USED PRIO
/swapfile file 1024M   0B   -2
$ free -h
              total        used        free      shared  buff/cache   available
Mem:           952M        758M         65M        540K        128M         60M
Swap:          1.0G          0B        1.0G

以上で、メモリが不足した場合でも Swap 領域が利用されます。
これによって、OOM の発生を回避することが可能です。

ただし、Swap 領域はあくまでメモリ不足を一時的に緩和するための手段です。

頻繁に Swap 領域が利用される場合は、パフォーマンスに影響を与えます。
そのため、その原因を特定して適切な対策をとることが重要です。

さいごに

この記事では、EC2 – ELB でのヘルスチェック失敗について調査しました。
まず、その原因が OOM (Out of Memory) であることを特定しました。
次に、Swap 領域の作成という暫定対応を実施しました。

しかし、この対策はあくまで一時的なものです。
将来的には以下のような対策も検討すべきでしょう。

  • インスタンスのメモリを増強する
    • メモリが不足しているならメモリを増強するのが常套手段です
    • ただし、インスタンスのコストが増加するデメリットがあります
  • アプリケーションの最適化
    • アプリケーションのメモリ使用量を抑えるように最適化することも一つの解決策です
    • 開発コストが発生しますが、長期的にはインフラコストを抑えることができます

アプリケーションの最適化について、 OOM を Apache / PHP の最適化で回避する記事を書きましたので、こちらも合わせてご覧ください。

【WordPress】OOM を Apache 最適化で解決!【EC2 / t2.micro】

なお、メモリ使用率やスワップ使用率については、デフォルトでは CloudWatch メトリクスで確認できません。
メモリ使用率・スワップ使用率を CloudWatch メトリクスで表示する方法については、以下の記事をご覧ください。

【EC2】メモリ使用率・スワップ使用率を CloudWatch で表示する

以上です。

コメント