AtCoderProblems
AtCoderProblems copied to clipboard
クローラーがメモリリークしてる?

クローラーのメモリ使用量を見るとリークがあるように見える。
・サーバーとかの知識に疎いんですが、これってどのくらい深刻な問題なんですか? ・未だ原因不明でしょうか?
・サーバーとかの知識に疎いんですが、これってどのくらい深刻な問題なんですか?
細かい話になってしまうのですが、AtCoder Problems のクローラーは ECS というサービスを使っていて、Docker コンテナの中で動いています。ECS では Docker コンテナ内のプロセスを監視していて、何かの原因でプロセスが落ちたりすると、自動的に Docker コンテナを再起動してくれます。ただ、メモリ使用量が多すぎる場合には ECS の監視プロセスごと死んでしまい、プロセスが Out Of Memory で死んだのに誰も何もできないという弱点があります。現状はアラートをセットしておいて、メモリを使いまくっているクローラーや応答が無くなったクローラーは僕が手動で再起動していますが、手間なのでなんとかしたいです(ただ、手動でなんとかなっているので緊急性は低いです)
・未だ原因不明でしょうか?
まだ何もやっていないので原因不明です。
調べてみました。クローラーがPgPoolを何回も作成しているのが原因かなと思います。
Poolの実体はArc<PoolInner>です。Poolを作成するとArc<PoolInner>を持ったそれのお世話をするtaskが作成されるのですが、このtaskは明示的にpool.close().awaitしない限り存在し続けて、Arc<PoolInner>の参照カウントを常に1以上にします。
クローラーの実装を見てみると、頻繁にPgPoolを作成する一方でcloseはしないのでArc<PoolInner>分のメモリが積み重なってこうなっているんじゃないか?と思いました。
実際に手元でクローラーを動かしながらtokio-consoleでタスクを監視してみると、PgPoolを作成した回数分だけtaskが増え続けるので有力かなと思います。
sqlxのリポジトリを調べてみると、issueが立っていました(https://github.com/launchbadge/sqlx/issues/2375 )。
sqlx 0.7で対策が行われているぽいので移行するか、PgPoolを一回だけ作成するよう改修を行うという対処になりそうです。
Poolのドキュメントには以下のような記述があり、sqlx的にはプログラム中で一回だけ作成されることを想定しているようでした。
PoolisSend,SyncandClone. It is intended to be created once at the start of your application/daemon/web server/etc. and then shared with all tasks throughout the process’ lifetime. How best to accomplish this depends on your program architecture. https://docs.rs/sqlx/0.6.2/sqlx/struct.Pool.html
リサーチありがとうございます!sqlx のバージョンを上げる PR を出しましたが、それとは別に Pool をシングルトン化するようなリファクタリングはやってもいいかもしれませんね。