GlintエコGlintエコでは最近、クライアントのFlaskアプリケーションが断続的に停止するという不可解な運用上の問題に直面しました。すべてのサービスが稼働しており、一見ログにもエラーが表示されていませんでした。徹底的な調査の結果、重大な問題を発見しました。

RuntimeError: reentrant call inside <_io.BufferedWriter name=''>

この記事では、以下について説明します。

  • 原因
     

  • デバッグ方法
     

  • 適用した修正
     

  • Gunicorn + ログを使用したPythonを使用するチームにとっての重要なポイント

問題

クライアントの設定は非常に一般的でした。

  • Gunicornの後ろで実行されているFlaskアプリケーション
     

  • ロードバランサーの後ろにある2台のサーバーにデプロイ
     

  • New Relicモニタリングのインストール
     

  • Gunicornバージョン:20.0.1
     

  • Pythonバージョン:3.6

突然、ユーザーからサイトへのアクセスが断続的であるという報告が届き始めました。しかし、システムメトリックはCPUとメモリの使用率が正常であることを示していました。プロセスは稼働していました。stderrでこのエラーを確認するまで、意味が分かりませんでした。

RuntimeError: reentrant call inside <_io.BufferedWriter name=''>
Worker with pid 12345 was terminated due to signal 9

問題のデバッグ

このバグは追跡が困難でした。調査を通じて学んだことは次のとおりです。

  • このエラーはGunicornのログ機構、特に複数のワーカープロセスが同時にstderrに書き込もうとした場合に関連しています。
     

  • これは、再帰的なログ記録によってクラッシュが発生する可能性のある古いバージョンのGunicornで知られている問題です。
     

  • シグナル9(SIGKILL)は、ワーカープロセスがシステムによって強制的にキルされたことを意味します。ログのデッドロックやメモリの枯渇が原因である可能性があります。

私たちは確認しました。

修正:段階的なアップグレード

最新バージョンにすぐにジャンプしませんでした。代わりに、安全なアップグレードプロセスに従いました。

  1. Gunicornを21.2.0にアップグレードしました。コミュニティがこのバージョンで多くのログの問題が解決されたことを確認したためです。
     

  2. 数日間システムを監視しました。エラーは消え、システムは再び安定しました。
     

  3. 安定性を確認した後、最新安定版であるGunicorn 23.0.0に移行しました。
     

  4. また、パフォーマンスと互換性を向上させるために、Pythonを3.10に更新しました。

それ以降、問題は発生していません。

追加の修正(オプションですが推奨)

  • Pythonでlogging.StreamHandler(sys.stdout)を使用して、直接stderrへのログ記録を適切なログハンドラーに置き換えました。
     

  • ピーク時間帯の同時実行性を制限するために、Gunicornワーカーの数をわずかに減らしました。
     

  • N個のリクエスト後にワーカーをリサイクルするために、Gunicornでmax_requests設定を追加しました。

gunicorn app:app --workers=4 --max-requests=1000 --max-requests-jitter=100

重要なポイント

  • Gunicorn < 20.1はもはや本番環境では安全ではありません。できるだけ早くアップグレードしてください。
     

  • ログは、正しく構成されていない場合、アプリケーションをサイレントにキルする可能性があります。
     

  • アプリケーションログが正常に見えても、常にstderrとワーカーシグナルを監視してください。
     

  • 安全なアップグレードパスに従い、重要な依存関係のGitHubの問題または変更ログを購読してください。

結論

この問題は、Gunicornのような成熟したライブラリでさえ、アクティブなメンテナンスと監視が必要であることを思い出させてくれました。Glintエコでは、クライアントがアプリケーションを構築するだけでなく、安全に実行およびスケーリングするのを支援しています。

Flask/Djangoアプリケーションで奇妙な動作が発生している場合、またはデプロイメントパイプラインについてセカンドオピニオンが必要な場合は、お問い合わせください。私たちも同じ経験をしています。