株式会社LegalForceのSREチームメンバー

浜地亮輔氏(以下、浜地):浜地から発表します。最近風邪気味で、咳き込むことがあるかもしれません。お聞き苦しいところ大変恐縮なんですが、ご了承ください。

まず自己紹介です。浜地亮輔と申します。2020年9月に株式会社LegalForceにジョインして、SRE(サイト・リライアビリティ・エンジニアリング)で仕事をしています。Twitterでは、@aibouというIDで日々活動しています。今回の勉強会のタイトルが検索インフラですが、自分自身はElasticsearchを過去4年ぐらい使っていました。

大きいものは、前々職でニュース記事の検索インフラを構築して運用していました。このときは、AWS上で構築していて、AWS OpsWorksというChefのマネージドサービスを使って、EC2上に構築して運用していました。趣味はNFLというアメリカンフットボールを観戦することやクライミングがすごく好きで、白金台のボルダリングジムによくいます。

LegalForceおよびLegalForceキャビネの契約書検索機能は製品の価値そのもの

株式会社LegalForceが提供している製品を紹介したいと思います。弊社では、2つの製品を提供しています。AI契約審査プラットフォーム「LegalForce」、AI契約書管理システム「LegalForceキャビネ(※発表当時はMarshall)」という2つの製品です。

LegalForceは、2021年2月の時点で導入社数が700社を突破していて、かなり驚異的なペースで導入する会社が増えています。これらの製品の中には、実はそれぞれ検索機能があります。LegalForceの中では、条文検索機能とキーワード補完機能という2つの検索用の機能があります。LegalForceキャビネ(Marchall)では、契約書検索機能があります。

特にLegalForceキャビネ(Marchall)の契約書検索機能は、かなり重要な機能で、これが動かなくなったら製品としての価値を提供できないと位置づけているぐらいです。それぞれの検索機能は、Elasticsearchを使って検索インフラを実現しています。

開発陣はかなり豪華だが人は足りていない

検索インフラに入る前に、まず検索機能の開発陣を紹介します。実はかなり豪華な開発陣が揃っていて、Apache Luceneのコミッターが在籍していて、その方を中心に検索機能を開発しています。クラスタによっては、独自プラグインを開発をして、本番導入をした実績もあります。

製品紹介のときに言ったとおり、事業の温度感としても検索機能はかなり高い位置づけにあります。そもそも検索が機能しないと、製品として価値を提供できないので、事業要望によって検索のクエリチューニングを行っています。

LegalForceは、契約書レビューが本分の機能なんですが、実はお客さんの中には条文検索をメインに使っている方もいるそうで、検索機能としてかなり重宝されているようです。

現在は我々SREが二足の草鞋で担っている状態で、開発の担当がインフラも見ている状況になっているので、人が足りていないのが現状です。

負荷分散やマシンリソースの最適化のためにクラスタを分割

ここからは、検索インフラがどういう感じで運用されているかというお話をしようと思います。まず、LegalForceとLegalForceキャビネ(Marchall)がそれぞれどういう感じで動いているかを説明したいんですが、LegalForceはAWS上に製品のシステムが展開されていて、LegalForceキャビネ(Marchall)はGCP上に製品のシステムが展開されています。

こういう背景があるので、検索インフラもそれぞれ近しいクラウドプラットフォームで動かしたほうがいいという判断のもと、それぞれクラスタを分けています。LegalForceは、さらに機能ごとにElasticsearchクラスタを分けていて、条文検索用のクラスタとキーワード補完用のクラスタをそれぞれ分けて作っています。

それぞれのクラスタに関してです。これらのクラスタはコンテナで動いています。AWSで動いているLegalForceは、ECS上でESのクラスタが構築されていて、LegalForceキャビネ(Marchall)のElasticsearchクラスタは、GKE上で構築されています。Elasticsearchクラスタは、ほぼすべて7.9.1のバージョンを利用していて、それぞれが導入しているプラグインは記載のとおりです。

ここで特筆すべきなのがキーワード補完用クラスタで、こちらは先ほど言ったとおり自作プラグインを本番導入しています。

それぞれのクラスタの構成と、なぜクラスタを分割したかという話をしようと思います。クラスタはmaster3台、data3台、client2台という構成になっていて、1つのノードにmasterとdataとclientをそれぞれ兼任させるのではなく、ロールごとにノードを分けています。

