inspectorを使わずにNode.jsのメモリリークを見つけて修正した
productionサーバーでしか発生しないメモリリークを、当たりをつけて(力技で)調査する方法を確立したshokai.icon
事例:Cosenseのweb dynoのメモリ使用量が爆発してるけどなぜかなんともない
普通のnodeのプログラムならnode:inspectorで覗くのが良いのだが
無理だった
node:inspectorが使えない理由
productionで雑にinspectorを有効化するわけにはいかない。性能が大きく下がるから
scrapbox.ioでしかメモリリークが発生していない
Cosenseは他にもセミオンプレ等のproduction環境があるが、そちらでは問題発生していない
productionに来ているリクエストをミラーリングしたり、ごく一部だけ調査用環境に流すような事はできない
Herokuなので
一時的にinspectorを起動したり、メモリダンプを出力したりする隠しAPIを用意する?
dynoを指定して外部から隠しAPIを叩くのは難しい。Herokuなので
メモリ使用量を自己点検し続け、既定値を超えていたらheap snapshotを出力するという方法
これはアリかもしれない。次回に向けて検討したいshokai.icon
理解する
メモリリークと、ただメモリ使用量が多いだけの処理は別である
--max-old-space-sizeがメモリ使用量をコントロールするパラメータではない事を、あらためて調べ直して納得しておく
Node.jsはHeroku dynoに搭載されているメモリ量を誤認しているなど、制御できないものは制御できない、ただし性質や法則はある、と理解する
力技で雑念を払う
怪しい所のうち、ぱっと直せそうな所をさっさと潰して覚悟を決める
HerokuでCluster modeのnode.jsプロセスを起動するとそれぞれがメモリを手加減なしに使おうとするので--max-old-space-sizeの指定が必須
NewRelic 12が原因でCosenseのメモリ使用量が増えてるわけではなかった
Cosenseのexpressを4から5に更新する
かなり血迷っているshokai.icon
あらためて的を絞る
全てのプロセスでメモリリークが発生しているわけではない
メモリ使用量のaverageとmaxに差がある事からわかる
HTTPリクエストの負荷はかなり分散する
ただし例外はある
クソデカJSONやクソデカCSVをexportするクソデカAPI
接続しっぱなしになるsocket.io
平日休日や昼夜など、アクセスパターンの違う時間帯を観察する
ビジネスユーザーの少ない土日の、しかも人間が少ない夜間に、時間経過に対して綺麗な右肩上がりでメモリ使用量が増えている事がわかった
https://scrapbox.io/files/69256e1485112c87a9821acf.png
平均が綺麗に上がっていっている
maxは階段状に上がっていっている
これが大きなヒントになったshokai.icon
リークの原因は人間ではなくbotやbatch処理によるもので、しかも、project毎にレスポンスサイズが大きく異なる機能なのではないか?と推測
あらためて力技でコードを読んでいく
データエクスポートするAPIを1つずつ調べる
それ以外も、思いつく限り全て調べてもらった
プログラム全体を調べるのはキリが無いのと、やり直すたびにslack通知の中の配列にめちゃくちゃ注目してしまうので、しっかりAPIを指示して調べさせる
どんどん直す
https://scrapbox.io/files/69256e1010003d6d446b0eee.png
https://scrapbox.io/files/69256e0e278303d6f77e5040.png
詳しくはscrapbox.ioのみ時間経過でメモリ使用量が増加する原因を、Codex CLIとともに探るを読んだ方がいいshokai.icon
ここまで10日ぐらいで完了
効果の検証
それぞれ観察する
夜間、人間がおらず、botやbatch処理のみが来ている状況
昼間、人間がいる状況
途中でサーバーをリスタートしてしまうとメモリ使用量もリセットされてしまう
詳しくはCosenseのweb dynoのメモリ使用量が爆発してるけどなぜかなんともないへ