Usual Software Engineer

よくあるソフトウェアエンジニアのブログ

PipelineDBにFluentdからログデータを流して集計する

リアルタイムログ解析としてEFKなどが定番のようになっていますが 実運用でなかなかEasticsearch導入に気がひけたりKibanaで細かい分析とビジュアライズができなかったり、 一方で本格的に分析のシステムを構築するならHadoopやCassandraなどでクラスタ組んだり有料のサービスを使ったりなど、 ちょっとデータ貯めこんでちょっと集計したいだけなのに気持ち的にもヘビーになることがあります。

そんな時、Fluentd+Norikra+MySQLとかで構築すると、直接DBにつっこむほどwrite頻度も多くないし 集計もSQLで取得もSQLで障壁が少なくて良いかなと思っていました。 ただ実際Norikraを試してみると、ログ内のtimestampを時間の基準とするext_timed_batchを使用した場合 ストリームのデータが前後して入力された時にデータが壊れる(意図しないデータが追加される)ということがわかったので 断念することにしました。*1

そこで彗星のごとく僕の前に現れたのがPipelineDBでした。 ユースケースがバッチリ合っていたので一目惚れしました。 PipelineDBの知名度はどのぐらいなのか定かではないですし バージョンは現在の最新でまだ0.8.4ですが公式サイトもしっかりしていて 個人的にデザインも好きですしチュートリアルもドキュメント内にあります。 先月のPGConf Silicon Valley 2015でCEOが紹介してる動画もあるので気になる人はどうぞ Breakout Session Presented by Derek Nelson of PipelineDB at PGConf Silicon Valley 2015 - YouTube

グダグダ説明するよりまずははじめの一歩としてとりあえず動く環境を作ってみました。 DockerでNginx+Fluentd+PipelineDBのコンテナ群が動作します。

github.com

若干ゴリ押しな設定なのですが、公式のDockerfileと設定ファイルを流用してほんの少し変えただけです。 流れはこんな感じです。

  1. PipelineDBにCONTINUOUS VIEWを作成しておく
  2. Nginxに適当にアクセスする
  3. NginxのログをDockerのFluentd logging driverで<DOCKER_HOST>に転送する
  4. <DOCKER_HOST>からポートフォワーディングでFluentdのコンテナにログを転送する
  5. Fluentdでfluent-plugin-postgresを使い、ログデータをPipelineDBに追加する

FluentdにはNginxのログが1行ずつ渡されていますが、PipelineDBで処理をしていて 毎分ごとのNginxへのアクセス数が準リアルタイムに取得できるようになっています。 今回の例ではこんな感じのログデータが

    remote    | host | user |        time         | method | path | code | size | referer |    agent
--------------+------+------+---------------------+--------+------+------+------+---------+-------------
 192.168.99.1 | -    | -    | 2015-12-05 17:03:09 | GET    | /    | 200  |  612 | -       | curl/7.43.0
 192.168.99.1 | -    | -    | 2015-12-05 17:03:15 | GET    | /    | 200  |  612 | -       | curl/7.43.0
...

こうなります。

pipeline=# select * from v_nginx_accesslogs;
       minute        |    path     | code | total_count
---------------------+-------------+------+-------------
 2015-12-05 17:03:00 | /           | 200  |           5
 2015-12-05 17:03:00 | /index.html | 200  |           3
 2015-12-05 17:04:00 | /test.html  | 200  |           6
 2015-12-05 17:04:00 | /test       | 404  |           1
 2015-12-05 17:04:00 | /hoge       | 404  |           1

このような単純なカウントだけでなくSQLで書ければ良いので色々な集計ができます便利! PipelineDBで集計する際に不要なデータ(ここではremoteとかhostとか)は捨てられるので 無駄にディスク容量を圧迫するようなことを防げます。 まあその代わりoriginのログファイルは別なところにとっておいてあるような状況が適してると思いますが。
dockerとかfluentdとかはいいからPipelineDBはどうなのよって人は チュートリアルが簡単なので触ってみると良いと思います。 PipelineDBでのデータ集計と取得はいたってシンプルです。

  1. CONTINUOUS VIEWを作成して集計内容を定義する

     ```
     CREATE CONTINUOUS VIEW v_nginx_accesslogs AS
     SELECT
       date_trunc('minute', time::timestamp) AS minute,
       path::text,
       code::text,
       count(*) AS total_count
     FROM nginx_accesslogs
     GROUP BY minute, path, code;
     ```
    
  2. STREAMにデータをINSERTしてデータを登録する

    • ここではnginx_accesslogsがSTREAMとして存在し、v_nginx_accesslogsを通してデータが投入される

         ```
         INSERT INTO nginx_accesslogs (time, path, code) VALUES ('2015-12-05 17:03:09', '/', '200');
         ```
      
  3. CONTINUOUS VIEWからSELECTしてデータを取得する

     ```
     SELECT * FROM v_nginx_accesslogs;
     ```
    

PipelineDBはPostgreSQLをフォークして作られているので 多くの人が既存の知識で扱うことができると思います。素晴らしい! ひとまず動かした程度ですが、PipelineDBイケてます。 実際に導入して運用している企業もありますし、これからもっと期待できそうです。

*1:開発者本人もext_timed_batchはオススメしないとのこと https://twitter.com/tagomoris/status/486851407140507648