fluent-plugin-uniqcountを公開しました

概要

fluent-plugin-uniqcountは、指定期間範囲において、設定で指定した属性ごとにイベント発生件数をユニークにカウントし、結果の上位N件を定期出力するfluentdプラグインです。SQLでいうところの:

SELECT key1, COUNT(key2) AS key2_count, COUNT(DISTINCT(key2)) AS key2_uniq_count FROM records WHERE time BETWEEN T1 AND T2 GROUP BY key1 ORDER BY key2_count DESC LIMIT 0, N;

に相当します。

fluent-plugin-uniqcountを使うと、

などが集計可能です。

特徴

fluent-plugin-uniqcountは、単位時間あたりのトラフィック量をN、集計対象区間長(設定項目: list*_span)をTとしたときに、以下のような特徴を備えています。

  • イベント1件あたりのプラグインへの入力コストは O(logNT)。単位時間あたりだと O(N logNT)。
  • プラグインの出力コストは O(logNT)。
  • 消費メモリは O(NT)。
  • ユニークカウントである(F5リロードなどでランキングが跳ね上がらない)。
  • 直近(T秒前〜現在)の集計結果が可能である(集計対象区間が時間経過とともにスライドする)。
  • 一つの集計単位を「リスト」と呼び、独立した設定を持つ任意の数のリストを保持することができる(最大10個まで)。
  • fluentdのイベント受信時刻ではなく、レコード内のタイムスタンプを基に集計を行うことができる(未設定時はイベント受信時刻を用いる)。
  • appサーバからfluentdにイベントが到達する時間のゆらぎを吸収するため、集計対象区間の終点を現在時刻から過去へオフセットすることができる(list*_offset: 転送に関与したfluentdのflush_interval値を考慮して設定する)

設定

項目
  • list*_label : 出力レコードに付与されるラベル文字列
  • list*_time : イベント時刻フィールド名(UNIXタイムスタンプ形式 - 省略時はfluentdにおけるイベント受信時刻が使われる)
  • list*_key1 : グルーピングに用いるフィールド名
  • list*_key2 : カウント対象フィールド名
  • list*_span : 集計対象区間長(秒)
  • list*_offset : 集計対象区間終点のオフセット値(秒)
  • list*_out_tag : 出力レコードに付与されるタグ
  • list*-out_num : 出力件数(上位N件)
  • list*_out_interval : 出力間隔(秒)
設定例

入力イベントが以下のようなフォーマットを持っているとき、

site.access_log: {"at":1367820029,"uri":"http://www.careerlink.vn/","remote_ip":168364289}
...

次のような設定で、各spanにおけるURLランキングを得ることができます。

<match site.access_log>
  type uniq_count

  list1_label min
  list1_time at
  list1_key1 uri
  list1_key2 remote_ip
  list1_span 60
  list1_offset 3
  list1_out_tag trends.min
  list1_out_num 5
  list1_out_interval 1

  list2_label day
  list2_time at
  list2_key1 uri
  list2_key2 remote_ip
  list2_span 86400
  list2_out_tag trends.day
  list2_out_num 5
  list2_out_interval 10
</match>

出力例は以下のようになります。

trends.min: {"label":"min","ranks":[{"key1":"http://www.careerlink.vn/","rank":0,"key2_uniq_count":13},{"key1":"http://www.careerlink.vn/file/71ca7183087cce9f04fc559ce37738e9","rank":1,"key2_uniq_count":12}, { ... }, ...],"at":1367840734}
trends.day: {"label":"day","ranks":[{"key1":"http://www.careerlink.vn/","rank":0,"key2_uniq_count":8034},{"key1":"http://www.careerlink.vn/file/065d88676460f47d99ec59263c650f54","rank":1,"key2_uniq_count":7735},{"key1":"http://www.careerlink.vn/file/71ca7183087cce9f04fc559ce37738e9","rank":2,"key2_uniq_count":7266}, { ... }, ... ],"at":1367840734}

TODO

  • gem化
  • 省メモリ化のため、オブジェクトの生成数をもっと減らしたい

注意点

流しこむトラフィックや、設定によっては、かなりのリソース(CPU、メモリ共に)を食うと思います。このプラグインを実際に使用する際は、fluentdのプロセスを独立させ、メインのfluentdプロセスからイベントをforwardさせ、処理結果をまたメインプロセスに戻してやるのがよいと思います。
なお、手元ではfluentdプロセスが2GB超のメモリを消費した状態で、安定して稼働しています(ruby 1.9.3p194)。