これらの言葉をすべて理解した後、ElasticSearch 運用のベテランでない人はいないでしょうか。

この記事が読者に Elasticsearch の機能とその使用法と理論的根拠を一般的に理解してもらえることを願っています。

1. 生活の中のデータ

検索エンジンはデータを取得するので、生活の中のデータから始めましょう。

私たちの生活には、構造化データと非構造化データの 2 種類のデータがあります。

構造化データ:行データとも呼ばれ、2 次元のテーブル構造によって論理的に表現および実現されるデータであり、データ形式と長さの仕様に厳密に従っており、主にリレーショナル データベースによって格納および管理されます。データベース、メタデータなど、固定形式または制限された長さのデータを指します。

非構造化データ:フルテキスト データとも呼ばれ、可変長または固定フォーマットがなく、オフィス文書、XML、HTML、Word 文書、電子メール、さまざまなレポート、画像などのすべてのフォーマットを含む、2 次元データベース テーブルによる表現には適していません。そして音声、映像情報など。

説明: より注意深く区別したい場合は、XML と HTML を半構造化データに分けることができます。独自のタグ形式もあるため、必要に応じて構造化データとして処理することも、プレーン テキストから抽出して非構造化データとして処理することもできます。

データの 2 つの分類に応じて、検索も構造化データ検索と非構造化データ検索の 2 種類に分類されます。

構造化データの場合、特定の構造を持っているため、一般にリレーショナル データベース (mysql、oracle など) の 2 次元テーブル (テーブル) に格納および検索でき、インデックスを構築することもできます。

非構造化データの場合、フルテキスト データを検索するには、順次スキャンとフルテキスト検索という 2 つの主な方法があります。

順次スキャン:テキスト名を通じてその一般的な検索方法、つまり、順次スキャン方式で特定のキーワードをクエリすることもできます。たとえば、新聞を渡された場合、その新聞のどこに「平安」という言葉が載っているかを調べてみましょう。必ず新聞を最初から最後まで目を通し、そのキーワードがどのセクションに掲載され、どこに掲載されているかをマークする必要があります。

この方法は間違いなく最も時間がかかり、最も効率的ではありませんが、新聞の植字フォントが小さく、セクションが多く、場合によっては複数の新聞がある場合は、目を流し読みするだけでほぼ十分です。

全文検索:非構造化データの順次スキャンは遅いのですが、最適化できますか? 非構造化データに特定の構造を持たせる方法を見つけるだけで十分ではないでしょうか? 非構造化データ内の情報の一部を抽出し、特定の構造を持つように再編成してから、特定の構造を持つデータを検索することで、比較的高速な検索の目的を達成します。

このアプローチは、全文検索の基本的な考え方を構成します。非構造化データから抽出され、再編成された情報のこの部分はインデックスと呼ばれます。この方法の主な作業負荷は初期段階でのインデックスの作成ですが、後の検索では高速かつ効率的です。

2、最初に Lucene について話します

世の中のデータの種類を簡単に理解すると、リレーショナル データベースの SQL 検索ではこの種の非構造化データを処理できないことがわかります。この種の非構造化データの処理は全文検索に依存する必要があり、現在市場で最も優れたオープンソースの全文検索エンジン ツールキットは Apache の Lucene に属しています。

ただし、Lucene は単なるツールキットであり、完全な全文検索エンジンではありません。Lucene の目的は、ターゲット システムでの全文検索機能を容易にするための使いやすいツールキットをソフトウェア開発者に提供すること、またはこれに基づいて完全な全文検索エンジンを構築することです。

現在、オープンソースで利用可能な Lucene ベースの全文検索エンジンは、主に Solr と Elasticsearch です。

Solr と Elasticsearch はどちらも比較的成熟した全文検索エンジンであり、機能や性能は基本的に同じです。ただし、ES自体は分散型でインストールや利用が容易であるのに対し、Solrの分散はZooKeeperを利用するなどサードパーティによる分散連携管理を実現する必要がある。

Solr と Elasticsearch はどちらも最下層で Lucene に依存しており、Lucene が全文検索を実現できるのは主に転置インデックスのクエリ構造を実装しているためです。

転置インデックスを理解するにはどうすればよいですか? 既存のデータ ファイルが 3 つある場合、ファイルの内容は次のとおりです。

1)Java は最高のプログラミング言語です。

2)PHP は最高のプログラミング言語です。

3)JavaScript は最高のプログラミング言語です。

転置インデックスを作成するには、トークナイザーを使用して各ドキュメントのコンテンツ ドメインを個別の単語 (用語または用語と呼びます) に分割し、すべての一意の用語の並べ替えられたリストを作成して、その用語がどの文書に出現するかをそれぞれリストします。結果は次のようになります。

CopyTerm          Doc_1    Doc_2   Doc_3
-------------------------------------
Java        |   X   |        |
is          |   X   |   X    |   X
the         |   X   |   X    |   X
best        |   X   |   X    |   X
programming |   x   |   X    |   X
language    |   X   |   X    |   X
PHP         |       |   X    |
Javascript  |       |        |   X
-------------------------------------

この構造は、文書内のすべての一意の単語のリストで構成されており、各単語にはそれに関連付けられた文書のリストがあります。この属性値によってレコードの位置を決める仕組みが転置インデックスです。転置インデックスを持つファイルは転置ファイルと呼ばれます。

次の図に示すように、上記の内容をグラフの形式に変換して、転置インデックスの構造情報を示します。

理解する必要がある主に次の中心的な用語があります。

  • 用語:インデックス内の最小のストレージおよびクエリ単位。英語の場合は単語、中国語の場合は通常、単語分割後の単語を指します。

  • 辞書 (用語辞書):辞書、用語のエントリのコレクションです。検索エンジンの通常のインデックス単位は単語であり、単語辞書はドキュメント コレクションに出現したすべての単語で構成される文字列コレクションです。単語辞書の各インデックス項目には、単語自体に関する情報と、単語へのポインタが記録されます。 「投稿リスト」。

  • 投稿リスト:通常、文書は複数の単語で構成されており、投稿リストには、特定の単語がどの文書に出現し、どこに出現したかが記録されます。各レコードは「投稿」と呼ばれます。転置リストには文書番号が記録されるだけでなく、単語の出現頻度やその他の情報も記録されます。

  • 転置ファイル:すべての単語の転置リストは、多くの場合、ディスク上の特定のファイルに順次に保存されます。このファイルは転置ファイルと呼ばれ、転置ファイルは転置インデックスを格納する物理ファイルです。

