SolrCloud分散リクエスト

Solrノードが検索リクエストを受信すると、リクエストは自動的に、検索対象のコレクションの一部であるシャードのレプリカにルーティングされます。

選択されたレプリカは、集約者として機能します。コレクション内のすべてのシャードのランダムに選択されたレプリカへの内部リクエストを作成し、レスポンスを調整し、必要に応じて後続の内部リクエスト(ファセット値を絞り込んだり、追加の保存済みフィールドを要求したりする場合など)を発行し、クライアントの最終的なレスポンスを構築します。

クエリフォールトトレランス

SolrCloudクラスタでは、各ノードはコレクション内のすべてのレプリカに読み取りリクエストをロードバランスします。クラスタと通信する「外部」のロードバランサが必要になる場合もあります。または、ZooKeeperのSolrのメタデータを読み取り、やり取りする方法を理解し、ZooKeeperアンサンブルのアドレスのみを要求して、どのノードがリクエストを受信するべきかを検出するクライアントが必要です。Solrは、これを実行できるCloudSolrClientと呼ばれるスマートなJava SolrJクライアントを提供します。

クラスタ内のいくつかのノードがオフラインになっているか、到達不能な場合でも、Solrノードは、少なくともすべてのシャードの1つのレプリカ、またはユーザーがshardsまたは_route_パラメータを使用して検索を制限した場合、すべての関連するシャードの1つのレプリカと通信できれば、検索リクエストに正しく応答できます。各シャードのレプリカが多いほど、ノード障害が発生した場合でもSolrクラスタが検索結果を処理できる可能性が高くなります。

zkConnectedパラメータ

Solrノードは、リクエストを受信した時点でZooKeeperと通信できなくても、認識しているすべてのシャードの少なくとも1つのレプリカと通信できれば、検索リクエストの結果を返します。これは通常、フォールトトレランスの観点から好ましい動作ですが、ノードがZooKeeperから通知されていないコレクション構造の大きな変更(シャードの追加、削除、サブシャードへの分割など)があった場合、古い結果または不正確な結果になる可能性があります。

リクエストを処理したノードがリクエスト時点でZooKeeperに接続されていたかどうかを示すzkConnectedヘッダーが、すべての検索レスポンスに含まれています。

zkConnectedを含むSolrレスポンス
{
  "responseHeader": {
    "status": 0,
    "zkConnected": true,
    "QTime": 20,
    "params": {
      "q": "*:*"
    }
  },
  "response": {
    "numFound": 107,
    "start": 0,
    "docs": [ "..." ]
  }
}

リクエストを処理するノードがZooKeeperと通信できない場合に古い結果や不正確な結果を防ぐには、shards.tolerantパラメータをrequireZkConnectedに設定します。これにより、zkConnectedヘッダーをfalseに設定するのではなく、リクエストが失敗します。

shards.tolerantパラメータ

クエリされた1つ以上のシャードが利用できない場合、Solrのデフォルトの動作はリクエストを失敗させることです。ただし、部分的な結果が許容される多くのユースケースがあるため、Solrはブール値のshards.tolerantパラメータ(デフォルトはfalse)を提供します。truefalseに加えて、shards.tolerantrequireZkConnectedにも設定できます。以下を参照してください。

shards.tolerant=trueの場合、部分的な結果が返される可能性があります。返されたレスポンスに適切なすべてのシャードからの結果が含まれていない場合、レスポンスヘッダーにはpartialResultsと呼ばれる特別なフラグが含まれます。

shards.tolerant=requireZkConnected であり、検索リクエストを処理しているノードがZooKeeperと通信できない場合、潜在的に古いまたは不正確な結果を返すよりも、リクエストは失敗します。これは、shards.tolerant=false の場合と同様に、1つ以上のクエリ対象シャードが完全に利用できない場合にも、リクエストの失敗を引き起こします。

クライアントは、より詳細な情報を取得するために、shards.tolerant パラメータと共にshards.info を指定できます。

partialResults フラグがtrueに設定された場合のレスポンス例