負荷分散や、マシンリソースを最適化するためにこういった方法を取っています。保持しているデータの質とか機能品質が異なるので、先ほど言ったとおり、機能や製品ごとにElasticsearchのクラスタを分けて運用しています。

キーワード補完用はリクエストの頻度がけっこうあるんですが、持っているデータの重要度や障害が発生したときの製品への品質影響度はそこまでは高くありません。一方、条文検索用のクラスタは、情報の重要度がすごく高いし、障害が起きたときにけっこうな影響があります。片方で障害が起きたときに、もう片方に影響を及ぼすとマズイので分けています。

コンテナを利用してよかったと思うこと

Elasticsearchクラスタを構築したことがある方は、けっこう仮想マシンでElasticsearchクラスタを構築しているんじゃないかなと思っています。今回LegalForceでは、コンテナを利用してElasticsearchを組んでいます。なぜコンテナを使っているのか、残念ながら詳しい経緯はわからないんですけど、運用上コンテナでよかったところがいくつかありました。

1つがElasticsearch回りのパラメータの設定を環境変数で設定できることです。ふだん仮想マシンで構築をするときは、elasticsearch.yamlにいろいろなパラメータを書いてノードを起動していると思うんですが、こういったパラメータを環境変数で設定できるので、非常に管理が楽でした。

もう1つが、KubernetesのStatefulSetという機能です。これが運用上でかなり楽な機能だと実感しました。

これを使うと、クラスタのアップグレードがすごく容易です。1台ずつ落として、上げていくという挙動なので、1台1台を再起動していくようなオペレーションが不要でとても便利でした。

ECSでも不可能ではないんですが、2台以上ノードが落ちるとクラスタが破損する可能性が非常に高いので、ヘルス率の制御が職人芸になりますし、同時に落ちるのが怖いので、結局タスクを1つ止めては落として……ということをやっています。なので、ElasticsearchのオペレーションツールとしてのKubernetesはかなりいいなと感じています。

この辺は、Elastic社もかなりKubernetesを推していて、機能やドキュメンテーションがすごく充実しているので、Elasticsearchを組むためにKubernetesを使うのは、僕はわりと“あり”なんじゃないかなと感じています。

顧客が1社増えるごとにシャードは3つ増える

あとはインデックスの運用です。けっこう重たい使い方をしていて、条文検索用クラスタと契約書検索用クラスタのそれぞれで、1つのインデックスに対して1つの顧客が紐づくように1対1のマッピングをしています。かつ、1つのインデックスに3つのレプリカを作ってデータロストに備えています。

なので、お客さんが1社増えると、実は3シャード増えるという計算になります。さっき冒頭で「導入会社が700社を超えた」というお話をしたと思うんですが、その結果クラスタ全体として、2,000シャードを超えてきた状況です。

こういう構成なので、チャーン(解約)したお客さんのデータを削除するときは、そのお客さんに紐づくインデックスをそのまま削除すればいいので、非常に楽です。ただElasticsearch的には、1ノードあたり1,000シャードを超える運用は推奨していないので、これ以上シャードが増える場合は、データノードを増やす運用が必要です。

なので、顧客やユーザー数に相関してインデックスが増えていく設計は、可能なら最初から避けたほうがいいかもしれません。

スナップショットデータが莫大すぎて起きたエラー

ほかには、こういったElasticsearchのインデックスのスナップショットで取っています。これは製品の仕様として、明言しているもので、すべてのお客さんのデータを毎時で取っています。保管先はAWSのS3やGCPのGCSです。

Elasticsearch Curatorというサードパーティ製のスナップショットやインデックスを管理してくれるツールを使っていて、これはけっこう前に設定したんですが、2020年の10月、11月ぐらいに、スナップショットを取得するタイミングで警告文が出始めました。

どういう警告文かというと、スナップショットのmetaデータファイルが5メガを超えているので、古いスナップショットを削除しなさいというエラーでした。これはAWSの条文検索用クラスタからけっこう来ていたんですが、すでにスナップショットのオブジェクト数が300万個以上あって、どれが一番古いのか、どれがどうなっているかがちょっとわからない状態でした。古いものを削除することが非常にリスクのある操作になるので、けっこう初動が遅れてしまいました。