上の図から、転置インデックスは主に辞書と転置ファイルの 2 つの部分で構成されていることがわかります。辞書と投稿リストは Lucene の 2 つの非常に重要なデータ構造であり、高速な検索の重要な基盤です。辞書と反転ファイルは 2 つの部分に分けて保存され、辞書はメモリに保存され、反転ファイルはディスクに保存されます。

3. 中心となる概念

いくつかの基本的な知識の基礎を築いた後、今日の主人公である Elasticsearch の導入に正式に入ります。ES は Java で書かれたオープン ソースの検索エンジンです。内部のインデックス作成と検索に Lucene を使用します。Lucene をカプセル化することで、Lucene の複雑さを隠します。代わりに、シンプルで一貫した RESTful API のセットを提供します。

ただし、Elasticsearch は Lucene を超えており、単なる全文検索エンジンではありません。それは次のように正確に説明できます。

  • 分散型リアルタイム ドキュメント ストア。各フィールドにインデックスを付けて検索できます。
  • 分散型リアルタイム分析検索エンジン。
  • 数百のサービス ノードまでスケールアップでき、PB レベルの構造化データまたは非構造化データをサポートします。

公式 Web サイトの Elasticsearch の紹介では、Elasticsearch は分散型でスケーラブルな、ほぼリアルタイムの検索およびデータ分析エンジンであると説明されています。Elasticsearch が分散型でスケーラブルなほぼリアルタイムの検索を、いくつかの核となる概念を通じてどのように実現するかを見てみましょう。

1. クラスター

ES のクラスタ構成は非常にシンプルで、サードパーティの調整および管理コンポーネントに依存する必要がなく、クラスタ管理機能は内部で実現されます。ES クラスターは 1 つ以上の Elasticsearch ノードで構成されます。各ノードは、同じクラスター名を構成することでクラスターに追加できます。デフォルト値は「elasticsearch」です。異なる環境では必ず異なるクラスター名を使用してください。そうしないと、ノードが間違ったクラスターに参加することになります。

Elasticsearch サービスの起動インスタンスはノード (Node) です。ノードは、node.name を使用してノード名を設定します。設定されていない場合は、起動時にランダムな汎用一意識別子が名前としてノードに割り当てられます。

1) 発見メカニズム

次に、ES が同じ設定cluster.name を使用して異なるノードを同じクラスターに接続するにはどうすればよいかという疑問があります。答えは禅の発見です。

Zen Discovery は、Elasticsearch の組み込みのデフォルト検出モジュールです (検出モジュールの役割は、クラスター内のノードを検出し、マスター ノードを選択することです)。ユニキャストおよびファイルベースの検出を提供し、プラグインを介してクラウド環境や他の形式の検出をサポートするように拡張できます。Zen Discovery は他のモジュールと統合されており、たとえば、ノード間のすべての通信は Transport モジュールを使用して行われます。ノードは検出メカニズムを使用して、Ping を通じて他のノードを見つけます。

Elasticsearch は、ノードが誤ってクラスターに参加することを防ぐために、ユニキャスト検出を使用するようにデフォルトで設定されています。同じマシン上で実行されているノードのみが自動的にクラスターを形成します。

クラスターのノードが別のマシンで実行されている場合は、ユニキャストを使用して、接続を試行するノードのリストを Elasticsearch に提供できます。ノードがユニキャスト リストのメンバーに接続すると、クラスター全体のすべてのノードのステータスを取得し、マスター ノードに接続してクラスターに参加します。

これは、ユニキャスト リストにはクラスター内のすべてのノードを含める必要はなく、新しいノードがそのうちの 1 つに接続して通信できるのに十分なノードだけが必要であることを意味します。マスター候補ノードをユニキャスト リストとして使用する場合、リストする必要があるのは 3 つだけです。この設定は elasticsearch.yml ファイルにあります。

Copydiscovery.zen.ping.unicast.hosts: ["host1", "host2:port"]

ノードが起動したら、最初に ping を実行します
。discovery.zen.ping.unicast.hosts が設定されている場合は、その設定でホストに ping を実行します。それ以外の場合は、localhost の複数のポートに ping を試行します。Elasticsearch は、同じホスト上での複数のノードの起動をサポートしています。 Ping 応答には、このノードとこのノードが考慮するマスター ノードの基本情報が含まれます。選挙の開始時に、各ノードが最初に考慮するマスターを選択します。ルールは非常に単純で、ID の辞書順に従ってソートし、最初のものを取得します。各ノードに認識されたマスターがない場合は、すべてのノードから選択します。ルールは上記と同じです。

ここには、discovery.zen.minimum_master_nodes という制限があります
。ノード数が最小制限に達しない場合、ノード数が選挙を開始するのに十分になるまで上記のプロセスが繰り返されます。最終的な選挙の結果、マスターが確実に選出され、ローカル ノードが 1 つしかない場合は、それ自体が選出されます。現在のノードがマスターの場合は、ノード数が Discovery.zen.minimum_master_nodes に達するまで待機を開始してから、サービスを提供します。現在のノードがマスターではない場合は、マスターへの参加を試みます。Elasticsearch では、上記のサービス検出とマスター選択のプロセスを ZenDiscovery と呼びます。

任意の数のクラスター (1 ~ N) をサポートするため、Zookeeper のようにノードの数を奇数に制限することはできません。また、マスターを選出するために投票メカニズムを使用することもできませんが、すべてのノードが従う限りルールを通過させる必要があります。同じルールであれば、取得される情報は同等であり、選択されたマスター ノードは一貫している必要があります。しかし、分散システムの問題点は、情報が不均等であることです。このとき、スプリットブレイン (Split-Brain) の問題が発生しやすくなります。ほとんどの解決策は、クォーラム値を設定することであり、利用可能なノードが外部サービスを提供するには、クォーラム (通常はノードの半分以上) より大きい必要があります。Elasticsearch では、クォーラム構成は
Discovery.zen.minimum_master_nodes です。

2) ノードの役割

