スフィンクスが配布します。 検索を高速化

最近、全文検索エンジンSphinxの作業を確認する必要がありました。頻繁なクエリには数秒かかるものもあれば、10秒以上かかるものもあったからです。 脆弱性と最適化パスを検索した後、パフォーマンスを改善する簡単な方法を見つけました-複数のスレッドの負荷を並列化することで、クエリ時間を大幅に短縮できました。



Sphinxの不快な機能の1つは、ロシア語では非常に少ない情報です。 負荷分散のトピックが取り上げられていないことに驚いたので、このソリューションをHabréで共有することにしました。



目標 :負荷を複数のスレッドに分割することにより、Sphinxのパフォーマンスを改善します。



解決策 :インデックスを分離し、構成内のスレッドの数を指定します。



実行スレッド



簡単なものから始めましょう-実行スレッドの数を示します。 サーバーにクアッドコアプロセッサがあるため、4つのスレッドを使用することをお勧めします。 これを行うには、構成ファイルのsearchdセクションでdist_threadsディレクティブを使用します。



searchd { ... dist_threads = 4 ... }
      
      





このディレクティブは、リクエストを処理するスレッドの最大数を示します。 デフォルト値は0です。これは、並列化を使用しないことを意味します。



インデックス分離



次に、各スレッドがその記録間隔を処理するようにインデックスを分割します。 つまり、テーブルに1,000,000個のレコードと4つのストリームがあるとします。 Sphinxがこれらのスレッドの結果を受信し、最も関連性の高い結果を生成するために、各スレッドが1,000,000 / 4 = 250,000レコードを処理する必要があります。 250,000個のレコードを処理する4つのスレッドが、1,000,000個のレコードをほぼ4回処理する1つのスレッドよりも高速にジョブを実行するのは論理的です。



いくつかのソースとインデックスがあるとします:



 source books { type = mysql sql_query = SELECT id, name FROM tb_books } index books { source = books min_infix_len = 3 }
      
      





たとえば、 min_infix_lenディレクティブはそのままにします。

インデックスを4つの部分に分割するには、限られたレコード間隔で4つのソースを作成し、それらをインデックス 'yに割り当てます。



 source books_base { type = mysql } source books0: books_base { sql_query = SELECT id, name FROM tb_books WHERE id % 4 = 0 } source books1: books_base { sql_query = SELECT id, name FROM tb_books WHERE id % 4 = 1 } source books2: books_base { sql_query = SELECT id, name FROM tb_books WHERE id % 4 = 2 } source books3: books_base { sql_query = SELECT id, name FROM tb_books WHERE id % 4 = 3 } index ind_books_base { min_infix_len = 3 } index ind_books0: ind_books_base { source = books0 } index ind_books1: ind_books_base { source = books1 } index ind_books2: ind_books_base { source = books2 } index ind_books3: ind_books_base { source = books3 } index ind_books { type = distributed local = ind_books0 local = ind_books1 local = ind_books2 local = ind_books3 }
      
      





テーブルをほぼ等しい部分に分割する最も簡単な方法は、クエリでレコードIDの多重度を指定することですが、これが唯一の方法ではありません。 別の方法として、 sql_query_rangeディレクティブを使用することもできますが、私の場合、このメソッドはテーブル内のレコードのidキーの分布が不均一であるため機能しませんでした。



indexsourcの先祖を指定して、それらから継承し、いくつかの繰り返しディレクティブを作成することをお勧めします。 この場合、 typeおよびmin_infix_lenディレクティブを発行しました。



結果にアクセスできるインデックスを作成するために、結果を取得するインデックスの名前を示すローカルディレクティブの分散型でind_booksインデックスを作成しました。



デルタ



デルタインデックスを使用する場合、最も簡単な解決策は、結果のインデックスの1つとマージすることです。



ただし、この場合、 デルタが大きすぎると判明した場合、それを保持する選択されたインデックスが他のインデックスよりも著しく大きくなり、パフォーマンスに悪影響を与える可能性があることに留意する必要があります。 これを防ぐには、一度にすべてのインデックスとマージするのが最善です。



最終的に、この方法を使用すると、クエリ時間を2倍から10倍に短縮できました。



All Articles