BUYMAの商品検索を支えるSolrCloud

お久しぶりです。アプリケーションエンジニアの木村です。

BUYMAでは、この記事を書いている時点で世界中から出品された約155万件の商品が検索可能となっていて、商品検索機能は世界中から自分の欲しい物を探すことを実現する、まさに「世界を買える」を実現するための重要な機能の1つとなっています。今日はそんなBUYMAの検索機能の裏側を支える基盤部分についてご紹介いたします。

BUYMAでは検索機能実現のためにはSolrを導入していて、さらにSolrCloudを構成しています。

SolrCloudとは

SolrCloudは、高信頼性、耐障害性、拡張性を運用コストを抑えつつ実現するSolrのクラスタリングの仕組みです。紙面の都合上あまりSolrCloudについて詳しく説明できませんが、下記リンクが参考になるのではないでしょうか。

あまりWeb上に詳説された記事がないので、下の書籍も参考にしつつ構築にとりかかりました。

-『Solr in Action』Trey Grainger-Timothy Potter (2014) Manning Publishing. -『改訂新板 Apache Solr 入門』大谷純-他(2013) 技術評論社. -『Scaling Apache Solr』Hrishikesh Vijay Karambelkar (2014) Packt Publishing. -『ZooKeeperによる分散システム管理』Flavio Junqueira-Benjamin Reed [著]、中田 秀基 [訳] (2014) オライリー-ジャパン

さらに、上の2つ目の本も監修されているロンウィットさんのトレーニングも受講しました。最後の本はSolrCloudに組み込まれるZookeeperの本です。

BUYMAでのSolrCloudの構成

BUYMAのでのSolrCloudの構成を表したものが下の図になります。

SolrCloud

更新のしくみですが、Solrを更新するバッチが常に動いていて、DBから更新がかかった商品情報を取得し、leaderのSolrノードへ更新リクエストを送ります。するとSolrCloudの仕組みとして、leaderノードが他のreplicaノードへ更新を伝えて全ノードが更新されます。

検索はRailsのWebサーバーから直接SolrCloud内のSolrノードへリクエストします。特にロードバランサー用のサーバー等は挟まず、SolrノードのIPをランダムに選び、そのIPへリクエストを飛ばすように、Railsアプリ側でロードバランシングしています。

耐障害性への取り組み

RailsのWebサーバーから直接SolrノードのIPへ検索リクエストが飛びますが、各SolrノードのIPアドレスはそれらを監視しているZookeeperから取得しています。したがって、いずれかのSolrノードで障害が起こった場合でもそれをZookeeperが感知し、リクエスト可能なIPの一覧からダウンノードのIPを外してくれ、ダウン中やリカバリ中のノードへは常にリクエストが振られない仕組みになっています。

更新時も更新バッチがZookeeperからleaderであるSolrノードのIPを取得し、それに対して更新リクエストを飛ばしています。もしleaderノードで障害が発生し、フェールオーバーして別のノードがleaderとなった場合でも、Zookeeperがそれを感知して更新バッチ側へleaderの変更が伝わる仕組みです。

実は、Zookeeperと連携してそこらへんの面倒な処理をやってくれるSolrJというSolrCloudにも対応したJava用のSolrクライアントがあるので、JVMのWebアプリではそれを使ったり、そうでない場合はSolrJを使ったAPIサーバーを検索クライアントとSolrとの間に挟む構成が通常なんだそうです。ただ、そのためのサーバーの運用保守もコストなので、RubyからZookeeperと連携するSolrCloud用のRubyクライアントを自分たちで作りました。gemとして公開していますので、ご自由にお使いいただいてフィードバック等をお待ちしております。

https://github.com/enigmo/rsolr-cloud

BUYMAの検索基盤クロニクル

BUYMAがシステム面で今の形に近いものに生まれ変わったのは2008年ごろ(らしいの)ですが、その当時公開されていたSolr 1.3系の時代から検索機能にはSolrが導入されていました。その後2011年に3.x系へとバージョンアップがなされ、2015年6月まで稼働していましたが、商品数の増加とマスキャンペーンにより大量のアクセスが予想されたため、マシンリプレースと合わせて2015年リリースされた5.x系へとバージョンアップしました。さらに、運用し易さを求めて、構成をSolrCloudとしました。

SolrCloud導入以前は、マスタースレーブ構成でもなく、Solrノードを並列にならべてそれぞれのIPアドレスを更新-検索クライアントとなる全サーバーに固定値で持たせていました。更新バッチは全Solrノードへ同じ更新リクエストを何度も送る必要があり、1ノードでも更新に失敗すれば検索結果がノードによってズレてしまいました。Solrノードでの障害発生時やメンテナンス時にもそれぞれのサーバーのSolrノードのIPを書き換えてやる必要がありました。商品数やアクセス数の増大に伴って、この先ノード数を増やす場合にこの構成では限界を感じていました。また、仮にマスタースレーブ構成にしたとしても、マスターが単一故障点になってしまったり、障害対応の時の手間は変わらないというのが難点で、マスタースレーブ構成への変更にも二の足を踏んでいました。

SolrCloudはそういった煩雑さから開放してくれ、まさに自分たちにとっては渡りに船でした。結果、スキーマ変更や設定ファイルのチューニング、ノードの障害発生時の対応やメンテナンスが圧倒的にやりやすくなりました。マシンリプレースの効果もありますが、パフォーマンスも、導入前より向上しました。

今後

Solrのバージョンが3.xから5.xとなり、機能面でも新たに使えるものが増えたので、BUYMAの検索の機能面としても向上していければと思います。