各ノードは候補マスター ノードまたはデータ ノードのいずれかになります。これらは
構成ファイル .../config/elasticsearch.yml で設定でき、デフォルトは true です。

Copynode.master: true  //是否候选主节点
node.data: true    //是否数据节点

データ ノードは 、データのストレージと、データの追加、削除、変更、クエリ、集計などの関連操作を担当します。そのため、データ ノード (データ ノード) には、マシン構成に対する要件が比較的高く、CPU、メモリ、と I/O を大量に消費します。通常、クラスターが拡大するにつれて、パフォーマンスと可用性を向上させるために、より多くのデータ ノードを追加する必要があります。

マスター ノード候補は マスター ノード (マスター ノード) として選出できます。クラスタ内のマスター ノード候補のみが投票および選出される権利を持ち、他のノードは選挙に参加しません。マスター ノードは、インデックスの作成、インデックスの削除、クラスターの一部であるノードの追跡、関連するノードにどのシャードを割り当てるかの決定、クラスター内のノードのステータスの追跡などを行います。安定したマスター ノードは、安定したマスター ノードが非常に重要です。クラスターの健全性。

ノードはマスター ノードまたはデータ ノードの候補になりますが、データ ノードは CPU とメモリ コア I/0 を大量に消費するため、ノードがデータ ノードとマスター ノードの両方である場合、マスター ノードに影響を与える可能性があります。クラスター全体の状態に影響を与えます。

したがって、クラスターの健全性を改善するには、Elasticsearch クラスター内のノードの役割を分割して分離する必要があります。低構成のいくつかのマシン ファームをマスター ノード ファームの候補として使用できます。

マスター ノードと他のノードは Ping を通じて相互にチェックし、マスター ノードは他のすべてのノードに Ping を送信して、ハングアップしたノードがあるかどうかを判断する責任があります。他のノードも Ping を使用して、マスター ノードが利用可能かどうかを判断します。

ノードの役割は区別されていますが、ユーザーのリクエストはどのノードにも送信でき、マスターノードが転送することなく、ノードはリクエストの分散、結果の収集、その他の操作を担当します。この種のノードは調整ノードと呼ぶことができます。調整ノードを指定して構成する必要はなく、クラスター内の任意のノードが調整ノードとして機能できます。

3) スプリットブレイン現象

同時に、ネットワークなどの理由でクラスター内で複数のマスター ノードが選択され、データ更新に不整合が生じる場合、この現象はスプリット ブレインと呼ばれます。つまり、クラスター内の異なるノードがマスター ノードの選択に同意しません。マスター、および複数のAマスターコンテスト。

「スプリット ブレイン」問題は、次のようないくつかの理由で発生する可能性があります。

  • ネットワークの問題:クラスター間のネットワーク遅延により、一部のノードがマスターへのアクセスに失敗し、マスターがダウンしていると考えて新しいマスターを選択し、マスター上のシャードとレプリカを赤色でマークし、新しいマスター シャードを割り当てます。

  • ノード負荷:マスターノードの役割はマスターとデータの両方であり、大量のアクセスがあった場合、ESが応答しなくなり(擬似死亡状態)、広範囲の遅延が発生する場合があります。他のノードはマスター ノードから応答を取得できず、マスター ノードがハングアップしたと判断し、プライマリ ノードが再選択されます。

  • メモリ回復:マスター ノードの役割はマスターとデータの両方です。データ ノード上の ES プロセスが大量のメモリを占有すると、JVM の大規模なメモリ回復が発生し、ES プロセスの応答が失われます。 。

スプリット ブレイン現象を回避するには、理由から始めて、次の側面から最適化対策を講じることができます。

  • 応答時間を適切に増加して誤判定を減らす:パラメータdiscovery.zen.ping_timeoutを通じてノードステータスの応答時間を設定します、デフォルトは3秒であり、適切に調整できます応答範囲内でマスターが応答しない場合ノードがハングアップしたと判断します。パラメーター (6s、discovery.zen.ping_timeout:6 など) を増やすと、誤判定を適切に減らすことができます。

  • 選挙トリガー:候補クラスター内のノードの構成ファイルにパラメーター Discovery.zen.munimum_master_nodes の値を設定する必要があります。このパラメーターは、マスター ノードが選挙に参加する必要がある候補マスター ノードの数を示します。公式の推奨値は (master_eligibel_nodes/2) + 1 です (master_eligibel_nodes は候補マスター ノードの数です)。そうすることで、スプリット ブレイン現象の発生を防ぐだけでなく、discovery.zen.munimum_master_nodes 以上の候補ノードが生き残っている限り、選出は正常に続行できるため、クラスターの高可用性を最大限に高めることができます。この値より小さい場合、選出動作はトリガーされず、クラスターは使用できず、断片化の混乱は発生しません。

  • 役割の分離:前述したマスターノード候補とデータノードの役割を分離することで、マスターノードの負担を軽減し、マスターノードの誤った死亡を防ぎ、マスターノードが「異常である」という誤った判断を減らすことができます。死んだ"。

2. シャード

ES は PB レベルの全文検索をサポートしています。インデックス上のデータ量が大きすぎる場合、ES はインデックス上のデータを分割し、水平分割を通じて異なるデータ ブロックに分散します。分割されたデータベース ブロックはスライスとして呼び出されます。

これは MySql のサブデータベースとサブテーブルに似ていますが、Mysql のサブデータベースとサブテーブルはサードパーティのコンポーネントに依存する必要があり、ES がこの機能を内部的に実装する点が異なります。

マルチシャード インデックスにデータを書き込む場合、書き込まれる特定のシャードはルーティングによって決定されるため、インデックスの作成時にシャードの数を指定する必要があり、シャードの数が決定されると変更できません。

以下に説明するシャードの数とコピーの数は、インデックス作成時の設定で構成できます。デフォルトでは、ES はインデックスに対して 5 つのプライマリ シャードを作成し、シャードごとにコピーを作成します。

CopyPUT /myIndex
{
   "settings" : {
      "number_of_shards" : 5,
      "number_of_replicas" : 1
   }
}

ES は、インデックスのスケールとパフォーマンスを向上させるためにシャーディングの機能を使用します。各シャードは Lucene のインデックス ファイルであり、各シャードにはプライマリ シャードとゼロから複数のコピーが必要です。