partialResultsを含むSolrレスポンス
{
  "responseHeader": {
    "status": 0,
    "zkConnected": true,
    "partialResults": true,
    "QTime": 20,
    "params": {
      "q": "*:*"
    }
  },
  "response": {
    "numFound": 77,
    "start": 0,
    "docs": [ "..." ]
  }
}

distrib.singlePass パラメータ

trueに設定すると、distrib.singlePass パラメータは分散検索アルゴリズムを変更し、最初のフェーズですべての要求された保存済みフィールドを各シャードからフェッチします。これにより、保存済みフィールドをフェッチするための2回目のリクエストを行う必要がなくなります。

これは、非常に少ない数の小さな値を含むフィールドを要求する場合に高速化できます。ただし、大きなフィールドを要求する場合や、多くのフィールドを要求する場合は、すべてのシャードからネットワーク経由でそれらをフェッチするオーバーヘッドにより、通常の分散検索パスと比較してリクエストが遅くなる可能性があります。

この最適化は、分散検索のみに適用されます。ファセットなどの特定の機能では、リファインメントなどに対して追加のネットワークリクエストが行われる場合があります。

ルーティングクエリ

クエリがどのようにルーティングされるかを制御する方法はいくつかあります。

クエリ対象シャードの制限

SolrCloudを使用する利点の1つは、さまざまなシャードに分散された非常に大規模なコレクションをクエリできることです。ただし、場合によっては、特定のドキュメントルーティングを使用してSolrを構成している場合があります。データ全体またはその一部を検索するオプションがあります。

SolrCloudはクエリを自動的にロードバランスするため、コレクションのすべてのシャードにわたるクエリは、shardsパラメータを定義しないクエリにすぎません。

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*

これは、クエリを分散するためにshardsパラメータが必要となる、ユーザー管理クラスタとは対照的です。

クエリを1つのシャードのみに制限するには、論理IDでシャードを指定するshardsパラメータを使用します(例:…)

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1

複数のシャードを検索する場合は、1つのリクエストでコンマで区切って各シャードを指定できます。

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1,shard2

上記の両方の例では、特定のシャードのみがクエリ対象となりますが、シャードの任意のレプリカがリクエストを受け取ります。

シャードIDの代わりに、使用するレプリカのリストをコンマで区切って指定することもできます。

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=localhost:7574/solr/gettingstarted,localhost:8983/solr/gettingstarted

または、パイプ記号(|)を使用して異なるレプリカIDを区切ることで、単一シャードのレプリカのリストを指定してロードバランシングを行うことができます。

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=localhost:7574/solr/gettingstarted|localhost:7500/solr/gettingstarted

最後に、コンマで区切られたシャードのリスト(それぞれパイプで区切られたレプリカのリストで定義)を指定できます。

次の例では、2つのシャードがクエリ対象となります。1つ目はshard1からのランダムなレプリカ、2つ目は明示的にパイプで区切られたリストからのレプリカです。

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1,localhost:7574/solr/gettingstarted|localhost:7500/solr/gettingstarted

shards.preference パラメータ

Solrでは、shards.preferenceというオプションの文字列パラメータを渡して、分散クエリで各シャード内の利用可能なレプリカを優先順位の順にソートすることを指定できます。

構文は次のとおりです。shards.preference=property:value。プロパティと値の順序は重要です。最初のものが主要なソート基準、2番目が2番目のソート基準などとなります。

shards.preferenceは、SolrJクライアントを使用する場合にのみ、単一シャードのシナリオでサポートされます。SolrJクライアントを使用しないクエリでは、単一シャードのコレクションでshards.preferenceを使用できません。

指定できるプロパティは次のとおりです。

replica.type

優先される1つ以上のレプリカタイプ。PULLTLOGNRTの任意の組み合わせが許可されます。

replica.location

優先される1つ以上のレプリケーションの場所。

場所はhttp://hostname:portで始まります。指定された文字列をプレフィックスとして一致させるため、ポートを省略することもできます。

特別な値localは、クエリを処理しているものと同じSolrインスタンスで実行されているローカルレプリカを表すために使用できます。これは、ドキュメントごとに多くのフィールドまたは大きなフィールドを返すクエリを要求する場合に役立ちます。ローカルにある場合、大量のデータをネットワーク経由で移動する必要がないためです。さらに、この機能は、パフォーマンスが低下した問題のあるレプリカの影響を最小限に抑えるのに役立ちます。健全なレプリカが問題のあるレプリカにヒットする可能性が低くなるためです。

