Solr Performance Factors

この記事は [SolrPerformanceFactors](https://cwiki.apache.org/confluence/display/solr/SolrPerformanceFactors) を翻訳したものです。

こちらもご覧ください: [SolrPerformanceData](https://cwiki.apache.org/confluence/display/SOLR/SolrPerformanceData), [BenchmarkingSolr](https://cwiki.apache.org/confluence/display/SOLR/SolrPerformanceProblems) , [SolrPerformanceProblems](https://cwiki.apache.org/confluence/display/SOLR/BenchmarkingSolr)

## スキーマ設計の考慮事項

### indexed フィールド

インデックスされるフィールドの数は、以下を大幅に増加させます。

- インデックス作成時のメモリ使用量
- セグメントのマージ時間
- optimize(最適化) の時間
- インデックスサイズ

これらの影響は、`omitNorms="true"` を使用することで減らすことができます。

### storedフィールド

クエリ結果としてstoredフィールドの値を取得するには、かなりのコストがかかる可能性があります。このコストはドキュメントごとに保存されるバイト数に大きく影響されます。バイト数が多いほど、ドキュメントはディスク上に分散され、フィールドを取得するために多くのI/Oが必要になります。（通常これはドキュメントのコンテンツ全体など、大きなフィールドを保存する場合に問題になります）

大きなフィールドをSolrの外に保存することを検討してください。それでも保存したい場合は、圧縮フィールドの使用を検討してください。これによりフィールドの保存と取得のCPUコストは増加しますが、I/O負荷とCPU使用率は低下します。

storedフィールドを常にすべて使用しているわけではない場合、遅延フィールド読み込みを有効にすると大きな恩恵を得られます。圧縮フィールドが使用されている場合は特に大きなメリットを得られます。


## 設定に関する考慮事項

### mergeFactor

mergeFactor は、セグメントの数を大まかに決定します。

mergeFactorの値は、同じ大きさのセグメントをいくつ作成したらそれらを一つのセグメントにまとめるのかをLuceneに伝えます。これは、基数と考えることができます。

たとえば mergeFactor を 10 に設定すると、1000 (あるいは maxBufferedDocs) 個のドキュメントがインデックスに追加されるたびに 新しいセグメントがディスク上に作成されることになります。サイズ 1000 のセグメントが 10 個目まで追加されると、 10 個すべてがサイズ 10,000 の単一のセグメントにマージされます。10,000 サイズのセグメントが 10 個追加されると、それらは 100,000 ドキュメントを含む単一のセグメントにマージされます。したがって、各インデックスサイズに含まれるセグメント数は、 常に9個までとなる。

これらの値は、solrconfig.xmlの*mainIndex*セクションで設定します（indexDefaultsセクションは無視してください）

#### mergeFactorのトレードオフ

大きいmergeFactor（例: 25）の場合

長所： 一般的にインデックス作成速度が向上する。
短所: マージの頻度が低く、検索が遅くなる可能性のある、より多くのインデックスファイルを持つコレクションになる。

小さいmergeFactor (例: 2)の場合

長所: インデックスファイルの数が少なくなり、検索が高速化する。
短所: セグメントのマージが多くなると、インデックスの作成が遅くなる。

### HashDocSetの最大サイズに関する考慮事項

hashDocSetはsolrconfig.xmlで指定される最適化で、セット内のアイテム数がmaxSize未満の場合にフィルター（docSet）のintハッシュ表現を可能にします。より小さいセットでは、この表現はよりメモリ効率がよく、より効率的に反復し、より高速に共通部分を計算することができます。

hashDocSetの最大サイズは、主にコレクション内のドキュメント数に基づいて決定されるべきです。ドキュメント数が多ければ多いほど、hashDocSetの最大サイズは大きくなります。試行錯誤を繰り返して、最適なサイズを決めてください

1. 保存するドキュメントの総数の0.5%を計算します
1. その値の「両側」の値を試して、最適なクエリ時間を求めます。
1. クエリータイムが頭打ちになり、高い方と低い方とでパフォーマンスに大差がなくなったら、高い方を使用する。

> 注：hashDocSetはバージョン1.4.0からSolrの一部ではなくなりました。

### キャッシュの autoWarm カウントに関する考慮事項

新しい searcher が開かれると、そのキャッシュは古い searcherのキャッシュからあらかじめキャッシュされる、すなわち「autoWarm」されるかもしれません。`autowarmCount`は、新しいサーチャーにコピーされるキャッシュ・アイテムの数です。おそらく、autowarmCountの設定は、オートウォームにかかる時間に基づいて設定したいでしょう。autoWarmにかかる時間とキャッシュをどの程度温めるかのトレードオフを考慮する必要があります。autowarmパラメータはsolrconfig.xmlのキャッシュの項目に設定します。

### キャッシュヒット率

Solrの管理画面からキャッシュ統計を監視します！Solrのキャッシュサイズを大きくすることは、パフォーマンスを改善する最善の方法です。特に、特定のキャッシュ・タイプで多くのキャッシュ削除が発生する場合は、より重要です。特に`filterCache`に注意してください。filterCacheは、Solrの内部でファセットにも使用されます。

### sortフィールドの、明示的なwarming

フィールドベースのソートを多用する場合、solrconfigの 「newSearcher」と 「firstSearcher」イベントリスナーに、これらのフィールドでソートする明示的にウォーミングクエリを追加するのが有利です。

## Optimizeの考慮事項

インデックスを最適化したい場合がある。
インデックスを一度構築し、その後一度も変更しない場合である。

急速に変化するインデックスを使用している場合、最適化するよりも、単純に低いマージファクターを使用することをお勧めします。最適化は非常に高価であり、インデックスが常に変化している場合、わずかな性能向上は長くは続きません。静的でないインデックスでは、トレードオフの価値はあまりありません。

マスター・スレーブのセットアップでは、マスターを最適化し、スレーブが単一セグメントのインデックスからサービスを提供するようにしたい場合もあります。しかし、この場合、インデックスの複製にかかる時間が大幅に増加する可能性があるため、多くの場合、この方法も望ましくありません。

## 更新とコミット頻度のトレードオフ

スレーブが新しいコレクションを受け取る頻度が高すぎると、パフォーマンスが低下します。このような劣化を避けるためには、スレーブがどのようにコレクションの更新を受け取るかを理解し、新しいコレクションがスレーブに頻繁にインストールされないように、関連するパラメータ（コミット数/頻度、スナッパー、自動ウォーミング/自動カウント）を最適に調整する方法を知る必要があります。

1. コレクションのスナップショットは、クライアントがコミットを実行するたびに取得され、マスターでpostCommitフックまたはpostOptimizeフックが使用されているかどうかに応じて最適化が実行されます
1. cronベースで動作するスレーブ上のスナップラーが、マスターに新しいスナップショットがないかチェックします。スナップラーが新しいコレクションのバージョンを見つけたら、スレーブはそれをプルしてスナップインストールする
1. 新しいインデックス・サーチャーが開かれるたびに、Solrがクエリをそのバージョンのコレクションに渡す前に、キャッシュの自動ウォーミングが行われます。クエリがキャッシュをウォームアップすることは、個々のクエリのレイテンシにとって非常に重要です

関連する3つのパラメータ

- スナップショットの数/頻度は、完全にインデックス作成クライアント次第である。したがって、コレクションのバージョン数はクライアントの活動によって決定される
- スナップラーはcronで実行される。1秒ごとに実行することも、1日に1回実行することも、その中間を実行することもできる。それらが実行されるとき、彼らは持っていない最新のコレクションだけを取得します
- キャッシュの自動ウォーミングは、solrconfig.xmlでキャッシュごとに設定されます

最新の変更を 「ライブオンライン」で表示するために、頻繁に新しいコレクションを作成したいのであれば、頻繁にコミット/スナップショットを行うことと、頻繁にスナップルを行うことの両方が必要です。クエリ時間を短縮するためのキャッシュへの依存度や、キャッシュの自動ウォームアップにかかる時間にもよりますが、インデックス変更を最も頻繁に配布し、良好なパフォーマンスを維持できるのは、おそらく1分から5分の範囲です。

キャッシュの自動ウォーミングはパフォーマンスにとって重要かもしれない。一方では、新しいキャッシュ・バージョンは、システムがコレクションの新しいバージョンに切り替えた後、後続のクエリがキャッシュから提供されるように、十分なエントリを入力する必要があります。一方では、新しいコレクションの自動ウォームアップ（入力）には、特に1つのスレッドと1つのCPUしか使用しないため、多くの時間がかかる可能性があります。設定がsnapinstallerをあまりにも頻繁に起動する場合、Solrスレーブは1つの（古い）コレクションにクエリを渡すという好ましくない状態になり、新しいコレクションをウォームアップしている間に、2番目の「新しい」コレクションがスナップされ、ウォームアップを開始する可能性があります！

このような状況を解決しようとすれば、2つ目のコレクションを使用するために最初の 「新しい 」コレクションを無効にしなければならず、次に 「3つ目 」の新しいコレクションをスナップしてウォームされれば、「2つ目 」の新しいコレクションを無効にしなければならない。完全にウォームアップされたコレクションは、中止される前に完全に終了することはない。これは、新しいコレクションが急速にインストールされないように、適切に調整された設定で防ぐことができます。

## クエリ結果の圧縮

クライアントに送り返す前にSolr XMLレスポンスを圧縮することは、状況によっては価値があります。レスポンスが非常に大きく、NICのI/O制限に抵触し、ギガビットイーサネットがオプションでない場合、圧縮を使用することが解決策になります。

Solrは通常CPUに負荷のかかるサービスなので、圧縮はクエリのパフォーマンスを低下させます。圧縮は、ファイルを元のサイズの1/6に、ネットワークパケットを元のサイズの1/3に縮小しようとします。(ビットとパケットの間に大きな隔たりがあることに意味があるのかないのか、今は時間をかけて考えているわけではありませんが、素晴らしい削減であることは言うまでもありません)。Solrサーバーでは、クエリーパフォーマンスに15%程度の影響があります。

ページ圧縮の設定方法の詳細については、使用しているアプリケーションサーバー（Tomcat、Resin、Jettyなど）のドキュメントを参照してください。

## インデックスのパフォーマンス

一般的に、更新リクエストごとに多くのドキュメントを追加する方が、更新リクエストごとに1つのドキュメントを追加するよりも高速です。

Javaクライアントからの一括更新には、（3.Xでは）
複数のスレッドを使用して複数の接続で更新をストリームするStreamingUpdateSolrServer.javaの使用を検討してください。
注意: 4.Xでは、StreamingSolrServerは廃止され、ConcurrentUpdateSolrServerが採用されています。

自動コミットの頻度を減らすか、完全に無効にすると、インデックス作成が速くなるかもしれません。これはメモリ使用量の増加につながり、過剰なスワッピングやガベージコレクションなど、パフォーマンス上の問題を引き起こす可能性があることに注意してください。

## メモリ使用率の考慮事項

### OutOfMemoryエラー

Solrインスタンスに十分なメモリが割り当てられていない場合、Java仮想マシンはJava OutOfMemoryErrorを投げることがあります。これが発生してもデータが破損する危険はなく、Solrはgracefulに回復しようとします。しかし、エラーがスローされたときに実行中の追加/削除/コミットは成功しない可能性があります。他の悪影響が発生する可能性があります。例えば、SimpleFSLockロック機構が使用されている場合（Solr 1.2の場合）、タイミング悪くOutOfMemoryErrorが発生すると、Solrはインデックスのロックを失う可能性があります。この場合、インデックスを変更しようとすると

```
SEVERE: Exception during commit/optimize:java.io.IOException: Lock obtain timed out: SimpleFSLock@/tmp/lucene-5d12dd782520964674beb001c4877b36-write.lock
```

といったエラーが発生します。

OOM発生時にヒープを見たい場合は、
```
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/the/dump
```

を設定する

### Java VMに確保されたメモリ

このエラーに対処する最も簡単な方法は、Java仮想マシンがまだ物理メモリをすべて使用していないと仮定して、Solrを実行しているJava仮想マシンに割り当てられるメモリの量を増やすことです。Solrディストリビューションのexample/でこれを行うには、標準的なSun仮想マシンを実行している場合、-Xmsと-Xmxコマンドラインパラメータを使用できます：

```
java -Xms512M -Xmx1024M -jar start.jar
```

さまざまなJVMメモリプールのサイズと使用量を確認するには、jconsole、visualvm、またはSPM for Solrパフォーマンスモニタリングのようなツールを使用して、長期的なモニタリングを行う。

### メモリ使用率に関わる要素

また、Solrのメモリ使用量を実際に減らしてみるのもいいでしょう。

要因の1つは、入力ドキュメントのサイズです。

ドキュメントの「追加」コマンドを処理する場合、標準のXML更新ハンドラには2つの制限があります：

- ドキュメントの「追加」コマンドを処理する場合、標準のXML更新ハンドラには2つの制限があります。(厳密には、min(<実際のフィールド値の長さ>, maxFieldLength)の合計です。そのため、maxFieldLengthを調整することは何らかの助けになるかもしれません)。
    - (私は、フィールドは関連するドキュメントオブジェクトに追加される前にmaxFieldLengthに切り捨てられると仮定しています。もしそうでなければ、maxFieldLengthはここでは役に立ちません。--ChrisHarris)
- 入力XMLの個々の<field>...</field>タグは、maxFieldLengthに関係なくメモリに収まらなければなりません。

複数の異なる 「add 」コマンドを同時に（異なるスレッドで）実行できることに注意してください。スレッド数が多いほど、メモリ使用量は多くなる。

インデックスを作成する場合、コミットが実行されるまでは、 インデックス化されたドキュメントの数に応じてメモリ使用量が増加する。コミット（ソフトコミットを含む）は、ほとんどすべてのヒープメモリを解放する。インデックス作成中の非常に大きなヒープとそれに伴うガベージ・コレクションの一時停止を避けるには、定期的に手動（ソフト）コミットを実行するか、solrconfig.xmlでautoCommit（またはautoSoftCommit）を有効にすることを検討してください。