3. レプリカ

レプリカはシャードのコピーです。各プライマリ シャードには 1 つ以上のレプリカ シャードがあります。プライマリ シャードが異常な場合、レプリカはデータ クエリやその他の操作を提供できます。プライマリ シャードと対応するレプリカ シャードは同じノード上に存在しないため、レプリカ シャードの最大数は n -1 になります (n はノードの数です)。

ドキュメントの新規作成、インデックス作成、削除リクエストはすべて書き込み操作であり、関連するレプリカ シャードにコピーする前にプライマリ シャードで完了する必要があります。ES の書き込み能力を向上させるために、このプロセスは同時に書き込まれます。同時に、同時実行性を解決するために、書き込みプロセス中のデータ競合の問題は、楽観的ロックを通じて ES によって制御されます。各ドキュメントには _version (バージョン) 番号があり、ドキュメントが変更されるとバージョン番号がインクリメントされます。すべてのレプリカ シャードが成功を報告すると、コーディネーター ノードに成功を報告し、コーディネーター ノードはクライアントに成功を報告します。

上の図から、高可用性を実現するために、マスター ノードはプライマリ フラグメントとレプリカ フラグメントを同じノードに配置することを回避していることがわかります。

この時点でノード Node1 サービスがダウンしているかネットワークが利用できないとすると、プライマリ ノード上のプライマリ シャード S0 も利用できなくなります。幸いなことに、正常に動作できる他の 2 つのノードがあります。この時点で、ES は新しいマスター ノードを再選択し、必要な S0 のすべてのデータはこれら 2 つのノードに存在します。S0 のコピーをアップグレードします。プライマリ シャード、プライマリ シャードのアップグレード プロセスは瞬時に行われます。この時点で、クラスターのステータスは黄色になります。

クラスターのステータスが緑色ではなく黄色なのはなぜですか? 2 つのプライマリ シャードがすべてありますが、各プライマリ シャードは 2 つのレプリカ シャードに対応する必要があることも設定されており、現時点ではレプリカ シャードが 1 つだけ存在します。したがって、クラスターが緑色の状態になることはありません。Node2 もシャットダウンしても、Node3 がシャードごとにコピーを保持しているため、プログラムはデータを失うことなく実行を続けることができます。

Node1 を再起動すると、クラスターは不足しているレプリカ フラグメントを再配布でき、クラスターの状態は元の通常の状態に戻ります。Node1 に以前のシャードがまだある場合は、それらを再利用しようとしますが、現時点では Node1 のシャードはプライマリ シャードではなくレプリカ シャードになっているため、変更されたデータ ファイルをシャードにコピーするだけです。

まとめ:

1) データのシャーディングは、処理できるデータの容量を増やし、水平方向の拡張を容易にするためのものであり、シャードのコピーを作成することは、クラスターの安定性を向上させ、同時実行の量を増やすためです。

2) コピーは増殖するものであり、多ければ多いほど消費量も多くなりますが、安全性は高くなります。シャーディングとは分割のことであり、シャードが増えれば増えるほど、単一シャード データの分散が少なくなります。

3) コピー数が多いほどクラスターの可用性は高くなりますが、各シャードは Lucene インデックス ファイルに相当するため、一定量のファイル ハンドル、メモリ、CPU を占有し、シャード間のデータ同期にも時間がかかります。ネットワーク帯域幅、つまりインデックスのフラグメントとコピーの数は多ければ多いほど良いのです。

4. マッピング

マッピングは、ドキュメントが持つ可能性のあるフィールドまたは属性とデータ型を記述するデータベース内のスキーマと同様に、ストレージ タイプ、単語分割方法、ES によるインデックス内のフィールドの格納かどうかなどの情報を定義するために使用されます。各分野の。リレーショナル データベースでテーブルを作成するときにフィールド タイプを指定する必要があるだけですが、ES ではフィールド タイプを指定して動的にフィールド タイプを推測したり、インデックスを作成するときにフィールド タイプを指定したりすることはできません。

データ形式に応じてフィールドの型を自動的に認識するマッピングを動的マッピング(Dynamic Mapping)と呼び、インデックス作成時にフィールドの型を具体的に定義するマッピングを静的マッピングまたは明示的なマッピング(Explicit Mapping)と呼びます。

動的マッピングと静的マッピングの使用を説明する前に、まず ES のデータにどのようなフィールド タイプがあるかを理解しましょう。後で、インデックスを作成するときに動的マッピングではなく静的マッピングを確立する必要がある理由について説明します。

ES (v6.8) のフィールド データ タイプには主に次のカテゴリが含まれます。

text 電子メールの本文や製品説明などの全文値のインデックスを作成するためのフィールド。これらのフィールドはトークン化され、インデックス付けされる前に文字列を個々の用語のリストに変換するためにトークナイザーに渡されます。分析プロセスにより、Elasticsearch は 1 つの単語内のすべての完全なテキスト フィールドを検索できます。テキスト フィールドは並べ替えには使用されず、集計にもほとんど使用されません。

キーワード 電子メール アドレス、ホスト名、ステータス コード、郵便番号、ラベルなどの構造化コンテンツのインデックスを作成するために使用されるフィールド。これらは通常、フィルタリング、並べ替え、集計に使用されます。キーワード フィールドは、正確な値でのみ検索できます。

フィールド タイプを理解すると、一部のフィールドを明確に定義する必要があることがわかります。たとえば、フィールドがテキスト タイプであるかキーワード タイプであるかは大きく異なります。時間フィールドには時間形式を指定する必要があるかもしれません。トークナイザーなど、いくつかのフィールドに特定のフィールドを指定します。これを動的マッピングで正確に行うことができない場合、自動認識は期待したものと多少異なることがよくあります。

したがって、インデックスを作成するときは、次のようにシャードとレプリカの数、およびマッピングの定義を指定する完全な形式にする必要があります。

CopyPUT my_index
{
   "settings" : {
      "number_of_shards" : 5,
      "number_of_replicas" : 1
   }
  "mappings": {
    "_doc": {
      "properties": {
        "title":    { "type": "text"  },
        "name":     { "type": "text"  },
        "age":      { "type": "integer" },
        "created":  {
          "type":   "date",
          "format": "strict_date_optional_time||epoch_millis"
        }
      }
    }
  }
}

