2020/10 サーバのメモリ増加調査
本番サーバのメモリ量が90%を超えて正常に動作しなくなることがありました。 なぜ90%まで増えるのか原因を突き止めるのに苦労したので紹介します。
現象
- サーバ起動時のメモリ使用量は5〜10%程度
- 1〜6ヶ月で緩やかに上昇し75%程度に
- 90%ぐらいからout of memoryが起きる
- するとPHPがメモリ確保できなくなる
- そしてサーバエラー、DB接続エラーとなりサイトが表示されない
なぜ気づかなかったか
- 3〜6ヶ月かけて上昇したと思ったら、40%程度に減ることもあった
- 頻繁にリリースすることがありリセットされてた
- 年に1回程度発生していたがアラートで事前検知し再起動していたので重要視していなかった
そんな中、メモリアラート閾値ギリギリのところで、BOTからのアクセスが増え一気にメモリが90%になりサイトが表示されない現象が起きてしましました。
調査
原因にたどり着くまで紆余曲折を経たので、時系列順に調べた内容を紹介します。
1. Laravel
まずはフレームワークのLaravelでメモリリークが発生するケースがないかググりました。 しかし、Laravelについてはメモリリーク事例記事のようなものは一切見当たりませんでした。
比較的新しく、その上人気のあるフレームワークだけあって優秀なんだと感心しました。
2. PHP
次は、Laravel同様にPHPについてググり、php-fpmの設定にたどり着きました。 本サーバでは前段にNginxを使っておりLaravelとの接続にphp-fpmを利用しているので、可能性はありました。
php-fpmの設定について
- 起動プロセス最大数
- プロセスを再起動する設定
の2点が怪しかったのですが、適切な設定がされており問題はありませんでした。
また、この調査から例えLaravelや自分達が実装した処理でメモリリークが起きていたとしても、php-fpmは設定されたリクエスト数に達するとプロセスを再起動するのでメモリは解放され、今回のような問題にはならないことがわかりました。
3. Slab
アプリ内に問題が見当たらないため、CPUやメモリの使用状況を確認できるtop
コマンドで、メモリを食いつぶいているプロセス(PHP含め)調べてみましたが問題は見当たりませんでした。
KiB Mem : 8009032 total, 227704 free, 849640 used, 6931688 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 6603212 avail Mem
途方に暮れている折、CloudWatchで取得しているメモリ使用割合をtop
コマンドのメモリ使用割合が大きく食い違っていることに気付きました。
つまり、topコマンドでは確認したかったメモリ使用状況を表せていない可能性が出てきました。
そして、/proc/meminfo
もメモリ使用状況を確認できることがわかり、確認してみると使用割合がCloudWatch同様にメモリが逼迫している結果となり、/proc/meminfo
を使えば本現象を計測できることを突き止めました。
Slab: 5027188 kB
SReclaimable: 5003208 kB
SUnreclaim: 23980 kB
さらに/proc/meminfo
の出力項目を精査するとSlab
値が大きく占有していることがわかりました。
原因
Slabキャッシュとは、スラブアロケータで使用される物理メモリで、カーネルが使用するキャッシュ機構でした。ググると少しづつ圧迫されているという事例記事が色々見つかりました。
- バージョンによってcurlやhttpsするとSlabが溜まる事例
- AWS SDKがcurlかhttpsを使っていてSlabが溜まる事例
本サーバはCloudSearchと連携するためにAWS SDKを利用していたので、AWS SDKが直接の原因である可能性が強くなってきました。
対処
サービスの性質上CloudSearch連携もAWS SDK利用も止めるわけにはいきません。 そこで、Slabキャッシュの解放コマンドを試したところ、一気にメモリ使用量は減りました。
> /bin/echo 2 > /proc/sys/vm/drop_caches
1日1回、CRONで解放コマンドを実施することで上記の画像のように、メモリ増加は発生しなくなり問題は解決しました。
本調査から
- php-fpmプロセス再起動
- /proc/meminfo
- Slabキャッシュ
を学ぶことができました。 もし似たような現象が発生した際には参考にしていただければと思います。