はじめに
DelishKitchenやヘルシカでインフラをやったりバックエンドをやったりしているyoshikenです。
今回は、Treasure Dataにログを送信しようとfluentdとfluent-bitを使っていたときにハマった話を書きます。
fluentdからfluent-bitへ
もともと弊社では歴史的背景でfluentdを使っていました。が、
- 大々的なlogの加工が必要なものはTreasure Dataなど別サービスで行う
- リソースの消費がやや気になる
- FireLensはじめ、Fargateでfluentbitのほうが相性が良い
などの理由より、新規サービスはすべてfluent-bitを使用することになりました。
移行から数ヶ月~数年経っていますが、flunetdに比べ軽量であるため期待した通りのパフォーマンスを発揮してくれています。
fluent-bitでTreasure Dataにログを送信できない現象
ヘルシカではアクセスログをTreasure Dataに送信する要件がありましたので、fluent-bitでTreasure Dataにログを送信する設定を行いました。
confを公式ドキュメント通りに記述しましたが、ログが送信されず、logを漁ってみると以下のようなエラーが出ていました。
[202x/xx/xx xx:xx:xx] [ warn] [output:td:td.0] HTTP status 404 {"status_code":404,"message":"Resource not found","severity":"error","error":"Resource not found","text":"Resource not found"}
同じような設定でflunetdを動かしてみると問題なく送信/挿入できたので、fluentbit固有の問題と考えdebugしていきます。
fluent-bitとfluentdではTreasure Dataプラグインの挙動が違う件
結論からいうと、fluent-bitのTreasure Dataプラグインはfluentdの同名のプラグインと挙動が微妙に異なります。
fluentdではテーブルが存在しない場合、正確に記すと「upload時に 404 not found
httpステータスコードが帰ってきた場合」はテーブルを作成する処理を行います
begin begin @client.import(database, table, UPLOAD_EXT, io, size, unique_str) rescue TreasureData::NotFoundError unless @auto_create_table raise end ensure_database_and_table(database, table) io.pos = 0 retry end
対してfluent-bitでは、テーブルが存在しない場合でも特に追加処理などせずにそのままエラーを返却する形になっています
https://github.com/fluent/fluent-bit/blob/master/plugins/out_td/td.c#L188-L207
/* Validate HTTP status */ if (ret == 0) { /* We expect a HTTP 200 OK */ if (c->resp.status != 200) { if (c->resp.payload_size > 0) { flb_plg_warn(ctx->ins, "HTTP status %i\n%s", c->resp.status, c->resp.payload); } else { flb_plg_warn(ctx->ins, "HTTP status %i", c->resp.status); } goto retry; } else { flb_plg_info(ctx->ins, "HTTP status 200 OK"); } } else { flb_plg_error(ctx->ins, "http_do=%i", ret); goto retry; }
理由ついてはissueなどを漁ってみましたが、特に言及はなかったです。 一応歴史的にはfluentdも昔はflunet-bit同様にエラーをそのままエラーで返していたましたが、途中でリトライ処理が追加された形になります。
まとめ
まとめると以下の表になります。
fluentd | fluent-bit | |
---|---|---|
テーブルが存在する | 送信可能 | 送信可能 |
テーブルが存在しない | 自動生成 | 404 not found |
弊チームではデータチームと話し合い、"エラーが出続けるのは健全ではない"・"fluentdと同じ仕様と勘違いし、Treasure Data側のテーブル作成を忘れてしまう"などの懸念が生じ、即座のリアルタイム性が必要なログではないため、"一度S3にoutput。その後、Treasure Dataのbatch importで挿入する。"という形で対応することとなりました。
同じようなプラグインでも挙動が異なるというレアケースを引いてしまったため、後世に同じような人がハマらないように記事に残しておきます。