こんにちは。
エンジニアの伊藤です。

11/18に開催された第7回Elasticsearch勉強会にて「niconicoの検索を支えるElasticsearch」と題して、niconicoでのElasticsearchの運用事例について発表してきました。
発表の機会を与えてくださった@johtaniさん、スタッフの皆さん、ありがとうございました。
(この投稿は報告が遅くなっただけで、アドベントカレンダーネタではありません...)

使用したスライドがコチラになります。
https://speakerdeck.com/shoito/niconico-elasticsearch
b864dbd5fc374ef7b2c3031e4dbe2bbd28487189

講演では、まずElasticsearchを使った検索基盤を作った背景、
次に、なぜElasticsearchを使うことにしたのか?
そして、どう使っているのか?どう運用しているのか?
最後に、良く参考にしているElasticsearchの情報源について紹介しました。

今回は発表内容の一部をピックアップして紹介します。

なぜElasticsearchなのか?

ニコニコ動画、生放送、静画など、そして今後増えていくニコニコサービスの
検索インデックスを抱えるためには、スケールアウトできることが大前提で、
プロジェクト開始当時に広く利用されていたSolr 3よりElasticsearchが
適していたことが大きな理由です。
9280dbd4b2ee098d2d8818d9d1601f6ae5f9a772

どうElasticsearchを使っているのか?

今回は検索エンジンとしての利用事例を話しました。
なお、ログ解析にKibana用途のElasticsearchを別クラスタで構築しています。
それと、検索フォームのサジェスト検索用の辞書作成時にスコア計算用にも利用しています。

アーキテクチャ

だいぶラフな図ですが、検索システム周りのアーキテクチャは図のようになっています。
青い線で示した部分が参照系(検索)で、赤い線で示した部分が更新系(インデックス構築)になります。
895a037150ac454068e32eedf3158839736ca79e

まず青い線についてですが、API frontは他システムから検索クエリを受けとったら、Elasticsearch用のクエリに変換し検索します。
(ElasticsearchのQuery DSLは種類が豊富で柔軟なクエリやフィルタが可能ですが、ここでは必要なものだけに限定しています)
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html

Elasticsearchは検索結果としてコンテンツのID列(一部例外でスコアを含むことがあります)を返し、次にMySQLからタイトルや本文など必要なフィールド情報を取得し、肉付けした結果をAPI frontへ、そしてリクエスト元へと返します。

次に赤い線についてですが、他サービスから「コンテンツが投稿/削除された」「視聴数が上がった」「タイトル/タグが変わった」などの更新メッセージ(JSON形式)がほぼリアルタイムにMessageReceiverへと送られてきます。
MessageReceiverはコンテンツIDを元にハッシュ値を算出し、更新メッセージを該当するRabbitMQのキューに振り分けます。
Indexer & Converterは担当するRabbitMQのキューを監視しており、更新メッセージを取り出し、必要な変換を加えた後にElasticsearchとMySQLへと保存します。

メンテナンスのためのエイリアス利用

運用しているとElasticsearchのインデックスについてアナライザやマッピングの変更の必要性が出てきて、インデックスの再構築(reindex)が必要になることがあります。
その際に、古いインデックスは参照したまま新しいインデックスを裏側で構築し、エイリアスの向き先を変更すればアプリケーション側の改修をすることなく、サービス無停止でのメンテナンスが可能になります。
(インデックスの再構築の際には、number_of_replicasを0(ゼロ)にしておくと、再構築時間が数十パーセントほど短くて済みます)
c6fd02c60e13767fe3440acb1734ba3090a713f9

なお、エイリアスはインデックスの別名という用途以外にも、デフォルトのフィルタ機能を設けたインデックスを提供する用途にも使えます。

index aliases
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-aliases.html

これまで遭遇したトラブル

遭遇したトラブルで代表的なものとして、スプリットブレイン問題(SpritSplit-brain)があります。
967056d71c78db7793dafefd9e046867a85c82ed
スプリットブレイン問題とは、本来1つのクラスタには1つのマスタノードが存在して、
クラスタの構成を管理するのですが、マスタノードに問題が発生したとクラスタ内で
判断されると、新たなマスタノードが選定され、元のマスタノードと合わせて2つの
マスタノードが存在してしまうというものです。
この問題が発生すると自然に解消することはないため、どちらかのマスタノードを
マスタから降格させる対応が必要になります。

HOW TO AVOID THE SPLIT-BRAIN PROBLEM IN ELASTICSEARCH
http://blog.trifork.com/2013/10/24/how-to-avoid-the-split-brain-problem-in-elasticsearch/

負荷計測とチューニング

どれくらいの検索/インデクシングリクエスト(QPS: Queries Per Secondを許容できるかを計測するために、GatlingやApache JMeterを利用しています。どちらを使うかは計測者の好みに任せてます。
f50665b3c61ea92d8d16df2940475e5ed70d85c5
なお、ElasticsearchのGithubリポジトリにはJMeterのテストシナリオがあるので、参考に
してみるのも良いかもしれません。

Gatling
http://gatling.io/

Apache JMeter
http://jmeter.apache.org/

elasticsearch / src / test / resources / jmeter /
https://github.com/elasticsearch/elasticsearch/tree/master/src/test/resources/jmeter

最後に

他にも検索/インデクシングのパフォーマンス・チューニングの例をいくつか紹介する
というような話をしましたが、長くなってしまったのでこの辺で。

勉強会が終わった後の懇親会でも、Elasticsearchを運用されてる方々とお話させていただきお互いに運用事例やノウハウを共有する機会がありました。皆さん、ありがとうございました。

なお、主催の@johtaniさんが開催報告ブログをまとめてくれています。
http://blog.johtani.info/blog/2014/11/19/hold-on-7th-elasticsearch-jp/



12月に入り、今日から各所でアドベントカレンダーが始まりましたね。
Elasticsearchに関してもあるので、個人的に楽しみにしています。

Elasticsearch Advent Calendar 2014
http://qiita.com/advent-calendar/2014/elasticsearch

ちなみにドワンゴ社員によるアドベントカレンダーもありますので是非ご覧ください。
ドワンゴ Advent Calendar 2014
http://qiita.com/advent-calendar/2014/dwango