こんにちは。検索エンジンチームの宮崎です。
皆さんご存じの通り、LIFULL HOME'Sのメイン機能は物件の検索です。
LIFULL HOME'Sでは、 検索機能の大部分を全文検索エンジンSolrで賄っています。
以下のような機能を検索エンジンで実現しています。
- こだわり条件検索(ガスコンロ3口、2階以上、など詳細な条件での検索)
- 駅・エリアでの絞り込み
- 地図検索
- タグによる物件検索
- 検索結果の件数
- 並び順
- 建物や戸ごとのグルーピング
これらの機能を実現している検索エンジンは、
アプリケーション実行基盤やDBに並んでサービス継続のために必要な重要コンポーネントです。
しかし検索エンジンはその特性上、ステートフルなソフトウェアです。
HDFSやその他ストレージと組み合わせることでステートレスにすることもできるかもしれませんが、多くの場合ステートフルなアプリケーションとして運用していることが多いと思います。
今回はステートフルなアプリケーションである検索エンジンを一部スポットインスタンス化することでランニングコストを削減したので、構成や進め方について紹介しようと思います。
🔎 全文検索エンジンをスポットインスタンス化???
全文検索エンジンとは
そもそも全文検索エンジンとは何でしょうか? Wikipediaにはこうあります。
全文検索とは、コンピュータにおいて、複数の文書(ファイル)から特定の文字列を検索すること。 「ファイル名検索」や「単一ファイル内の文字列検索」と異なり、 「複数文書にまたがって、文書に含まれる全文を対象とした検索」という意味で使用される。
もともとは多数の文書の中から特定の文字を含む文書を検索するために作られたもののようです。 LIFULL HOME'Sでは文書の代わりに物件情報を検索エンジンに入れて物件の検索を実現しています。
スポットインスタンスとは
次にスポットインスタンスとは何でしょうか?
これは、AWS(Amazon Web Services)において、条件付きでマシンを安く使用できるしくみのことです。
その条件というのが、「スポットで起動されたインスタンスはAWS側の都合により、事前の予告なく※1停止されることがある」というものです。
※: インスタンス停止の2分前に通知されます。
これは、スポットインスタンスのしくみによりそのような条件になっています。
スポットインスタンスは、AWSのクラウド内で使用されていないEC2を安く使えるというしくみです。
誰にも使われてないのはもったいないから、安くてもよいので使ってもらおうということですね。
ステートフルなソフトウェアとスポットインスタンス
スポットインスタンスはその特徴から、
公式の説明「ステートレス、耐障害性、または柔軟性を備えたさまざまなアプリケーションでご利用いただけます」にある通り、
ステートレスなアプリケーションで主に利用されます。
任意のタイミングでインスタンスを停止できることと、ステートレスであることは相性がよいからです。
ステートレスであれば、インスタンスを停止したい場合はそのままインスタンスを停止すればよいのです。
(実際には停止時に行いたい処理があることのほうがほとんどだとは思います)
さて、検索エンジンはステートフルなソフトウェアでした。
しかしタイトルの通り、ステートフルでも安くしたい!のです。
そんな検索エンジンをスポットインスタンス化してコスト削減した構成が以下です。
🔗 検索エンジンの構成
検索エンジンは以下のような構成になっています。
一部省略していますが、概略としてはこんな感じです。
Lambdaは、Solrのリーダーにデータを書き込みます。 実際に検索用のクエリを受け取るインスタンスはAutoScalingGroupで管理しています。
AutoScalingGroupを使用しているので、MixedInstancesPolicyを設定することでスポットインスタンスを適用できます。
🤔 工夫点
- インスタンス起動時に、systemdでクラスタに自動で参加するようにしている
- インスタンス停止時に、systemdでクラスタから自動で抜けるようにしている
- スポットインスタンスの終了通知をEventBridgeで受け取って、ALBから自動で切り離すようにしている
- 書き込みと読み込みでエンドポイントを分けている
- クラスタはデプロイ時に全インデックスを再構築できる
- マスタ/スレーブ構成にすることで参照用Solrはリードオンリーに動作する
「クラスタはデプロイ時に全インデックスを再構築できる」、「マスタ/スレーブ構成にすることで参照用Solrはリードオンリーに動作する」の 2点のおかげで、ステートレスなSolrを実現しています。 ステートレスなSolrを実現するとAutoScalingGroupで管理できるようになり、負荷増に耐えたり柔軟性が上がり、スポットインスタンスで動作させることができています。
またマスタ/スレーブのような構成にすることで、検索クエリの負荷や書き込みの負荷をお互い影響させないようにしています。
📖 結果
コストエクスプローラーの数値が見えない状態で切り取ったものです。 オレンジの部分がスポットでかかっている金額です。緑色のオンデマンドの金額がかなり小さくなっているのがわかると思います。
スポットインスタンスが、だいたい正規の値段の1/3程度だったので概算で、1日あたり約20%強のコスト削減を実現しました。 別のプロジェクトで行っていたSavingsPlansによるコスト削減と含めると、 ほぼオンデマンドで動いているインスタンスがいない状態です。 社員の数が少なければボーナスで焼き肉を食べに行けるくらいにはなったでしょう。
最後に
Solrの特徴とAWSをうまく組み合わせることで、耐障害性を確保しつつ、コスト削減を実現しました。
ステートフルなアプリケーションの中の、ステートレスな部分のみスポットインスタンスを適用したという話でした。 もともとイミュータブルに作っていたことや、更新と検索でエンドポイントを分けた構成にしていたことで、 簡単にスポットインスタンスによるコスト削減を実現できました。 アーキテクチャは大事ですね。
カジュアル面談もやっていますので、一緒に「感動を届ける検索エンジンを実現する」、ひいてはLIFULLが目指している「あらゆるLIFEを、FULLに。」することに興味がある方はぜひお話しましょう!