さようならElasticsearch、よろしくElastic Cloud
2022/5/19 20:25 - 20:40
(明らかに15分で収まる内容の資料ではないですが、資料はモリモリで発表はスカスカでもScrapboxで盛り上がれるか、という仮説の検証を兼ねています)
yuisekiです

Gyazoのプロジェクトマネージャー兼ソフトウェアエンジニアです
本日お集まりいただいたみなさん、ありがとうございます
>
12年間運用を続けているB2C SaaSの検索インフラの実態(14分まで、1分間)
一応動いてるんだけどなんで動いてるのか誰もわかっていない状態
新しい検索の機能追加やアイデアを試行錯誤したいけど、変更方法が不明のため、諦める
いやそれはダメでしょということで、検索インフラ刷新を検討し、いろいろと模索はしていた
偉業👏👏👏

検索インフラ移行のゴール(13分まで、1分間)
これまで通りのことができるようにする
高速な検索
オンデマンドなindexing
無料ユーザーの画像は検索を試そうとした時だけindexingすることでコスト節約
追加で実現したいこと
正確な検索
index mappingsを再定義・再構築できるようにする
移行におけるダウンタイムはゼロ
謎のロストテクノロジーにしない
これ全部話すと一時間になるので面白い話とお得な話だけします
やったー!

概要を聞いてるだけでもすごく大変な作業をしたというのが伝わる

失敗から学ぶElastic Cloud(10分まで、3分間)
Elastic Cloudに移行しようとしていた間、ハチャメチャに失敗していました
(科学においても、工学においても、医学においても、経営・事業においても、政治においても、etc)
>Anyone who has never made a mistake has never tried anything new.
まず落ちるテストを書く=まず失敗する
とはいえガンガンシステム壊しちゃいました!では困る
ググったらCFOがいる企業は実在する模様
最高財務責任者(Chief Financial Officer)では
おもしろい


「失敗に関する本も読んでいる」
ここでNotaの本の購買支援(?)が生きるのか

影響範囲が限定されている
すばやく失敗前の状態に戻せる
発生条件がコントロールされている
失敗から得た情報を元に再発を防止し、さらに改善できる コスパの良い失敗?

Gyazoユーザーが検索できなくなってしまいましたみたいな事態は絶対に避ける
Elastic Cloudに立ち上げたクラスタへ、旧Elasticsearchクラスタと同じリクエストを送って、負荷に耐えられるか検証
失敗:index mappings更新時にハチャメチャに負荷が跳ね上がってしまう
最高に過酷だった時
CPU Usage 200%超え!
Search Response Times 60k ms超え!
キロミリセック熱い

Index Response Times 60k ms超え!
だいぶ過酷だった時
CPU Usage 100%超え!
Search Respones Times 10k ms超え!
Elastic Cloudにこれよりも負荷かけたことあるぞという人がいたら是非ご連絡ください
失敗その1(9分30秒まで、30秒間)
仮説: number_of_shards
を増やせば増やすほど速くなるのでは
結果:そんなことはない。小さいshardsを増やすと最高に過酷になる(後述)
失敗その2(9分まで、30秒間)
?refresh=true
仮説:オンデマンドなindexingのためには ?refresh=true
にしなければならないのでは
結果:そんなことはない。そしてずっとだいぶ過酷だったのは、おそらくこれが原因だった(後述)
複数のdata nodeでクラスタを構成する
検索indexをshardで分割して各data nodeで分散して持つ
shardはさらにreplicaごとにdata nodeに冗長化される
shardの実体はsegmentである
Luceneの概念
indexをファイルシステム上の小さいファイルとして持つ
ファイルなのか〜

リクエスト時に何が起きるか……
searchリクエスト時
全shardでindexを検索して、結果を統合する
indexingリクエスト時
メモリ上のIndexing Bufferから、指定したタイミングで、shardごとに、ファイルシステム上のsegmentに反映する
この処理がめちゃくちゃ重いので、可能な限り先延ばししたほうが良い
Elastic Cloudにおいて、Elasticsearchクラスタは、Deploymentと呼ばれる
1つのDeploymentで、data nodeは最大でも3台まで
たいていのクラウドインフラはAZはregionごとに3つ
data node超大量に立てて負荷分散させるみたいな力技はできない
Elastic Cloudとしてはdata nodeの性能を最大限引き出して3台のクラスタでスケールインすることを推奨
小さいdata nodeを大量に立ち上げるのは実は非推奨
data nodeのCPUとメモリがElasticsearchのパフォーマンスに大きく影響するため
----- ----- ここからは index settings お得情報です ----- -----
(index settingsとは、Elasticsearchがindexをどのように扱うかというindexに関するメタ的な設定項目です)
これはありがたい

定番テクニック(6分まで、1分間)
(公式ドキュメントに書いてある)
number_of_shardsのデフォルト値は1
number_of_shardsの値が1だと、shardの数って1つになるんですよ(
進次郎構文)
data nodeが3台あっても、number_of_shardsの値が1だと、1台しか使われない
ひぇ〜〜〜〜

なにそれこわい

data nodeが3台あるなら、少なくとも3に変更しないと、意味がない
shardのサイズが50GBを超えそうだったら、6, 9, 12, 15...にする
後から変更不可能なので、見積もって設計する必要がある
indexingもsearchも、shardごとに実行される
data nodeの台数が少ないのに、小さいshardsが大量にあると、処理がメッチャ遅くなる
number_of_replicasのデフォルト値は1
number_of_replicasの値が1だと、replicaの数って1つになるんですよ(
進次郎構文)
number_of_shardsが3でnumber_of_replicasが1だと、indexing時に6つのshardに書き込む必要がある
indexing時は0にしておくとパフォーマンスが向上する
bulk APIでindexingのリクエスト数を減らす
余談:bulk APIのリクエストボディが巨大すぎるとそれはそれでElasticsearchがご機嫌斜めになる
重要テクニック(5分まで、1分間)
(!!!公式ドキュメントに書いてない!!!)
refresh_interval
を 30s
とかにする
?refresh=true
のようなリクエストをすると refresh_interval
は無視されて即座にrefreshされるので注意!
?refresh=true
というリクエストをすると
refresh_interval
は無視されて即座にrefreshされるんですよ(
進次郎構文)
つまりメモリ上のIndexing Bufferからファイルシステム上のsegmentへの書き込みが即座に発生する
ワォ

