YARNについて書きたい気持ちを抑えて前回の続きです。
まだfluentdをがっつり導入しているわけじゃなく、独自プラグインや構成については改良の余地があるかもなので、まぁ参考程度に見ておいてください。
データフロー
APサーバのログ書き込みから、HDFSに書き込むまでの処理内容です。パスとかは適当に書き換えてます。なぜこんなフローなのかは後述。めんどいのでテキストで。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
(WEB/AP) ◆ログを固定パスに追記 (ex: date >> /tmp/service_plathome_logtype.log のような) ├─□cronによる強制logrotate (10分~1時間程度おき) │ (Fluentd Agent) ◇IN 改造tailプラグインでログ取得 (pathに*の使用可、basenameをtagにできる) │ ◆OUT copy ├─◆flowcounter (unit hourで行数を記録) │ └─◆file (監視用) └─◆roundrobin └─◆改造forward (圧縮/暗号化/ハッシュ化) └─◆serverへ送信 (flush_interval 10) │ (Fluentd Collector) ◇IN 改造forward (ハッシュ解読/復号化/解凍) │ ◆OUT copy ├─◆flowcounter (同上) │ └─◆file (監視用) └─◆改造webhdfs (pathにtagの埋め込み可, flush_interval 10) │ (HDFS) ◇path /logs/%{tag}/%Y%m%d-%H%M.log で各種ログに分けて1分単位のファイルにAPPEND |
改造プラグインは後述なのでそれ以外を何点か。
APのログ
日時パスとかにせず固定パスにしているのは、シンプルかつlogrotateで簡単に移動&圧縮できるからです。さらに最後にHDFSに書き込むpathを可変にするためにpathのbasenameをtagにしています。そうしなければ、AgentごとにFluentd設定を変える必要がでるからです。前回書いた通り、様々な環境への導入を踏まえて、導入も運用もシンプルになるように心がけています。負荷とflush_intarvalの関係
Agent -> Collector は flush_interval 10 でforward処理が少し重めなので、10秒毎にCollectorに負荷がかかります。なので1秒毎にして均一化すべきとも考えましたが、Agentは大量にいるので結果的に均一になるだろうと考え、送受信効率とのバランスをとって10秒にしてみました。ちなみに、Agentは常にtailしているので常に負荷は均一です。
Collector -> HDFS も flush_interval 10 にしてあります。出来上がりファイルが1分単位なのに、1分毎にflushしたんじゃ少し遅いし、あまり小刻みでもAPPENDが不安なので10秒です。10秒といっても、Collectorが5台だとしたら平均2秒毎にAPPENDされることになりますが、今のところ大丈夫だと思っています。
改造プラグイン
プラグインの案と検証は俺ですが、コーディング自体は今回は相棒にやってもらいました(なんて楽なんでしょう!)。数回のダメ出しを経てとても良い仕上がりにしてくれました。プラグインを今後どう扱うかは考え中です。改造tail
基本のtailに以下の機能を加えてあります。改造forward
(OUT)改造webhdfs
Fluentdの負荷試験
CPUは Xeon L5520でやりました。OSはそれなりのサーバに20インスタンス以上ぶっこんだ仮想環境で、fluentdはAgentもCollectorも2vCPUにしてあります。なのでfluentdは問題ないですがHDFSは性能はいまいちな状態です。
数値は、特にどこにもログ送受信に遅延が発生していない状態で、
CPU100%換算 の 処理行数/秒 です。
CPU100%換算:ベンチマーク時に100%にしてしまうと待ちが発生して実際の性能がわからなくなるため、50~80%程度になるように負荷をかけて、それを100%に換算しています。…換算はしますが、実運用では半分近くなったら増設を考えますよ、と
公開プラグインのみの場合
(IN tail -> OUT roundrobin forward => IN forward -> OUT webhdfs)
1 2 |
Agent : 57000rows / s Collector : 63000rows / s |
むぅ、速い。
独自プラグイン3つ+flowcounter
1 2 |
Agent : 47000rows / s Collector : 60000rows / s |
圧縮/暗号化している割に性能劣化は低く、20%減で済んでいるのが不思議です。不思議すぎて相棒にイチャモンつけて中身をわざわざ確認しましたが、ちゃんと圧縮/暗号化されてました・・・。今のrubyってこんなに性能いいの・・・。
これは 1Agent, 1Collector, HDFS での性能です。
他に 1Agent : 複数Collector や 複数Agent : 1 Collector 、複数 : 複数 も試しましたが、オーバーヘッド的なものは認められず、綺麗にスケールアウトしました。問題になるとしたら、大量Collector -> HDFS の部分だけですね。
圧縮/可逆暗号化について
なぜAgent -> Collector間にこのような処理を入れているかですが、CollectorがWANで受け取るからです。つまり、複数のIDCから受け取るということです。この時にいくつか選択肢があるので考えたのを書いてみます。圧縮だけする
複数IDCの場合、GlobalIPアドレスで受け取るのが最も簡単です。トラフィック軽減で圧縮だけして、あとは平文でえぇやん、経路上の誰が盗むというのだ!言ってみろ!!VPNを使う
暗号化できてPrivateLANで解決できる優れもの!まではいいのですが、IDC毎にVPNをはる必要があり、社内管理サーバだけならまだしもサーバ管理者が社外の場合があると、途端に色々めんどくさくなります。さらに、VPNは冗長化や負荷分散の点で弱く、途中に余計な経路も増えるので効率が下がります。SSH使えるぜ
設定、トンネル、運用、いいとこないです。可逆暗号化しようか
プラグイン作成の手間と若干の負荷が許容できれば、なかなか良い落とし所ではないでしょうか。monitによる監視
モニタリングとかアラート系は別途やってるので、さらに1つ付け加える形です。実はAgent落ちてるんじゃないか、とかそもそもAPからログきてないんじゃないかとか。色々あると思いますが、今はやりすぎず少なすぎずに留めています。デーモン操作とかも必要なので monit を使っています。
Agent
Collector
flowcounter+スクリプトによるアラート
まだ本番にぶっこんでないので調整しますが、こんな感じで考えています。行チェックはアラートだけに留めていますが、色々確信してきたらmonitに何か実行させるかもしれません。
内容がもはや所感じゃなくなってますが、今の私の気持ちはこんな感じです。
業務としてやってることを書く時にどこまで書くかが難しいところですが、
このくらいなら大丈夫でしょう。多分。