Давеча у меня возникла необходимость пересмотреть работу полнотекстового поискового движка Sphinx, поскольку, некоторые нередкие запросы занимали секунды, а иные даже больше десяти. После поиска уязвимых мест и путей оптимизации нашел нехитрый способ повышения производительности — распараллеливание нагрузки на несколько потоков, в результате я получил неплохое сокращение времени запросов.
Одна из неприятных особенностей Sphinx’а — очень скудная информация на русском языке. Удивишись тем, что тема распределения нагрузки не была затронута, решил поделиться данным решением на Хабре.
Цель: повысить производительность Sphinx путём разделения нагрузки на несколько потоков.
Решение: разделить индексы и указать в конфигурации количество потоков.
Потоки выполнения
Начнем с более простого — указания количества потоков выполнения. Предположим, что на нашем сервере четырехядерный процессор, поэтому оптимальнее всего будет использовать четыре потока. Для этого используем директиву dist_threads в разделе searchd конфигурационного файла.
searchd { ... dist_threads = 4 ... }
Директива обозначает максимальное количество потоков для обработки запроса. Значение по умолчанию — 0, что подразумевает неиспользование распаралелливания.
Разделение индексов
Далее, разделим индексы, чтобы каждый поток обрабатывал свой интервал записей. Другими словами: допустим, в нашей таблице 1 000 000 записей и четыре потока. Необходимо, чтобы каждый поток обработал 1 000 000 / 4 = 250 000 записей, чтобы в дальнейшем Sphinx получил результаты работы этих потоков и выдал наиболее релевантный результат. Логично, что четыре потока обрабатывающие по 250 000 записей быстрее справятся с работой, чем один поток, обрабатывающий 1 000 000 записей почти в четыре раза.
Предположим, что у нас есть некоторый source и index:
source books { type = mysql sql_query = SELECT id, name FROM tb_books } index books { source = books min_infix_len = 3 }
Для примера оставим директиву min_infix_len.
Чтобы разделить индекс на четыре части, создадим четыре source с ограниченными интервалами записей и назначим им по index‘у:
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-шников записей по таблице.
Хорошей практикой будет указать прародителей index‘ов и sourc‘ов, чтобы наследоваться от них и вынести в них некоторые повторяющиеся директивы. В данном случае, я вынес в них директивы type и min_infix_len.
Чтобы иметь некоторый индекс, к которому можно было обратиться за результатами, мы создали индекс ind_books с типом distributed в директивах local которого указали имена индексов, результаты которых необходимо получить.
Delta
Если вы используете delta индекс то самым простым решением будет мержить его с одним из полученных индексов.
Однако, в этом случае, необходимо иметь ввиду, что если delta окажется слишком большой, то выбранный индекс, с которым мы мержим её, окажется заметно больше остальных, что может негативно сказаться на производительности. Чтобы предотвратить это, оптимальнее всего мержить её со всеми индексами поочередно.
В конечном итоге, использование этого метода позволило мне сократить время запросов от 2 до 10 раз.
ссылка на оригинал статьи http://habrahabr.ru/post/263849/
Добавить комментарий