コレクション内の(ローカルに利用可能なレプリカを持たない)シャードの数が増えると、replica.location:localの値は減少します。クエリコントローラは、ほとんどのシャードに対してクエリをローカル以外のレプリカに指示する必要があるためです。

言い換えれば、この機能は、少数のシャードと多くのレプリカを持つコレクションに向けられたクエリを最適化する場合に最も役立ちます。

また、クエリ対象のコレクションのレプリカをホストするすべてのノード間でリクエストをロードバランシングしている場合(SolrのCloudSolrClientが行うように)にのみ、このオプションを使用する必要があります。ロードバランシングを行わない場合、クエリがクラスタ全体に均等に分散されないため、クラスタにホットスポットが発生する可能性があります。

replica.base

固有のレプリカ属性によるソート後に適用されるこのプロパティは、優先順位が等しいレプリカのセット間のフォールバック順序を定義します。指定された場合、このプロパティには1つの値しか指定できず、最後に指定する必要があります。

random(デフォルト)は、各リクエストに対してレプリカをランダムにシャッフルします。これによりリクエストは均等に分散されますが、レプリケーションファクタが1より大きいシャードでは、キャッシュの使用が最適化されない可能性があります。

stable:dividend:_paramName_ は、指定されたパラメータ名に関連付けられた値から整数を解析します。この整数は、被除数(剰余等価レプリカ数)として使用され、(リスト回転を介して)等価レプリカ間の優先順位を決定します。

stable[:hash[:_paramName_]] 指定されたパラメータ名に関連付けられた文字列値は、レプリカの優先順位を決定するために使用される被除数にハッシュされます(上記の明示的なdividendプロパティと同様)。paramNameは、指定されていない場合はqがデフォルトとなり、「メインクエリ」の文字列値にキー付けされた安定したルーティングを提供します。これは、一部のユースケース(パラメータ置換を利用する静的なメインクエリなど)には不適切な場合があります。

replica.leader

リーダーの状態に基づいてレプリカを優先します。trueまたはfalseに設定します。

2つのTLOGレプリカと4つのPULLレプリカを持つシャード(合計6つのレプリカ、そのうちの1つがリーダー)を考えてみましょう。shards.preference=replica.leader:falseの場合、6つのレプリカのうち5つが優先されます。これとshards.preference=replica.type:PULLを比較すると、6つのレプリカのうち4つのみが優先されます。

リーダーではないTLOGレプリカは、検索の観点からはPULLレプリカのように動作することに注意してください。リーダーからインデックスの更新をプルし、ソフトコミットを実行しません。違いは、リーダーではないTLOGレプリカもそのTLOGに更新をキャプチャすることです。そのため、現在のリーダーが失われた場合に、リーダーに置き換わる候補となります。

node.sysprop

クエリは、現在のものと同じ定義済みシステムプロパティを持つノードにルーティングされます。たとえば、異なるラックでSolrノードを起動する場合は、システムプロパティ(例:-Drack=rack1)でこれらのノードを識別する必要があります。その後、クエリにshards.preference=node.sysprop:sysprop.rackを含めることで、常に同じrack値を持つシャードにヒットするようにできます。

:

  • 優先順位が等しいレプリカ間で安定したルーティング(クライアントの「sessionId」パラメータにキー付け)を優先

    shards.preference=replica.base:stable:hash:sessionId&sessionId=abc123
  • PULLレプリカを優先

    shards.preference=replica.type:PULL
  • PULLレプリカを優先し、PULLレプリカが利用できない場合はTLOGレプリカを優先

    shards.preference=replica.type:PULL,replica.type:TLOG
  • ローカルレプリカを優先

    shards.preference=replica.location:local
  • "server1"というホスト上のレプリカを優先し、2番目のオプションとして"server2"を使用

    shards.preference=replica.location:http://server1,replica.location:http://server2
  • 利用可能な場合はPULLレプリカを優先し、そうでない場合はTLOGレプリカを優先し、その中でローカルレプリカを優先

    shards.preference=replica.type:PULL,replica.type:TLOG,replica.location:local
  • ローカルレプリカを優先し、その中で利用可能な場合はPULLレプリカを優先し、そうでない場合はTLOGレプリカを優先

    shards.preference=replica.location:local,replica.type:PULL,replica.type:TLOG
  • リーダーではないレプリカを優先

    `shards.preference=replica.leader:false`

