はじめに
私はn8nを、セルフホストでGCPの仮想端末に立てています。そこそこ使っていて、立て方とかバージョンアップとか、いくつか記事を書いていますが、今回は落ちた話です。
落ちたことは、毎日実行されてスマホのSlackに通知しているものが、ある日から来なくなって気づきました。(ごみの日の連絡ですw)
ごみの日の連絡は落ちるようなワークフローではなくチョロなんですが、でっかいのがいるのでアイツが悪さをしてなんかなってるなーと思って調べ始めました。
VMのスペック
e2-micro(2個の vCPU, 1GBのメモリ)
原因
結果的に、n8nのプロセスが"1GBのメモリ"を大量に使用し、OOM(Out Of Memory)でkill(強制終了)されたということでした。
落ちたときの状況はこんな感じ。
- インスタンスのメモリが合計955MBで、スワップなし
- n8n以外に、OSやその他プロセスで、常時350MBくらいは使っている
- n8nが500~600MBのメモリを使うとフルになって、OOM killer登場
- n8n v2.27はタスクランナー(N8N_RUNNERS_ENABLED=trueで別プロセス)+アクティブなワークフロー13個で、ピーク時に500MB超を消費し、メモリを使い切ってkillされている。
- 補足: database.sqliteが294MBまで肥大化しており、起動時のDBタイムアウトやメモリ圧迫の一因になっている可能性があり(プルーニングは336時間=14日設定済み)。
詳細
エラーになっていたワークフローの大きさは、ノードの数が100~150個くらいです。確かに個人で使うにしては大きくて、その理由は、ある処理パターンをコピペで類似のものをいくつも作ったからです。Aサイト用、Bサイト用、といった具合に。
n8nは実際に走らせてみると、パラレルに実行できる場面でも1つずつ実行していたので、まぁいいかくらいに思ってました。
メモリ的には、各ノードのINとOUTを保持してるので、100個もあればまー重いかもしれないけどテキストだし、と思ってました。(それは今もそう思ってるけど)
対策
対策1:スワップ
ひとまず、メモリ不足なので2GBのスワップファイルを作成しました。
スワップとは、メモリが足りなくなった時、メモリ上のデータの一部をディスクに退避させてメモリを空ける仕組みです。それが発生すると、当然遅くなりますが、落ちにくくはなります。
その状態でメモリの使用状況を見ながら実行させてみると、無事完走。メモリの最大使用時は、571MBを使用。(落ちた時より多かった)
で、ここがポイントなんですが、メモリの使用状況がマックスになったのは、全部終わった直後でした。
つまり、ワークフローの終了処理として、DBに書き込んだりログに書いたりするときに、実行したノードが多いとメモリに負荷が多くかかるということでした。
とすると、本対策としてできることは、、、
- メモリが多いマシンに変更する
- スワップファイルを設定したのでこれで様子見
- ワークフローを小さくする
という感じでしょうか。
「メモリが多いマシンに変更する」については、天井(デッドライン)が高くなるわけですが、実際はピークのときにしか使わず、元々セーフだった部分は無駄に高い天井。コスパが悪いですよね。
「スワップファイルを設定したのでこれで様子見」については、まぁそれもありかもしれない。空きディスクが多いし。まぁスワップファイルは設定したままにしておきます。
「ワークフローを小さくする」。単純ですが、ワークフローが肥大している原因は、コピペで増えたことであって、それを分割することは容易でした。1つのワークフローである理由はあまりなく、同じ処理だからグルーピングしておきたい、くらい。なのでこれが本命。
対策2(本命):ワークフローを小さくする
ワークフローを1/3ずつくらいに分解して、念のため実行時刻も少しずらしておきました。
それで解消。(本命のくせに、細かく書くことがない)
今この状態で1週間くらい様子を見て、正常に動いてくれています。
おわりに
n8nのセルフホストは、SaaSよりは安くできますが、やっぱり手がかかる。Qiitaを見るような、私のこの内容を読むような人は、手がかかるのも面白いと思えるかもしれませんが、万人受けはしません。非エンジニアならなおさらやってはいけないと思いました。エンジニアが非エンジニア(お客様)に作って環境を渡す、ということもしないほうがいいかも。n8nのアップデートもしないといけないし。
私はこういう作業が嫌いではありませんが、n8nを忘れたころに何か起こるので、実はめんどくさいです。脳メモリが小さいYO!🤣
ではよきワークフローライフを!