これによって、パフォーマンスに影響が出ることはなかったんですが、この状態を放置して、クラスタ破損や障害が起きてほしくないなら事前に何かしらの対応を取らないとね、というところで対応をしていました。対応方法は至ってシンプルです。S3バケットに保存しているんですが、そのバケットを新しく作って、向き先をバツンと切り替えました。

この場合、まっさらなバケットからスナップショットを取ると、その時点でフルスナップショットを取ってくれるので、そこから復旧が可能です。検証で復元できることがわかったので、切り替えて古いのを削除しました。

それまではElasticsearch Curatorを使ってスナップショットを取っていたんですが、切り替えのタイミングでこれを止めて、Elasticsearch 7.5から導入されたSnapshot Lifecycle Managementを使うようにしました。

スナップショットを取るにはPythonのスクリプトを使わないといけないんですが、そもそもスナップショットをいつ取るのかであったり、どこに保管するのかであったり、そういった設定自体をElasticsearchの中に持たせることができる機能なんです。

これを使うことで、curatorを使わなくてもスナップショットを自動で管理して、古いものは自動的に捨てる設定ができるので、Snapshot Lifecycle Managementを使ってスナップショットを管理するように変更しました。Elasticsearch 7.5以上を使っている方は、スナップショットを取るためにもうcuratorを使わなくていいと思っています。バージョンが合っていたら、ぜひSnapshot Lifecycle Managementを使ってみてください。

楽しい成長を目指すLegalForce社のメンバーを募集中

先ほど、人が足りないと話したとおり、検索基盤回りは、かなりいろいろなことをやりたい感じなんですが、いかんせんちょっと人が足りていない状況です。やりたいことはどんどん増えているんですが、バックログがどんどん積まれて消化されていない状況になってきています。

なので、LegalForceにぜひ応募いただければなと思っています。2021年3月にシリーズCで30億円の資金調達が完了しており、シリーズBの投資家がほぼ全員フォローするという、かなりの期待をもっている会社だと思います。楽しい成長をしそうな会社だと僕も思っているので、みなさんと働けるといいなと考えています。ぜひ応募をよろしくお願いいたします。

では浜地からの発表は終わりです。ありがとうございました。

司会者:ありがとうございました。1件質問が来ています。「ECS上でESを動かすのに、インデックスはどこで永続化しているのでしょうか?」というものです。こちらはいかがでしょうか?

浜地:はい。こちらはECSをEC2上で動かすオプションをしています。最近はけっこうFargateが流行っていると思うんですが、このElasticsearchクラスタはFargateを使わずに、ECS on EC2を使っています。そのときのEC2のインスタンスノードに対して、EBSをアタッチして、そこで永続化をしています。

司会者:ありがとうございます。では次もう1つ。「k8s上では永続化にはPersistentVolume(PV)を使っていますか?」。こちらはいかがでしょうか?

浜地:はい。PVを使っています。すみません、Kubernetes回りの設定に関しては、僕も追い切れていないところがあって、詳細にはお答えできないんですが、PVは使っています。

司会者:ありがとうございます。あとはTwitterで、何か気になるツイートはありますか?

浜地:そうですね。以前にconnpass上で、「1インデックスあたりのサイズと、クラスタのインデックスサイズが知りたいです。」というご質問がありました。それに関しては、会社によってインデックスを分けている都合上、1インデックスあたりは平均を取るとそこまで大きくないです。

クラスタあたりの総インデックスに関しては、ちょっと今はお答えできない状況です。今の会社の運用ではなくて、冒頭で話した前々職で扱っていたElasticsearchクラスタの話になりますが、インデックスサイズが大きくて困る場合です。シャードを落としたときに復旧のためのデータ転送が発生します。インデックスサイズが大きいと、そのときにけっこうネットワークを食いつぶす可能性があるので、そこら辺はちょっと気をつけないといけないかもしれないですね。

司会者:ありがとうございます。もう1件、「Amazon Elasticsearch Serviceの利用は検討されましたか?」。

浜地:詳しい背景や経緯はちょっと見えなかったんですが、全文検索においては、Amazon Elasticsearch Serviceはちょっと違うかなと思います。全文検索の精度向上や機能改善のため、辞書周りやプラグインなどのカスタマイズを入れていたりするので、恐らく今新しく作るとしても、利用はしないと思います。

司会者:ありがとうございます。