この記事は Akatsuki Advent Calendar 2016 の15日目です。
はじめに
今やログ収集ソフトウェアのデファクトスタンダードとなったFluentdですが、オートスケール環境においては思わぬログの重複や欠損が発生する可能性があります。今回は私の所属するプロジェクトで行ったログ重複・欠損対策について紹介したいと思います。
前提
今回前提とするシステムは下図のような構成になっています。
ELB配下にオートスケーリンググループに属するEC2インスタンスのアプリサーバが複数台あり、各インスタンス上では Rails と Fluentd (sender) が動作しています。各アプリサーバから出力されたログは Fluentd (aggregator) により集約され、最終的に DB に保存されます。
Fluentd を利用したログ収集の構成としては一般的なものかと思います。
(バックエンドのDBは色々な選択肢がありますが...)
Fluentdの基本的な動作と注意点
アプリサーバ上で動作しているFluentdはRailsから出力されたログをログアグリゲータに送信しますが、送信タイミングは即時ではありません。一時的にローカルファイルとして保存してから送信を行います(以降送信バッファと呼びます)。これは、アプリサーバやFluentdが落ちたり、ログアグリゲータと通信が不能になった場合であってもログ欠損を起こさないようにするための仕組みなのですが、この送信バッファの取り扱いに気をつけないと、スケールアウト時にログを重複して送ってしまったり、スケールイン時にログを欠損させてしまったりといった問題を起こすことがあります。
スケールアウト時のログ重複送信対策
AWSのオートスケール機能は予め起動設定で指定したAMIからインスタンスを起動します。このとき、指定したAMIにFluentdの送信バッファが含まれているとログの重複送信が発生してしまいます。
送信バッファがAMIに含まれてしまう原因
AMIを作成する方法は多くありますが、この問題が起きるのは「稼働しているインスタンスからAMIを作成する場合」です。私の所属するプロジェクトではこの方法でAMIを作成しています。
(補足ですが、Chefによる Infrastructure as Code は実践しています。ただ、インフラ構築時間を短縮する等の理由により、稼働しているインスタンスからAMIを作成する運用をしているところは他にもあるのではないかと思います。)
既存インスタンスからAMIを作成する場合の送信バッファ対策
既存インスタンスからAMIを作成する場合の送信バッファによるログ重複送信を防ぐための方法としては以下の方法が考えられます。
- ログアグリゲータへの送信が終わるのを待ってからAMIを作成する
- 起動スクリプト(userdata)に送信バッファを削除する処理を入れる
1 の方法は、送信が終わる時間が読めないことや、ログアグリゲータが落ちていた場合はいつまでたってもAMI作成が開始できない可能性があるため、良い方法とは言い難いです。
2 の方法は、起動スクリプトへの変更が必要になりますが、ログの送信完了を待つ必要がなく、確実かつ即時AMIの作成を開始することができます。
今回は2の方法を採用することにしました。
起動スクリプトによる送信バッファ削除処理の詳細
まず、以下のステップでAMIを作成します。
- AMIを取得するインスタンスをELBから外す
- インスタンスにログインし、Fluentdを落とす
- 起動スクリプトによる送信バッファ削除処理が完了するより先にFluentdが立ち上がってしまわないよう、chkconfigでFluentdの自動起動をOFFにする
- AMIの作成を開始する
- AMIの作成が完了したら、インスタンスにログインしFluentdを再度起動し、chkconfigの設定を復元する
- インスタンスをELBに戻す
こうして作成したAMIをオートスケールの起動設定に登録し、起動スクリプトに送信バッファを削除する処理を追加することでスケールアウト時のログ重複送信を防ぐことができます。
(なお、上記処理はすべてスクリプトにより自動化しています。また、起動スクリプトは送信バッファの削除処理の他に、Fluentdの起動、chkconfigによる自動起動設定の復元等も併せて行う必要があります。)
スケールイン時のログ欠損対策
もう一点。スケールイン時のログ欠損対策も必要です。
スケールイン時、送信バッファが残った状態でインスタンスが終了されてしまうとログ欠損につながります。
私の所属するプロジェクトでは5分待ってからインスタンスを終了するよう設定ししのいでいますが、 Instance Lifecycle Hook を使えば、送信バッファが無くなったことを確認してからインスタンスが終了できるのではないかと考えています。
(まだ着手できていません...)
最後に
オートスケール環境におけるFluentdのログ重複・欠損対策、特に送信バッファの取り扱いについて紹介させていただきました。今回はFluentdが対象でしたが、これ以外にも遅延送信(処理)を行うソフトウェアには同様の注意が必要になると思われます。
ご参考になれば幸いです。