4. 基本的な使い方

Elasticsearch の使用を決定する際に最初に考慮すべきことは、バージョンの問題です。Elasticsearch (0.x と 1.x を除く) には現在、一般的に使用される安定したメジャー バージョン 2.x、5.x、6.x、7 があります。 x (現在)。3.x と 4.x はなく、ES は 2.4.6 から 5.0.0 に直接ジャンプしたことがわかるかもしれません。

実際、これはユーザーの混乱を避けるために、ELK (ElasticSearch、logstash、kibana) テクノロジー スタックのバージョンを統一するためのものです。Elasticsearch が 2.x (2.4.6 の最後のバージョンは 2017 年 7 月 25 日にリリースされました) の場合、kibana はすでに 4.x (Kibana 4.6.5 は 2017 年 7 月 25 日にリリースされました) であり、次のメインkibana のバージョンは 5.x である必要があるため、Elasticsearch はメイン バージョンを 5.0.0 として直接リリースしました。統合後はバージョン選択に迷うことがなくなり、elasticsearchのバージョンを選択した後は同じバージョンのkibanaを選択できるため、バージョンの非互換性を気にする必要がなくなりました。

Elasticsearch は Java を使用して構築されているため、Elasticsearch のバージョンを選択する際には、ELK テクノロジーの統合バージョンに注意を払うことに加えて、JDK のバージョンにも注意する必要があります。各メジャー バージョンは異なる JDK バージョンに依存しているため、現在のバージョン 7.2 はすでに jdk11 をサポートしています。

1. インストールと使用方法

1) Elasticsearchをダウンロードし、解凍します 解凍すればインストール不要で利用可能になります 解凍後のディレクトリは以下の通りです。

  • bin: 起動コマンドやプラグインのインストールコマンドなどを含むバイナリシステムコマンドディレクトリ。
  • config: 設定ファイルのディレクトリ。
  • data: データ保存ディレクトリ。
  • lib: パッケージのディレクトリに依存します。
  • ログ: ログ ファイル ディレクトリ。
  • modules: x-pack モジュールなどのモジュール ライブラリ。
  • プラグイン: プラグインディレクトリ。

2) インストールディレクトリで bin/elasticsearch を実行して ES を起動します。

3) デフォルトでは、ポート 9200 で実行されます。curl http://localhost:9200/ をリクエストするか、ブラウザに http://localhost:9200 と入力して、現在のノード、クラスター、データベースなどの情報を含む JSON オブジェクトを取得します。そしてバージョン。

Copy{
  "name" : "U7fp3O9",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "-Rj8jGQvRIelGd9ckicUOA",
  "version" : {
    "number" : "6.8.1",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "1fad4e1",
    "build_date" : "2019-06-18T13:16:52.517138Z",
    "build_snapshot" : false,
    "lucene_version" : "7.7.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

2. クラスターの健全性ステータス

クラスターの健全性を確認するには、Kibana コンソールでコマンド GET /_cluster/health を実行し、次の情報を取得します。

Copy{
  "cluster_name" : "wujiajian",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 9,
  "active_shards" : 9,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 5,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 64.28571428571429
}

クラスタのステータスは緑、黄、赤で示されます。

  • 緑:クラスターは正常で、すべてが完全に機能し、すべてのシャードとレプリカが適切に動作しています。
  • 黄色:警告ステータス。すべてのプライマリ シャードは正常に機能していますが、少なくとも 1 つのレプリカが正常に動作していません。この時点でクラスターは機能しますが、高可用性がある程度損なわれます。
  • 赤:クラスタが正常に使用できません。1 つまたは一部のシャードとそのレプリカが異常に利用できません。現時点では、クラスターのクエリ操作は引き続き実行できますが、返される結果は不正確になります。このシャードに割り当てられた書き込みリクエストはエラーを報告し、最終的にはデータ損失につながります。

クラスターのステータスが赤の場合、クラスターは使用可能なシャードからの検索リクエストを処理し続けますが、割り当てられていないシャードをできるだけ早く修正する必要があります。

5. 機構原理

ES の基本概念と基本操作を紹介しても、まだ疑問が残るかもしれませんが、それらは内部でどのように機能するのでしょうか? プライマリ シャードとレプリカ シャードはどのように同期されますか? インデックスを作成するプロセスは何ですか? ES はインデックス データを異なるシャードにどのように分散しますか? そして、これらのインデックスデータはどのように保存されるのでしょうか? ES はほぼリアルタイムの検索エンジンであり、ドキュメントの CRUD (作成、読み取り、更新、削除) 操作がリアルタイムであると言われるのはなぜですか? そして、Elasticsearch は、電源がオフのときにデータを失わずに更新が永続化されることをどのように保証するのでしょうか? また、ドキュメントを削除してもすぐにスペースが解放されないのはなぜですか? これらの質問を踏まえて、次のコンテンツに進みます。

1. インデックス作成の原則

次の図は、4 つのプライマリ シャード (S0、S1、S2、S3) と 8 つのレプリカ シャード (R0、R1、R2、R3) を含む合計 12 のシャードを持つ 3 つのノードのクラスターを示しています。各プライマリ シャードはそれぞれに対応します。 2 つのレプリカ シャードがあり、ノード 1 はクラスター全体の状態を担当するプライマリ ノード (マスター ノード) です。

インデックスの書き込みはプライマリ シャードにのみ書き込め、その後レプリカ シャードに同期されます。ここには 4 つのプライマリ シャードがあります。データ ES はどのようなルールに従って特定のシャードに書き込まれますか? このインデックス データは S0 に書き込まれ、S1 または S2 には書き込まれないのはなぜですか? そのデータが S0 ではなく S3 に書き込まれるのはなぜですか?

まず第一に、これは決してランダムではありません。そうしないと、将来文書を入手したいときにどこを探せばよいのかわかりません。実際、このプロセスは次の式に従って決定されます。

Copyshard = hash(routing) % number_of_primary_shards

routing は変数値で、デフォルトはドキュメントの _id で、カスタム値に設定することもできます。ルーティングはハッシュ関数を通じて数値を生成し、この数値をnumber_of_primary_shards (プライマリ シャードの数) で割って余りを求めます。0 とnumber_of_primary_shards-1
の間の残りの部分は、探しているドキュメントが存在するシャードの場所です。

これは、インデックスの作成時にプライマリ シャードの数を決定し、この数を決して変更しない必要がある理由を説明しています。数が変更されると、以前のすべてのルーティング値が無効になり、ドキュメントが二度と見つからなくなるからです。

ES クラスター内の各ノードは、上記の計算式を通じてクラスター内のドキュメントの保存場所を知っているため、各ノードは読み取りおよび書き込みリクエストを処理する能力を持ちます。書き込みリクエストがノードに送信されると、そのノードは前述の調整ノードとなり、ルーティング式に従ってどのシャードに書き込むかを計算し、ノード上のシャードのメイン シャードにリクエストを転送します。 。

このときのデータの余りをルーティング計算式に通した値が shard = hash(routing) % 4 = 0 であるとすると、具体的な処理は以下のようになります。

1) クライアントが ES1 ノード (調整ノード) に書き込みリクエストを送信し、ルーティング計算式で得られた値が 0 の場合、現在のデータをプライマリ シャード S0 に書き込む必要があります。

2) ES1 ノードは、S0 プライマリ フラグメントが存在するノード ES3 にリクエストを転送し、ES3 はリクエストを受け入れてディスクに書き込みます。