これらのパラメータをクエリ文字列で指定する場合は、適切にURLエンコードする必要があります。

collection パラメータ

collectionパラメータを使用すると、クエリを実行するコレクションまたは複数のコレクションを指定できます。これにより、複数のコレクションを一度にクエリすることができ、分散方式で動作するSolrの機能はコレクション全体で動作します。

https://127.0.0.1:8983/solr/collection1/select?collection=collection1,collection2,collection3

_route_ パラメータ

_route_パラメータを使用して、対応するシャードを特定するために使用されるルートキーを指定できます。たとえば、一意のキー「user1!123」を持つドキュメントがある場合、ルートキーを「route=user1!」 (末尾の「!」文字に注意)として指定すると、そのユーザーをホストするシャードにリクエストがルーティングされます。コンマで区切って複数のルートキーを指定できます。このパラメータは、ユーザーごとにシャードデータがある場合に利用できます。ドキュメントルーティングの詳細を参照してください。

https://127.0.0.1:8983/solr/collection1/select?q=*:*&_route_=user1!
https://127.0.0.1:8983/solr/collection1/select?q=*:*&_route_=user1!,user2!

ニアリアルタイム(NRT)ユースケース

ニアリアルタイム(NRT)検索とは、ドキュメントがインデックス付けされた直後に検索に使用できるようになることを意味します。NRT検索はSolrCloudの主要な機能の1つであり、ユーザー管理クラスタや単一ノードインストールではめったに試みられません。

ドキュメントの耐久性と検索可能性はcommitsによって制御されます。「ニアリアルタイム」の「ニア」は、アプリケーションのニーズに合わせて設定できます。コミットは「ハード」または「ソフト」のいずれかで、クライアント(SolrJなど)によるREST呼び出し、またはsolrconfig.xmlで自動的に行われるように設定できます。通常は、コミット戦略をsolrconfig.xmlで設定し(下記参照)、外部からコミットを発行しないことをお勧めします。

通常、NRTアプリケーションでは、ハードコミットはopenSearcher=falseで設定され、ソフトコミットはドキュメントを検索可能にするために設定されます。

コミットが発生すると、セグメントのマージなど、さまざまなバックグラウンドタスクが開始されます。これらのバックグラウンドタスクは、インデックスへの追加の更新をブロックしたり、ドキュメントの検索への可用性を遅延させたりしません。

NRT用に設定する際には、キャッシュとautowarmの設定に特に注意してください。これらはNRTのパフォーマンスに大きな影響を与える可能性があります。非常に短いautoCommit間隔の場合、キャッシングとautowarmingを完全に無効にすることを検討してください。

ShardHandlerFactoryの設定

より細かい制御のために、Solrの分散検索内で使用される並行処理とスレッドプーリングの側面を直接設定および調整できます。デフォルトの設定は、レイテンシよりもスループットを優先しています。

これは、検索ハンドラの構成でshardHandlerFactoryを定義することによって行われます。

標準の検索ハンドラにshardHandlerFactoryを追加するには、この例のようにsolrconfig.xmlに設定を提供します。

<requestHandler name="/select" class="solr.SearchHandler">
  <!-- other params go here -->
  <shardHandlerFactory class="HttpShardHandlerFactory">
    <int name="socketTimeout">1000</int>
    <int name="connTimeout">5000</int>
  </shardHandlerFactory>
</requestHandler>

HttpShardHandlerFactoryは、Solrにすぐに含まれている唯一のShardHandlerFactory実装です。

注記

shardHandlerFactoryは、ノード間の通信を許可するノードを制御するsolr.xmlで設定されたallowUrlsパラメータに依存しています。これは、ホストの設定がコアごとまたはコレクションごとではなく、グローバルであることを意味します。詳細は、allowUrlsセクションを参照してください。

