12月12日にFluentd v0.12をリリースしました.ここでは出たばかりのv0.12について書きます.v0.12はv1リリースのための準備マイナーバージョンアップの一つで,なるべく互換性を維持しつつ新機能や新しいAPIを実装しています.以下がv0.12で提供される主な新機能です.
- フィルタ
- ラベル
- ログ転送でのAt-least-once semantics
- 新しいParser/Formatterクラス
このうち,一番下の機能はv0.10にもバックポートされています.それぞれ説明していきます.
フィルタ
Fluentdで一番待ち望まれていた機能です.Fluentdはロバストなログ転送にフォーカスして開発されているログコレクタで,貯めた後にHadoopでバッチを回したり,Prestoでアドホッククエリを投げるなどがよくある構成です.
ただ,ログを貯める前に速報値を出したいとか,ログ本体にはないデータを付加して転送したいなど,様々なユースケースが出てきました.Fluentd v0.10ではそのような場合に,grep
,record_reformer
,geoip
など,Outputプラグインでフィルタ的な処理を書くプラグインが多数生まれました.しかしこれは毎回tagの書き換えを必要とし,少し分かりづらいという問題がありました.
v0.12からはもっと直感的に使えるFilterプラグインの仕組みを導入しました.
データの流れ
v0.10では,間にフィルタ的な処理を挟む場合には,以下のような設定と処理の流れになっていました.fooというタグを使いたくてもタグの書き換えが必須なため,raw.fooなど少し工夫が必要です.
<source>
@type tail
tag raw.foo
</source>
<match raw.foo>
@type filter
remove_tag_prefix raw.
</match>
<match foo>
@type mongo
</match>
Source -> Input - raw.foo -> Output -> - foo -> Output -> Database
|------------------ Fluentd ------------------|
v0.12のフィルタを使えば,fooというタグを使ってそのままフィルタ処理を適用して行けます.
<source>
@type tail
tag foo
</source>
<filter foo>
@type filter
</match>
<match foo>
@type mongo
</match>
Source -> Input - foo -> Filter -> - foo -> Output -> Database
|---------------- Fluentd ----------------|
フィルタでは,タグの書き換えができません.その場合には,引き続きOutputプラグインを使ってください.その代わり,タグにマッチするフィルタ群と最終的なアウトプットをまとめて一つのパイプラインにすることで,処理効率を高めています.これはフィルタ的な処理が多ければ多いほど,恩恵は増えると思います.
詳細に関しては,Fluentd v0.12 Filter プラグインの使い方と作り方を参照してください.気をつけることとして,フィルタはv0.12から入ったばかりでまだAPIが完全に固定されているわけではありません.フィードバックを受けてより良いAPIに変わる可能性があるので,プラグインを書く方は注意してください.
ラベル
Fluentdでは,タグはイベントソースの識別子であり,これを使ってルーティングをします.単純な転送であれば問題にならないのですが,複数の入力があったり,タグの書き換えが発生すると,ルーティングが複雑化する傾向にありました.
そのため,ラベルという機能を導入し,ルーティングそのものはラベルで行うようにしました.これと上記のフィルタ機能を組み合わせると,よほどのことが無い限り,タグを書き換えずにイベントをルーティング出来るようになります.
<source>
@type forward
</source>
<source>
@type forward
@label @TEST
port 24225
</source>
<match forward.**>
@type tdlog
</match>
# labelの引数はパターンではなく,@で始まる名前
<label @TEST>
<match forward.**>
@type elasticsearch
</match>
</label>
この例では,通常のforward
への入力はTDに流れ,テスト用のforward
への入力はESに流れるという感じになっています.relabel
プラグインを使えば他のラベルに飛ぶことも出来ますし,タグの書き換えをすることなくルーティングが可能となりました.
ラベルを利用するにはプラグインにちょっとした変更が必要になるので,それらを含めての詳細はFluentd v0.12 ラベル機能の使い方とプラグインの改修方法を参照してください.
ログ転送でのAt-least-once semantics
Fluentdのin_forward
/out_forward
プラグインは今までat-most-onceしかサポートしていませんでしたが,v0.12からat-least-onceをサポートするようになりました.
<match forward.**>
@type forward
require_ack_response
</match>
require_ack_response
をout_forward
に設定すれば,in_forward
がackを返すまでチェックし,タイムアウトやなんらかの理由でackが返ってこなければ,再度チャンクを再送します.
自分で試した限りだとこれといったパフォーマンス劣化は見られなかったのですが,それなりの流量がある所で試して見てもらいたい所です.
注意点として,require_ack_response
を使うには,out_forward
もin_forward
もFluentd v0.12以上である必要があります.
新しいParser / Formatterクラス
v0.10の段階でもParser / Formatterはプラグイン化していたのですが,APIが整備されていなくてアドホックな感じになってました.それを整えて,他のInput / Outputプラグインなどと同じように使えるようにしました.
v0.10では以下のようにしてParserプラグインを実装してました.
# Parserプラグインの実装
module Fluent
class TextParser
class FooParser
# 何も継承してないので,自分で基本モジュールをincludeする必要がある
include Configurable
# Overwrite initialize, configure and parse method
# なぜかProc.newが必要
TextParser.register_template('foo', Proc.new { FooParser.new })
end
end
end
# Parserプラグインを使う方法
parser = TextParser.new
parser.configure(conf)
v0.12では以下のように書けます.おまじない的なコードが減り,Inputプラグインなどと同じように書けます.
# Parserプラグインの実装
module Fluent
class TextParser
# Fluent::Parserクラスを継承
class FooParser < Parser
# 通常のプラグインと同じ登録方法
Plugin.register_parser('foo', self)
# Overwrite initialize, configure and parse method
end
end
end
# Parserプラグインを使う方法
parser = Plugin.new_parser('foo')
parser.configure(conf)
今回は省きますが,Formatterに関してもParserとほぼ同じように書けます.既存のAPIも残っているので今までのは使い続けられますが,新しいプラグインを作る時はこちらを推奨します.
また,この変更はv0.10.58にバックポートされているので,v0.10/v0.12両方で動くプラグインが書きやすくなっています.
最後に
v0.12で入った機能の中で大きめなやつを取り上げました.今回はルーティング部分などをリファクタリング含めかなり弄ったので,ユーザから見える所だけでなく,Engineの責務の分離など,内部的にも色々と改善されました.まだ互換性維持のためにいくつか無理している所もありますが,v1への過程でもっと綺麗にしていきたい所です.
v0.14ではプラグインのAPI改善やServerEngine対応,イベント時間のミリ秒以下のサポートなど,v1に向けてさらに加速していく予定ですので,来年にご期待ください!