3) 2 つのレプリカ シャード R0 にデータを同時にコピーします。この場合、データの競合はオプティミスティック同時実行によって制御されます。すべてのレプリカ フラグメントが成功を報告すると、ノード ES3 は調整ノードに成功を報告し、調整ノードはクライアントに成功を報告します。

2. 保管原理

上記はESの内部インデックスの書き込み処理プロセスです。この処理はESのメモリ上で実行され、データは特定のシャードとコピーに割り当てられた後、最終的にディスクに保存されます。データが失われることはありません。特定のストレージ パスは、
設定ファイル .../config/elasticsearch.yml で設定できます。このファイルは、デフォルトでインストール ディレクトリのデータ フォルダーに保存されます。ES をアップグレードするとすべてのデータが失われる可能性があるため、デフォルト値を使用しないことをお勧めします。

Copypath.data: /path/to/data  //索引数据
path.logs: /path/to/logs  //日志记录

1) セグメント化されたストレージ

インデックス ドキュメントはセグメントの形式でディスクに保存されます。セグメントとは何ですか? インデックス ファイルは複数のサブファイルに分割されており、各サブファイルはセグメントと呼ばれます。各セグメントは転置インデックスそのものであり、セグメントは不変です。インデックス データがハードディスクに書き込まれると、変更することはできません。最下層にセグメントストレージモードを採用することで、読み書き時のロックの発生をほぼ完全に回避し、読み書きのパフォーマンスを大幅に向上させます。

セグメントがディスクに書き込まれた後、コミット ポイントが生成されます。コミット ポイントは、コミット後のすべてのセグメント情報を記録するために使用されるファイルです。セグメントにコミット ポイントが設定されると、セグメントには読み取り権限のみが付与され、書き込み権限が失われます。逆に、セグメントがメモリ内にある場合、セグメントには書き込み権限のみがあり、データの読み取り権限はありません。つまり、データを取得することはできません。

セグメントの概念が提案されている主な理由は次のとおりです。 初期の全文検索では、文書コレクション全体に対して大規模な逆索引が確立され、ディスクに書き込まれていました。インデックスが更新された場合は、完全なインデックスを再作成して、元のインデックスを置き換える必要があります。この方法は、データ量が多い場合には非常に非効率であり、インデックスの作成コストが非常に高いため、データを頻繁に更新できず、適時性が保証されません。

インデックス ファイルはセグメントに保存され、変更できません。追加、更新、削除にはどのように対処すればよいでしょうか?

  • 追加:追加の処理は簡単で、データが新しいため、現在のドキュメントに新しいセグメントを追加するだけで済みます。

  • 削除:変更できないため、削除操作の場合、ドキュメントは古いセグメントから削除されませんが、新しい .del ファイルが追加され、これらの削除されたドキュメントのセグメント情報がファイルにリストされます。削除対象としてマークされたドキュメントはクエリで引き続き照合できますが、最終結果が返される前に結果セットから削除されます。

  • 更新:古いセグメントを変更してドキュメントの更新を反映することはできません。実際、更新は削除と追加の 2 つのアクションに相当します。古いドキュメントは .del ファイル内で削除対象としてマークされ、ドキュメントの新しいバージョンは新しいセグメントにインデックス付けされます。ドキュメントの両方のバージョンが 1 つのクエリで一致する可能性がありますが、削除された古いバージョンは結果セットが返される前に削除されます。

このセクションは変更不可として設定されているため、利点と欠点がいくつかあります。利点は主に次の点に現れます。

  • ロックは必要ありません。インデックスを更新しない場合は、複数のプロセスが同時にデータを変更することを心配する必要はありません。

  • インデックスがカーネルのファイルシステム キャッシュに読み込まれると、その不変性によりインデックスはそこに残ります。ファイル システム キャッシュに十分なスペースがある限り、ほとんどの読み取りリクエストはディスクにアクセスせずにメモリに直接送信されます。これにより、パフォーマンスが大幅に向上します。

  • 他のキャッシュ (フィルター キャッシュなど) は、インデックスの存続期間中常に有効です。データは変更されないため、データが変更されるたびに再構築する必要はありません。

  • 単一の大きな逆インデックスに書き込むと、データが圧縮され、ディスク I/O とメモリにキャッシュする必要があるインデックスの使用量が削減されます。

セグメントの不変性の欠点は次のとおりです。

  • 古いデータを削除する場合、古いデータはすぐには削除されませんが、.del ファイル内で削除済みとしてマークされます。古いデータはセグメントが更新された場合にのみ削除できるため、大量のスペースの無駄が発生します。

  • 頻繁に更新されるデータがあり、更新のたびに古いデータをマークするために新しいデータが追加される場合、多くの無駄なスペースが発生します。

  • 新しいデータが追加されるたびに、データを保存するために新しいセグメントが必要になります。セグメント数が多すぎると、ファイルハンドルなどのサーバーリソースの消費が非常に大きくなります。

  • すべての結果セットをクエリ結果に含めると、削除対象としてマークされた古いデータを除外する必要があるため、クエリの負担が増加します。