罠だ…

一方で、テストの際には ?refresh=true
にする必要がある
GyazoではCircleCI上でElasticsearchを立ち上げて実際にindexingやsearchをリクエストしてテストしている
?refresh=true
しないと、テストで30秒待つとか確率的に落ちるとかいった厳しい感じになる
index settings改善後(4分30秒まで、30秒間)
Indexingリクエストが殺到していても検索レスポンスが150ms以下
👏ナイススクショw

開発者のGyazoにこういう画像沢山眠ってそう

----- ----- ここからは index mappings お得情報です ----- -----
(index mappingsとは、検索対象のドキュメントを実際にどのようなデータ型とデータ構造でindexingするかという設定項目です)
検索の高速化のためのindex mappings(3分まで、1分間)
(公式ドキュメントに書いてある)
全文検索したいフィールドが多数ある場合、copy_toで一つのフィールドにぶち込んで、それのみを検索対象にすると、速くなる Elasticsearchの気持ちになって考えてみてください
たくさんのフィールドを検索するより、一つにまとめられたフィールドを検索したほうが、検索の回数が減って速いんですよ(
進次郎構文)
everything
フィールドを用意する(名前は何でも良い)
rubyeverything: {
type: 'text',
analyzer: 'ngram_analyzer',
}
ネーミング良すぎる

全文検索したいすべてのフィールドで copy_to: 'everything'
する
rubytitle: {
type: 'text',
analyzer: 'ngram_analyzer',
copy_to: 'everything',
},
desc: {
type: 'text',
analyzer: 'ngram_analyzer',
copy_to: 'everything',
},
ocr: {
type: 'text',
analyzer: 'ngram_analyzer',
copy_to: 'everything',
},
everything
フィールドに対して検索すると速い
ruby{
match_phrase: {
everything: term
}
}
逆にこれをやらないですべてのフィールド内の文字列を全文検索しようとするとどうなる…?
ruby{
multi_match: {
query: term,
fields: %w[title desc ocr ...]
}
}
この検索クエリはElasticsearchにおいて内部的には各fieldsをそれぞれ検索して結果を結合してソートするのと変わらない
フィールド数が多い場合はこのテクニックは重要
Gyazoは様々な画像のメタデータを持っているため、この場合にあたる
Gyazoの全文検索はこれで実現されている
(公式ドキュメントに書いてある)
公式ドキュメントだいじ

へえ両方のインデックスを使えるの熱い

旧Elasticsearchでは、全て、kuromojiインデックスによる全文検索だった
実は検索できない単語があった
Elastic Cloudではn-gramインデックスで、1文字単位で全文検索できるようになった
意図しないTokenizeが行われてしまったり辞書に無い単語では検索できないという問題が解決できた
(使えるけど精度が微妙)
Elasticsearchの
nested fieldsという概念を使うと、別のanalyzerによるtokenizeの結果を保持できる
n-gramとは別にkuromojiのインデックスを持つことで、いいとこ取りできる
rubyeverything: {
type: 'text',
analyzer: 'ngram_analyzer',
fields: {
kuromoji: {
type: 'text',
analyzer: 'kuromoji_analyzer',
}
}
}
もちろんこのフィールドに対して任意の検索クエリが実行できる
ruby{
more_like_this: {
fields: ["everything.kuromoji"],
like: [
{
_index: "index-name",
_id: "document-id"
}
]
}
}
まとめ(0分まで、1分間)
Elastic Cloudに移行して良かった点
Elastic Cloudでハチャメチャな失敗をしたことで、ElasticsearchやLuceneについての理解が深まってよかった
ゼロダウンタイムでElasticsearchからElastic Cloudへ移行できた
すごい

ElasticsearchのマイナーバージョンアップはElastic Cloudで管理画面でボタンを押すだけで可能になった
Elastic Cloudで困っている点
Kuromojiの辞書を簡単にカスタマイズできない
新語に対応できない
Elastic Cloudの方と話をしたら仕様的には頑張れば辞書カスタマイズできるらしいです
追加できるカスタムプラグインの形式や容量が制限されている
(Elastic Cloudが機械学習による自然言語処理に対応したらしいけど全然大変)
オトク情報いっぱいあって嬉しい

type:gif
Gif画像を検索
app:"Google Chrome"
これ「同じアプリの画像を表示」から出てくるから極秘情報ではないと思う

site:scrapbox.io
Scrapbox経由で貼り付けた画像を検索
title:typescript
ocr:Gyazo
camera:
もある
極秘情報たすかる

NANI!?

なるほど、
極秘情報で検索をかけるとこういった情報が出てくるのかw

拡散しようと思ったらなんかショートカットが追加されてた

真面目な話ですが、本来は機能追加やUI変更をしたら、ちゃんとユーザーさんに何が変わったのか言わずとも気づいてもらえなければならない/あるいは言葉で伝えなければならないのですが、Gyazoは日々メッチャ改善や機能追加をしているのにそれをお伝えできていません…!極秘情報というのは半分自虐です…!!

草

まあscrapboxもそんな感じですし
専門的な分野過ぎて伝えにくいというのもありそう

関連リンク