これ何
今日お昼ご飯食べられなかったので。
何が起ったの
午前中画像とかアップロードできなくなった。
原因は
tomcat上で運用されているSpring Bootのサーバでtempが溢れた。
問題の説明
tomcatにはデフォルトで動的に書き込まれるディレクトリが2つあります。
一つは logs
、もう一つは temp
。
workやwebappsも動的といえば動的だけどある程度以上膨れることはないので除外します。
logs
はアプリケーションのログ(catalina.out) とかアクセスログ(access_log.txt)とかもろもろ吐かれるところ。
1日に1回程度cronか、log appenderによるローテーションがかかるように設定するのがセオリー。
temp
はjavaのテンポラリディレクトリのことで、tomcatではデフォルトここに置かれるというもの。
さまざまなライブラリが一時保存先として利用している。
つまり、javaをつるしで起動すると /tmp
になるし、tomcat上でなにもしないと $TOMCAT_HOME/temp
になる。変更可能。
問題はこの一時保存のファイルのライフサイクルにあります。
ここで作ったファイルのライフサイクルはアプリケーションに依存しており、ルールとしては、強いていえばテンポラリファイルを使ったら消しておこうねくらいの勢いであるため、消されずにそのままにしてしまうことがたまにある。
ただ、javaのvm終了時にまとめて消すとかいう File.deleteOnExit()
というのもあるんですが、どうやら今回はこれを使っていても、208日間連続起動というちょっとびっくりな時間起動しているtomcatであったため、仮にこの実装をやっていても意味はなかった。
なので、tomcatに限らずjavaのプログラムだと意図して消すような対策をとっていなければ、消さない限りは残り続ける仕様です。
では、消さないと何が起こるか・・・そう、Disk Fullである。
問題点
画像ファイルのアップロードは近年大きいと10MiBの写真がぽいぽい投げられるのが普通になっており、一昔前の写メールかっこわらいのノリでいると痛い目を見る。
dockerのコンテナとかデフォルトでは20GBしかファイルシステム割り当てられないので、デプロイせずに連続稼働しているとヤバいことになるケースもあると思うし、サードパーリー製の某みたいなのは頻繁にテンポラリファイルを生成しては消ししているのでお気をつけ遊ばせ!
今回は 80GiBを200日くらいで使い潰したので、約0.4Gib/dayで増えていったんですね・・
昔私もやったことあるから直接は言わなかったですが、政治的な事情で申し上げることができないことがいくつかあったのでここでいいます!!
アプリケーション側の問題点は下記の2つ。
- 使い終わった一時保存として書き込んだファイルが放置されているか先述のvm依存になっている
- ファイルが書き込めなかった時のエラーハンドリングが雑
- DBに行が残り、ファイルの実体がない状態
インフラ側の問題点
- ディスクフルを検出できなかった
対策は?
政治的な事情もあるので月1でインスタンスをローテーションしましょう、です。
障害対策を完走した感想
古傷を抉られるのは誰しも痛いもので、この件に関しては私は優しかったと思います。
参照
File.deleteOnExit() の詳細はこちら。
https://stackoverflow.com/questions/16691437/when-are-java-temporary-files-deleted
Javaのテンポラリフォルダの説明など
https://codechacha.com/ja/java-get-temp-dir/