一、基本概念#
-
NRT:
Near Realtime、近リアルタイム、2 つの側面を持つ。一つはデータを書き込んでからそのデータが検索可能になるまでの非常に短い遅延(約 1 秒程度)があること、もう一つは Elasticsearch に基づく検索と分析操作の時間が秒単位に達すること。 -
Cluster
クラスター、外部にインデックスと検索のサービスを提供し、1 つ以上のノードを含む。各ノードがどのクラスターに属するかはクラスター名によって決定される(デフォルト名は elasticsearch)。 -
Node
単独の Elasticsearch サーバーインスタンスは 1 つのノードと呼ばれ、ノードはクラスターの一部である。各ノードには独立した名前があり、デフォルトでは起動時に UUID を取得して名前とすることができ、手動で設定することも可能。1 つのノードは 1 つの Elasticsearch クラスターにしか参加できない。 -
primary shard
プライマリシャード、データストレージの単位、シャードを増やすことで水平スケーリングを行い、インデックス作成時に指定され、作成後は変更できない。 -
replica shard
レプリカシャード、シャードのデータコピーとして機能し、データの損失を防ぎ高可用性を確保し、同時にシャードの検索リクエストを分担し、クラスター全体のスループットとパフォーマンスを向上させる。 -
Index
インデックス、同じ構造のドキュメントの集合、データベースのデータベースインスタンスに相当する(Es 6.0 でタイプが廃止された後は実質的に単一のデータテーブルに相当する)。 -
type
タイプ、Es 6.0 以降廃止、参考リンク: Removal of mapping types -
Document
ドキュメント、Elasticsearch の最小データストレージ単位、JSON データ形式、関係型データベースの表記録(1 行のデータ)に類似し、構造定義は多様化しており、同じインデックス内のドキュメントはできるだけ同じ構造を持つ。
Lucene 検索#
Lucene 概念#
検索の基本プロセス:クエリ分析 => トークン化 => キーワード検索 => 検索順位付け
倒排インデックス#
従来の検索は記事を通じて、キーワードの位置を 1 つずつ探し出すものであった。しかし、倒排インデックスはトークン化戦略を通じて、単語と記事のマッピング関係表を形成し、O (1) の時間でキーワードを通じて記事リストを見つけることができる。簡単に言えば、内容に基づいてドキュメントを探すのに対し、MySQL などの正排インデックスはID に基づいてドキュメントを探す。
底層の実装は FST(有限状態遷移器)データ構造に基づいている。Lucene は 4 + バージョン以降、大量にこのデータ構造を使用している。FST には 2 つの利点がある:
-
スペースの占有が少ない。辞書内の単語の接頭辞と接尾辞の再利用を通じて、ストレージスペースを圧縮している。
-
クエリ速度が速い。O (len (str)) のクエリ時間計算量。
参考リンク🔗:
二、Elasticsearch 使用#
増删改查#
- Get API
- Delete API
- Update API
- Bulk API
検索#
- Search API
- Aggregrations
- Query DSL
- Elasticsearch SQL
Analyzer トークン化#
Standard Analyzer
:デフォルトのトークン化器、単語に基づいて分割し、大文字を小文字に変換する。Simple Analyzer
:非アルファベットに基づいて分割(記号はフィルタリングされる)、大文字を小文字に変換する。Stop Analyzer
:ストップワード(the、is)に基づいて分割し、大文字を小文字に変換する。Whitespace Analyzer
:空白に基づいて分割し、大文字を小文字に変換しない。IK
:中国語トークン化器、プラグインのインストールが必要。ICU
:国際化トークン化器、プラグインのインストールが必要。jieba
トークン化:現在人気のある中国語トークン化器。
インデックス管理#
alias エイリアス#
-
複数のインデックスをグループ化する。
月ごとにインデックスを作成する際、最初に日ごとにインデックスを作成することを考慮し、インデックステンプレート(
indices templates
)を使用することで、ログデータを日ごとに自動的にインデックス作成し、月ごとのインデックスエイリアスを使用して日ごとのインデックスを分類することができる。 -
インデックスを柔軟に変更し、インデックスを変更する際にコードを変更する必要がなく、ゼロダウンタイムでインデックスデータを移行する。
例えば、インデックスを変更(シャードの変更、マッピングの変更、名前の変更など)する必要がある場合、新しく作成したインデックスを対応するエイリアスにバインドするだけで、データ移行が完了した後に旧インデックスとのエイリアスのバインド関係を削除すればよい。
ゼロダウンタイム移行の参考公式文書: Changing Mapping with Zero Downtime
-
同じインデックスの異なる「ビュー」を作成するために使用できる。
マルチテナントのシナリオに適しており、異なるユーザーが特定のインデックス内の異なるデータを見る必要がある場合、
filtered alias
(フィルタリングエイリアス)を作成してフィルタリングすることができる。
-
複数の物理インデックスに対してエイリアスを介して書き込むシナリオ。
複数の物理インデックスに対してエイリアスを介して書き込む必要がある場合、
write index
を指定することで、複数のインデックスを指すエイリアスのすべてのインデックスと更新リクエストは 1 つのインデックス、つまり書き込みインデックスとして解釈される。各エイリアスは 1 回の書き込みインデックスとして 1 つのインデックスを割り当てることができる。書き込みインデックスが指定されておらず、エイリアスが複数のインデックスを参照している場合、書き込みは許可されない。
例操作:
curl -X POST "localhost:9200/_aliases?pretty" -H 'Content-Type: application/json' -d'
{
"actions" : [
{ "remove" : { "index" : "test1", "alias" : "alias1" } },
{ "add" : { "index" : "test2", "alias" : "alias1" } }
]
}
curl -X POST "localhost:9200/_aliases?pretty" -H 'Content-Type: application/json' -d'
{
"actions" : [
{
"add" : {
"index" : "test1",
"alias" : "alias2",
"filter" : { "term" : { "user" : "kimchy" } }
}
}
]
}
参考リンク : Index Aliases
rollover API#
日付に基づいてインデックスをロールオーバー作成する。
参考リンク : Rollover Index
インデックスマッピング#
- Mapping 設定
Index Template
Dynamic Template
: Elasticsearch が認識するデータタイプに基づいて、フィールド名と組み合わせてフィールドタイプを動的に設定する。
参考リンク:
routing ルーティング#
ドキュメントをインデックスする際、ドキュメントは 1 つのプライマリシャードに保存される。Elasticsearch はどのドキュメントをどのシャードに保存すべきかをどのように知るのか?ドキュメントを作成する際、どのようにしてこのドキュメントがシャード1
に保存されるべきか、またはシャード2
に保存されるべきかを決定するのか?
実際、このプロセスは以下の公式によって決定される:
shard = hash(routing) % number_of_primary_shards
routing
は可変値で、デフォルトはドキュメントの_id
であり、カスタム値に設定することもできる。routing
はハッシュ関数を通じて数字を生成し、その数字をnumber_of_primary_shards
(プライマリシャードの数)で割った余りが、私たちが求めるドキュメントの所在シャードの位置である。
これが、インデックスを作成する際にプライマリシャードの数を決定し、その数を永遠に変更しない理由である。数が変わると、以前のすべてのルーティング値が無効になり、ドキュメントは再び見つからなくなるからである。(新しいバージョンでは、Es は一定の条件制限の下で、特定のインデックスのプライマリシャードをSplit分割またはShrink縮小することをサポートしているが、n 倍に分割するか、プライマリシャード数 /n 個に縮小することしかできず、8 から 9 や 9 から 8 のような変更はできない)。
三、クラスターアーキテクチャ#
クラスターの役割#
- Master Node マスターノード:グローバルにユニークで、クラスターの選挙を行う。クラスター層の関連操作を担当し、クラスターの変更を管理する。マスターノードはデータノードとしても機能できるが、推奨されない。
- Data Node データノード:データを保存し、データ関連の操作を実行する。一般的にデータの読み書きプロセスはデータノードとだけやり取りする。
- Ingest Nodeインジェストノード: Es 5.0 バージョンで導入された概念。インデックスドキュメントの前に、データを書き込む前に
processors
プロセッサとpipeline
パイプラインを定義してデータを変換することを許可する。参考リンク:Ingest Node - Coordinating node コーディネーティングノード:コーディネーティングノードはクライアントリクエストをデータを保存するデータノードに転送し、各データノードはローカルでリクエストを実行し、結果をコーディネーティングノードに返す。コーディネーティングノードはこれらのデータ結果を収集し、単一のグローバル結果に統合する。
- Tribe Nodeトライブノード、廃止され、Cross-cluster searchに置き換えられた。
クラスターの健康状態#
- Green: すべてのプライマリシャードとレプリカシャードが正常に動作している。
- Yellow: プライマリシャードは正常だが、すべてのレプリカシャードが正常に動作しているわけではなく、単一障害点のリスクがあることを意味する。
- Red: プライマリシャードの一部が正常に動作していない。
各インデックスにも上記の 3 つの状態があり、特定のレプリカシャードが正常でない場合は Yellow 状態となる。
curl -X GET "localhost:9200/_cluster/health?pretty"
を使用してクラスターの状態を確認できる。具体的には:Cluster health APIを参照。
クラスターの拡張#
クラスターを拡張し、ノードを追加する際、シャードはクラスターの各ノードに均等に分配され、インデックスと検索プロセスの負荷を均等に分散させる。これらはすべてシステムによって自動的に行われる。
参考: 拡張設計
主要内部モジュール#
####Cluster
Cluster モジュールはマスターノードがクラスター管理を実行するためのラッパー実装であり、クラスターの状態を管理し、クラスター層の設定情報を維持する。主な機能は以下の通り:
- クラスターの状態を管理し、新しく生成されたクラスターの状態をすべてのノードに公開する。
- allocation モジュールを呼び出してシャードの割り当てを実行し、どのシャードをどのノードに割り当てるべきかを決定する。
- クラスター内の各ノード間で直接シャードを移動し、データのバランスを保つ。
allocation#
シャードの割り当てに関連する機能と戦略をラップしており、プライマリシャードの割り当てとレプリカシャードの割り当てを含む。このモジュールはマスターノードによって呼び出される。新しいインデックスの作成やクラスターの完全な再起動にはシャードの割り当てプロセスが必要である。
Discovery 発見モジュール#
クラスター内のノードを発見し、マスターノードを選出する役割を担う。ノードがクラスターに参加または退出する際、マスターノードは適切なアクションを取る。ある意味で、発見モジュールは ZooKeeper のような役割を果たし、マスターノードを選出し、クラスターのトポロジーを管理する。
gateway#
マスターからブロードキャストされたクラスター状態(clusterstate)データの永続的なストレージを担当し、クラスターが完全に再起動した際にそれらを復元する。
Indices インデックスモジュール#
グローバルレベルのインデックス設定を管理し、インデックスレベルの設定(インデックス設定はグローバルレベルと各インデックスレベルに分かれる)を含まない。また、インデックスデータの復元機能をラップしている。クラスター起動段階で必要なプライマリシャードの復元とレプリカシャードの復元はこのモジュールで実装されている。
HTTP#
HTTP モジュールは JSON over HTTP の方式で ES の API にアクセスすることを許可する。HTTP モジュールは本質的に完全に非同期であり、応答を待つためにスレッドをブロックすることはない。非同期通信を使用する HTTP の利点は C10k 問題を解決することである(10k レベルの同時接続)。特定のシナリオでは、HTTP keepalive を使用してパフォーマンスを向上させることを考慮することができる。注意:クライアントで HTTP チャンクを使用しないこと。
Transport 伝送モジュール#
クラスター内のノード間の内部通信に使用される。1 つのノードから別のノードへの各リクエストは伝送モジュールを使用する。HTTP モジュールと同様に、伝送モジュールも本質的に完全に非同期である。伝送モジュールは TCP 通信を使用し、各ノードは他のノードといくつかの TCP 長接続を維持する。内部ノード間のすべての通信はこのモジュールによって担われる。
Engine#
Engine モジュールは Lucene の操作と translog の呼び出しをラップしており、シャードの読み書き操作の最終的な提供者である。
ES は Guice フレームワークを使用してモジュール化管理を行っている。Guice は Google が開発した軽量依存性注入フレームワークである。ソフトウェア設計では、具象ではなく抽象に依存することがよく言われるが、IoC はこの理念の実現方法であり、内部でオブジェクトの作成と管理を実装している。