HttpShardHandlerFactoryは、次のパラメータを受け入れます。

socketTimeout

オプション

デフォルト:0

ソケットが待機できる時間(ミリ秒単位)。デフォルトは0で、オペレーティングシステムのデフォルトが使用されます。

connTimeout

オプション

デフォルト:0

ソケットのバインド/接続に許容される時間(ミリ秒単位)。デフォルトは0で、オペレーティングシステムのデフォルトが使用されます。

maxConnectionsPerHost

オプション

デフォルト:100000

分散検索で各シャードに作成される同時接続の最大数。

corePoolSize

オプション

デフォルト:0

分散検索の調整に使用されるスレッド数の維持される最低限の数。

maximumPoolSize

オプション

デフォルト:Integer.MAX_VALUE

分散検索の調整に使用されるスレッドの最大数。

maxThreadIdleTime

オプション

デフォルト:5

負荷の減少に応じてスレッドの数を減らす前に待機する時間(秒単位)。

sizeOfQueue

オプション

デフォルト:-1

指定されている場合、スレッドプールは直接ハンドオフバッファではなく、バッキングキューを使用します。高スループットシステムでは、これを直接ハンドオフ(-1)に設定することをお勧めします。レイテンシを改善したいシステムでは、リクエストの変動に対応するために、適切なサイズのキューを設定することをお勧めします。

fairnessPolicy

オプション

デフォルト:false

フェアポリシーキューイングに関するJVMの仕様を選択します。有効にすると、分散検索は先入れ先出し方式で処理されますが、スループットのコストがかかります。無効にすると、レイテンシよりもスループットが優先されます。

分散逆文書頻度 (IDF)

関連性の計算には、ドキュメントと用語の統計が必要です。分散システムでは、これらの統計はノードによって異なるため、スコアリング計算にバイアスや不正確さが生じる可能性があります。

Solrは、ドキュメントと用語の統計をstatsCacheと呼ばれるキャッシュに格納します。ドキュメント統計の計算に関しては、すぐに使用できる実装が4つあります。

  • LocalStatsCache:これは、関連性の計算にローカルの用語とドキュメントの統計のみを使用します。シャード間で用語の分布が均一な場合は、これは合理的に機能します。<statsCache>が設定されていない場合は、これがデフォルトのオプションです。

  • ExactStatsCache:この実装は、ドキュメント頻度に対してグローバルな値(コレクション全体)を使用します。ノード間で正確なスコアリングが実装にとって重要である場合は、このオプションを選択することをお勧めします。

  • ExactSharedStatsCache:これは機能においてExactStatsCacheに似ていますが、グローバル統計は同じ用語を持つ後続のリクエストで再利用されます。

  • LRUStatsCache:この実装は、グローバル統計を保持するために、最後に使用されたキャッシュを使用します。グローバル統計はリクエスト間で共有されます。

実装は、solrconfig.xml<statsCache>を設定することで選択できます。たとえば、次の行はSolrでExactStatsCache実装を使用するようにします。

<statsCache class="org.apache.solr.search.stats.ExactStatsCache"/>

分散デッドロックの回避

各シャードはトップレベルのクエリリクエストを処理し、他のすべてのシャードにサブリクエストを作成します。HTTPリクエストを処理するスレッドの最大数が、トップレベルのクライアントと他のシャードの両方からのリクエストの可能な数よりも多くなるように注意する必要があります。そうでない場合、構成により分散デッドロックが発生する可能性があります。

たとえば、HTTPリクエストを処理するスレッドが1つしかない2つのシャードの場合、デッドロックが発生する可能性があります。両方のスレッドは同時にトップレベルのリクエストを受け取り、互いにサブリクエストを作成する可能性があります。リクエストを処理するスレッドが残っていないため、着信リクエストは他の保留中のリクエストが完了するまでブロックされますが、サブリクエストを待機しているため、完了しません。Solrが十分な数のスレッドを処理するように設定することで、このようなデッドロック状況を回避できます。

分散トレースとデバッグ

値がtrackであるdebugパラメータを使用して、リクエストをトレースし、分散リクエストの各フェーズのタイミング情報を取得できます。