読者です 読者をやめる 読者になる 読者になる

ログ解析にNorikraを使ってみた

この記事は、CyberAgent エンジニア Advent Calendar 2014 の 17 日目の記事です。
昨日は@neo6120さんのアドテクスタジオのゼミ制度の紹介と活動報告 でした。
18日目は@sitotkfmさんのSpark StreamingでHyperLogLogを実装してみたです。



弊社で、プラットフォーム機能の一部を作らせて頂いている、@hase_xpwです。

@kakerukaeruさんにやろうぜ!って誘われたので参加してみました
これを機にブログもっと更新したいと思います!

今回のテーマは、Norikraというミドルウェアで、業務でログ解析をする際に使ってみた所かなり便利だったのでNorikraの魅力を少しでもお伝えできればいいなと思いテーマに選びました。

これおかしくね?みたいなのがあったらバシバシ指摘して頂きたいです。

環境構築と使い方は、わかりやすくまとめられている方がいるので割愛させて頂きます

1. Norikraってなに

LINE株式会社の TAGOMORI Satoshi (@tagomoris)さんが開発
norikra/norikra · GitHub
スキーマレスにストリームデータの処理を行ってくれます

fluentdのプラグインが用意されているため、fluentd経由でデータを吸い上げて集計する事が可能です

内部的には、jRubyで書かれていて、バックエンドのエンジンにはEsperというJavaのライブラリが利用されています。
Esperはデータのストリーム処理をSQL Likeに行えるJavaのライブラリで、ストリームのデータに対してwindowをあてて、期間ごとにデータを切り出して集計をします。

イメージはこんな感じです
f:id:hase-xpw:20141216110111p:plain


Norikraの利用例としては、Elasticsearch + kibana + fluentd + Norikraでログのリアルタイム可視化が挙げられます。ログデータをrawデータのまま保持すると、ディスク容量を圧迫し、また、データ量に比例して解析のコストが非常に大きくなるため、潤沢なリソースが必要になってしまいます。このため、Norikraであらかじめデータを集計して無駄なものを省いておくことにより、解析のコストを抑えることができます。

2. なにができるの

Norikraでは、データの集計・検索・結合等、EsperでサポートされているSQLシンタックスのほとんどを利用可能です
ドキュメント

INSERT, UPDATEは非対応ですが、ログ解析とかの利用では全然不要かと
Group By, JOINやサブクエリ周りが利用できるのはかなり夢が広がりますね
パフォーマンス面でも、4コアで2000 event/sくらいさばいても全然余裕なようです

Current Status:
	•	10 queries
	•	2,000 events per seconds
	•	5% usage of 4core CPU

5. なにがすごいの

SQLの知識だけあれば、かなり色々な形でログを集計できます
レイテンシの集計・アクセス数の集計・エラーレートの集計・課金額の集計・イベントのクリア状況の集計 etc...

webUIが用意されていて、サービスの再起動なしにクエリを変更する事が可能です

こんなの
f:id:hase-xpw:20141215194906p:plain


パフォーマンス面では、こちらの記事にあるように、fluentdはデフォルトでシングルプロセスで動くため、マルチコアの恩恵が受けられない のですが(プラグインを利用すればマルチプロセスで動かせます)

一方で、Norikraはjrubyで動くため、マルチプロセスで稼働させる事が可能です

6. 利用事例

弊社のとあるサービスで、ログのリアルタイム解析に利用しています

サービスの特性上、不特定多数のクライアントからAPIが呼び出されるため、各クライアントがどのくらいアクセスしていて、どんなレスポンスを返しているかを確認したいことがあり、毎回ログを集計するのも大変なので、クライアント別にステータスコードを集計し、kibanaを使いリアルタイムに可視化しようと考えました。

利用する候補として、Stormか、fluent-plugin-datacounter(こちらも@tagomorisさん作です)かNorikraを考えていたのですが、Stormはヘビーすぎたためあきらめ、datacounter pluginは正規表現でマッチしたログの数を集計するため、今回のようにクライアントが増える場合、増えるたびに設定を書き換えなければいけないため、Norikraにしました。

fluent-plugin-datacounterの設定ファイル

<match accesslog.baz>
  type datacounter
  count_key status
  pattern1 OK ^2\d\d$
  pattern2 NG ^\d\d\d$
  input_tag_remove_prefix accesslog
  output_per_tag yes
  tag_prefix datacount
  output_messages yes
</match>

構成
・Elasticsearch
・kibana
・fluentd
・Norikra

導入するシステムは200 req/s * 10台 = 2000 req/sくらいのアクセスが想定されていたため、公式に書いてある実績に従うならさばけると思うのですが、今後規模が大きくなったり、複雑なクエリを投げたくなった際に苦しくなる事が予測されるので、各サーバーにNorikraを配布し、必要なデータを集計して送るように構築しました。また、Aggregator側にもNorikraを配布し、必要に応じて受けたログの再集計を出来るようにしました。

こんな感じです
f:id:hase-xpw:20141216191603p:plain

投げているクエリは、こんな感じにステータスコードをclientのid別に集計するクエリです

SELECT
    client_id,
    status_code,
    count (client_id) as count
FROM
    access_api01.win:time_batch (10 sec)
GROUP BY
    client_id,
    status_code

クエリ自体がシンプルなこともありますが、現状リソースを圧迫するような事はなく安定稼働しています
windowは10sに設定していますが、この辺はCPUとメモリーのトレードオフだと思うので環境に合わせてチューニングすればいいかと思います

参考までに、8コアサーバーでのCPU使用率グラフです、メモリは多めにとってますが実際に使われてるのは100 ~ 200MBくらいでした
f:id:hase-xpw:20141215204940p:plain


実際に可視化した図はこんな感じになります
f:id:hase-xpw:20141217102417p:plain

7.まとめ

SQL likeにログを集計できるというのは使ってみた感じすごく便利

ElasticsearchのバックエンドがLuceneだったり、NorikraのバックエンドがEsperだったり、基盤技術がしっかりしているものの方が流す血が少なくてすむ気がする

Norikraを作るまでのアプローチとか読んでみるととても面白い!
fluent-plugin-esper構想概略 - たごもりすメモ

JOIN, subquery周りをもっと検証してみたい。windowのサイズが小さければそこまでjoinにコストはかからなそうな印象