2) 遅延書き込み戦略

ストレージの形式を導入した後、インデックスをディスクに書き込むプロセスはどのようなものですか? fsync を直接呼び出して物理的にディスクに書き込むのでしょうか?

答えは明らかです。ディスクに直接書き込まれると、ディスクの I/O 消費量がパフォーマンスに深刻な影響を及ぼします。その後、書き込まれるデータの量が多くなると、ES が停止してフリーズし、クエリが実行されなくなります。迅速に対応できるようになります。この場合、ES は準リアルタイム全文検索エンジンとは言えなくなります。

書き込みパフォーマンスを向上させるために、ES は新しいデータが追加されるたびにディスクにセグメントを追加するのではなく、遅延書き込み戦略を採用します。

新しいデータがあると、最初にメモリに書き込まれ、メモリとディスクの間にファイル システム キャッシュがあり、デフォルトの時間 (1 秒) に達するか、メモリ内のデータが一定量に達すると、新しいデータがメモリに書き込まれます。リフレッシュ (Refresh) をトリガーし、メモリ内のデータを新しいセグメントに生成してファイル キャッシュ システムにキャッシュし、それからディスクにリフレッシュしてコミット ポイントを生成します。

ここでのメモリは ES の JVM メモリを使用しますが、ファイル キャッシュ システムはオペレーティング システムのメモリを使用します。新しいデータはメモリに書き込まれ続けますが、メモリ内のデータはセグメント形式で保存されていないため、検索機能は提供できません。メモリがファイル キャッシュ システムにフラッシュされると、新しいセグメントが生成され、そのセグメントはディスクへのフラッシュを待たずに検索のために開かれます。

Elasticsearch では、新しいセグメントを書き込んで開く軽量のプロセスはリフレッシュと呼ばれます (つまり、メモリがファイル キャッシュ システムにフラッシュされます)。デフォルトでは、各シャードは 1 秒ごとに自動的に更新されます。これが、Elasticsearch がリアルタイム検索に近いと言われる理由です。ドキュメントへの変更はすぐには検索に表示されませんが、1 秒以内に表示されるからです。また、手動でリフレッシュをトリガーすることもできます。POST /_refresh はすべてのインデックスをリフレッシュし、POST /nba/_refresh は指定されたインデックスをリフレッシュします。

ヒント:リフレッシュはコミットよりもはるかに軽い操作ですが、それでもパフォーマンスのオーバーヘッドが発生します。手動更新はテストを作成する場合に便利ですが、本番環境でドキュメントのインデックスが作成されるたびに手動で更新しないでください。また、すべてのケースを毎秒更新する必要があるわけではありません。Elasticsearch を使用して多数のログ ファイルのインデックスを作成している可能性があります。ほぼリアルタイムの検索ではなく、インデックス作成速度を最適化したい場合があります。このとき、refresh_interval = の値を増やすことで、各インデックスの値を減らすことができます。インデックスの更新頻度を作成するときの設定に「30 秒」があります。値を設定するときは、その背後にある時間単位に注意する必要があります。それ以外の場合、デフォルトはミリ秒です。fresh_interval = -1 の場合、インデックスの自動更新がオフになることを意味します。

遅延書き込み戦略は、データがディスクに書き込まれる回数を減らし、全体的な書き込み能力を向上させることができますが、ファイル キャッシュ システムはオペレーティング システムのメモリに属する​​メモリ空間でもあることがわかっています。メモリの電源がオフになっている場合、またはデータが失われる異常なリスクがある場合。

データ損失を避けるために、Elasticsearch はトランザクション ログ (Translog) を追加します。これは、まだディスクに保存されていないすべてのデータを記録します。トランザクション ログを追加した後、インデックスを書き込むプロセス全体を次の図に示します。

  • 新しいドキュメントのインデックスが作成されると、まずメモリに書き込まれますが、データの損失を防ぐために、データのコピーがトランザクション ログに追加されます。新しいドキュメントは常にメモリに書き込まれ、トランザクション ログにも記録されます。この時点では、新しいデータを取得したりクエリしたりすることはまだできません。

  • デフォルトのリフレッシュ時間に達するか、メモリ内のデータが一定量に達すると、リフレッシュがトリガーされ、メモリ内のデータが新しいセグメントの形式でファイル キャッシュ システムにリフレッシュされ、メモリがクリアされます。現時点では、新しいセグメントはディスクに送信されていませんが、ドキュメントの検索機能を提供でき、変更することはできません。

  • 新しいドキュメント インデックスが継続的に書き込まれるため、ログ データ サイズが 512M を超えるか、時間が 30 分を超えると、フラッシュがトリガーされます。メモリ内のデータは新しいセグメントに書き込まれると同時にファイル キャッシュ システムに書き込まれ、ファイル システム キャッシュ内のデータは fsync によってディスクにフラッシュされ、コミット ポイントが生成され、ログ ファイルが削除され、空の新しいログが作成されます。

このように、電源がオフになっている場合、または再起動する必要がある場合、ES は送信ポイントに従って永続化されたセグメントをロードする必要があるだけでなく、永続化されていないデータをディスクに再永続化するために Translog ツール内のレコードも必要になります。データ損失の可能性を回避します。

3) セグメントのマージ

自動更新プロセスでは 1 秒ごとに新しいセグメントが作成されるため、短期間にセグメント数が急増する可能性があります。また、セグメントの数が多すぎると、より大きな問題が発生します。各セグメントはファイル ハンドル、メモリ、CPU サイクルを消費します。さらに、各検索リクエストは各セグメントを順番に調べてクエリ結果を結合する必要があるため、セグメントが多いほど検索は遅くなります。

Elasticsearch は、バックグラウンドで定期的にセグメントのマージを実行することで、この問題を解決します。小さなセグメントは大きなセグメントにマージされ、さらに大きなセグメントがさらに大きなセグメントにマージされます。これらの古い削除されたドキュメントは、セグメントがマージされるときにファイル システムから消去されます。削除されたドキュメントは、新しい大きなセクションにはコピーされません。インデックス作成と検索はマージ中に中断されません。

