タグによってforward先を一意にしつつ負荷分散したい時に使えるかもしれないfluent-plugin-hash-forward #fluentd

そろそろfluentd触ろうかと思ってはや1年近くが経とうとしている今日この頃。ふと構成を色々考えてたんですが、ひとつ気になる問題がありました。

forwardとかroundrobinとかでログの転送先をいろんなサーバにすることがあると思うのですが、単純なcount up以外の集約を行おうとすると、サーバ(正確にはflunetdのインスタンス)が別れてるとちょっと面倒ですよね。例えば、アクセスログから1分辺りのステータスコードによってdatacounterするとして、それを出力してるサーバ毎にやりたいと思った時に、一つのサーバからの出力がラウンドロビンされていろんなfluentdに分かれていると、ちょっと厳しい。

また、例えば1サーバでin_forwardの受け口は1つにしつつ、ローカルに別プロセスでいくつもfluentdを上げてそれらにロードバランスしようかと思った時にも、単純にラウンドロビンしちゃうと、せっかく1サーバに集めたのに処理がプロセスで別れてしまって悲しい。

なにができればいいのかなぁと考えると、例えばアクセスログの処理用のworkerサーバをいくつか横に並べた時に、「accesslog.server1」とタグがあったら、worker1に、「accesslog.server2」とタグがあったらworker2に、みたいな感じでタグによって一意に決まると嬉しそう。

ただ、こんな単純なルールだとタグの種類だけworkerを準備しないといけないわけで、もうちょっと賢くやりたい。というわけで、タグをmurmurhashでintに変換して、それをworkerの数で剰余を取ってバランスするといいかなと思って、fluent-plugin-hash-forwardというプラグインを試しに書いてみました。

仕組みとしてはtagomorisさんのfluent-plugin-forestを大いに参考にさせて頂いています(というかコピペしてます><)。configで指定したサーバの数だけout_forward(serverは1つのみ)のインスタンスを作成して、emitの中でtagをmurmurhashしてどのサーバに振るかを一意に決めています。

configは以下の様な感じで、見てもらえばわかる通りout_forwardっぽいです。<server>の部分とadd/remove_prefix以外は実際内部的に生成するout_forwardにそのまま渡されます。

<match pattern>
  type hash_forward
  add_prefix hoge
  flush_interval 1s

  <server>
    host 192.168.1.3
    port 24224
  </server>
  <server>
    host 192.168.1.4
    port 24224
  </server>

  <secondary>
    type file
    path /var/log/fluent/forward-failed
  </secondary>
</match>

こんな感じでserverを並べて書いてあげるとtagの文字列によって良い感じに負荷分散してくれると思います。使いどころがあるのかどうかは定かではないですが、興味ある方がいればインプット頂ければと思います!