セグメントのマージは、インデックス作成および検索中に自動的に行われます。マージ プロセスでは、同様のサイズのセグメントの小さなセットが選択され、バックグラウンドでそれらがより大きなセグメントにマージされます。セグメントは、コミットされていない場合とコミットされていない場合があります。マージ後、古いセグメントが削除され、新しいセグメントがディスクにフラッシュされ、新しいセグメントを含む新しいコミット ポイント (古いマージされたセグメントは除外されています) が同時に書き込まれ、新しいセグメントは検索のために開かれます。

セグメントのマージは膨大な量の計算を必要とし、大量のディスク I/O を消費します。セグメントのマージにより書き込み速度が低下し、チェックを外したままにすると検索パフォーマンスに影響します。Elasticsearch はデフォルトでマージ プロセスにリソース制限を設けているため、検索を適切に実行するのに十分なリソースがまだあります。

6. パフォーマンスの最適化

1) ストレージデバイス

最近のサーバーではディスクがボトルネックになることがよくあります。Elasticsearch はディスクを大量に使用するため、ディスクが処理できるスループットが高くなるほど、ノードの安定性が高まります。ディスク I/O を最適化するためのヒントをいくつか紹介します。

  • SSDを使用します。他の場所で述べたように、それらは機械式ディスクよりもはるかに優れています。

  • RAID0を使用します。ストライピング RAID では、ディスク I/O が増加しますが、1 台のハード ドライブに障害が発生すると、当然のことながら障害が発生します。ミラーリングまたはパリティ RAID は、レプリカがすでにこの機能を提供しているため、使用しないでください。

  • あるいは、複数のハードドライブを使用し、Elasticsearch が複数の path.data ディレクトリ構成を介してハードドライブ全体にデータをストライプ化できるようにします。

  • NFS や SMB/CIFS など、リモートにマウントされたストレージは使用しないでください。この遅延が発生すると、パフォーマンスに完全に逆効果になります。

  • EC2 を使用している場合は、EBS に注意してください。SSD ベースの EBS であっても、通常はローカル インスタンス ストレージよりも低速です。

2) 内部インデックスの最適化

特定の用語をすばやく見つけるために、Elasticsearch は最初にすべての用語をソートし、次に二分法に従って用語を検索します。時間計算量は logN であり、辞書を検索するのと同じです。これが用語辞書です。今見ると、従来のデータベースが B-Tree を使用する方法と似ているように思えます。

ただし、用語が多すぎると、用語辞書が非常に大きくなり、メモリに保存するのは非現実的です。そのため、辞書の索引ページのような用語索引が用意されています。ページがそれらである場合、インデックスという用語はツリーであることが理解できます。このツリーにはすべての用語が含まれているわけではなく、用語のいくつかの接頭辞が含まれています。用語インデックスを使用すると、用語辞書内の特定のオフセットをすばやく見つけ、その位置から順番に検索できます。

FST を使用して、メモリ内の用語インデックスを圧縮します。FST では、すべての用語がバイト単位で保存されます。この圧縮方法では、ストレージ スペースを効果的に削減できるため、用語インデックスがメモリに十分収まるようになりますが、この方法ではより多くの CPU リソースが必要になります。 。

ディスクに保存される投稿リストについては、ストレージの占有容量を削減するために圧縮技術も使用されます。

3) 設定パラメータを調整する

  • 各ドキュメントに、適切に圧縮されたシーケンス パターンを使用して順序付けされた ID を割り当てます。圧縮率が低く、Lucene の速度が大幅に低下する UUID-4 のようなランダム ID は避けてください。

  • 集計と並べ替えを必要としないインデックス フィールドの Doc 値を無効にします。ドキュメント値は、ドキュメント => フィールド値に基づくマッピングの順序付きリストです。

  • ファジー検索を必要としないフィールドの場合は、インデックス作成前にこれらのテキストの単語分割を避けるために、テキスト タイプの代わりにキーワード タイプを使用します。

  • 検索結果にほぼリアルタイムの精度が必要ない場合は、index.refresh_interval をインデックスごとに 30 秒に変更することを検討してください。一括インポートを実行している場合は、この値を -1 に設定することでインポート中の更新をオフにすることができます。また、index.number_of_replicas: 0 を設定することでレプリカをオフにすることもできます。完了したら、忘れずにオンに戻してください。

  • 深いページング クエリを回避するには、ページング クエリに Scroll を使用することをお勧めします。通常のページング クエリでは、from + サイズの空の優先キューが作成され、各フラグメントは from + size 個のデータを返します。デフォルトでは、ドキュメント ID とスコアスコアのみが調整ノードに送信されます。 n 個のフラグメントがある場合、調整ノードは次に (+ サイズから) × n 個のデータを 2 回ソートし、取得する必要があるドキュメントを選択します。from が大きいと、ソート処理が非常に重くなり、CPU リソースを著しく占有します。

  • マップされたフィールドの数を減らして、取得、集計、または並べ替えが必要なフィールドのみを提供します。他のフィールドは Hbase などの他のストレージ デバイスに保存でき、ES で結果を取得した後、Hbase に移動してこれらのフィールドをクエリします。

  • インデックスとクエリを作成するときにルーティング値を指定します。これにより、特定のシャード クエリに対して正確になり、クエリの効率が向上します。ルーティングの選択では、データのバランスのとれた分散に注意を払う必要があります。

4) JVM チューニング

  • プログラムが実行時にヒープ メモリ サイズを変更しないように、ヒープ メモリの最小サイズ ( Xms ) と最大サイズ ( Xmx ) が同じであることを確認してください。インストール後に Elasticsearch によって設定されるヒープ メモリは、デフォルトで 1 GB です。.../config/jvm.option ファイルを使用して構成できますが、物理メモリの 50% を超えず、32GB を超えないようにすることが最善です。

  • GC はデフォルトで CMS 方式を採用しており、同時実行ですが STW の問題があるため、G1 コレクターの使用を検討できます。

  • ES はファイル システム キャッシュ (ファイルシステム キャッシュ)、高速検索に大きく依存しています。一般に、使用可能なメモリの少なくとも半分がファイル システム キャッシュに物理的に割り当てられていることを確認する必要があります。

おすすめ

転載: blog.csdn.net/dyuan134/article/details/130220330