Pull to refresh

Sphinx — Распределённый поиск. Выполнение REPLACE для distributed индекса

Reading time3 min
Views11K
Статья нацелена на тех кто уже знает что такое Sphinx и SphinxQL
Цель: Обеспечить непрерывность работы поиска по сайту с помощью Sphinx в момент проведения технических работ над одной из нод Sphinx кластера.

Sphinx отличный инструмент для организации поиска по сайту. В проекте в котором я участвую поиск объявлений происходит с помощью Sphinx. Объявления хранятся в бд в EAV модели а поиск по ним выполняет Sphinx затем объявления извлекаются по найденным сфинксом идентификаторам. Таким образом если Sphinx перестанет работать то это скажется на всём сайте.

Для работы используются rt индексы sphinx для моментального внесения изменений в поисковую выдачу если какое либо объявление будет отредактировано или забанено. Пока это работало на одной ноде всё было хорошо до тех пор пока не возникало необходимости внести изменения в саму структуру индексов. Для изменения списка атрибутов в поисковом индексе необходимо было править конфигурацию, перезапускать сфинкс и выполнять переиндексацию объявлений. Для того чтобы это производить без остановки работы сайта решено было построить кластер с одной главной нодой фактически выполняющей роль балансировщика и двумя дочерними нодами содержащими индекс и являющимися зеркальными между собой.

Настройка секций indexer и searchd в целом обычная
indexer
{

}

searchd
{
   listen = 127.0.0.1:3301         # Порт для Sphinx Api
   listen = 127.0.0.1:3309:mysql41 # Порт для SphinxQL

   log       =                  ./sphinx-log-searchd.log
   query_log =                  ./sphinx-log-query.log
   pid_file  =                  ./sphinx-log-searchd.pid
   binlog_path =                ./sphinx-binlog

   read_timeout = 5
   max_children = 30
   max_matches = 1000
   seamless_rotate = 1
   preopen_indexes = 0
   unlink_old = 1
   
   workers        = threads 
}


Для организации поискового кластера в Sphinx есть distributed индексы.
На главной ноде все индексы имеют следующий вид.
index distributed_section_1
{
 type  = distributed
 agent = 127.0.0.1:9301:rt_section_1|127.0.0.1:9302:rt_section_1
 ha_strategy = nodeads
}

К слову есть разница между тем как описывать дочерние ноды, в предыдущем примере они описаны как зеркала, а в следующем они описаны как ноды хранящие две разные части одного индекса. Разница в том что в первом случае запрос select отправляется на одну из нод, а во втором примере select отправляется на все ноды и результат поиска от каждой из нод объединяется.
index distributed_section_1
{
 type  = distributed
 agent = 127.0.0.1:9301:rt_section_1
 agent = 127.0.0.1:9302:rt_section_1
 ha_strategy = nodeads          # стратегия распределения запросов между нодами. nodeads - отправляет запросы к не мёртвым нодам
}

На дочерних нодах индексы описываются, как самые обычные real time индексы в Sphinx:
index rt_section_1
{
	 type               = rt 
	 mlock              = 1 

	 morphology		    = stem_en, stem_ru 
	 min_word_len		= 3 
	 min_infix_len		= 1 
	 index_exact_words 	= 1 
	 dict               = keywords 

	 path			    = ./notices_rt_section_1

	 rt_field 	= title
	 rt_field 	= text

	 rt_attr_uint 	= date
	 rt_attr_uint 	= active
	 rt_attr_multi 	= location
}

Всё с выборкой на кластере проблем нет.
mysql> select * from rt_section_1;
+---------+------------+--------+----------+
| id      | date       | active | location |
+---------+------------+--------+----------+
|  185191 | 1398749772 |      1 | 145430   |
|  185234 | 1398749771 |      1 | 145425   |
+---------+------------+--------+----------+
2 rows in set (0.03 sec)

Мне уже показалось что задача на этом решена, но не ту-то было. Выборка работает, а что на счёт REPLACE или INSERT запросов?
Как оказалось тут была засада — REPLACE и INSERT по умолчанию работают только на локальных индексах, а я использую распределенный.

Но не беда. Так как sphinx проект с открытым кодом я сделал свою сборку которая позволяет выполнять REPLACE запросы на distributed индексах.
Для её сборки надо скачать исходники и выполнить команду
cmake . && make

Теперь запустив эту сборку с точно теме же настройками что и ранее запрос выполнится на всех нодах-зеркалах.
mysql> REPLACE INTO rt_section_130054 (id, `location`, `title`, `text`, `active`, `date`) VALUES ( 2435558, ( 145411 ) , 'Тестовый заголовок', 'Тестовая запись', 1, '1399529047');
Query OK, 2 rows affected (0.04 sec)

Я для проверки использовал два зеркала, и мы видим что затронуто 2 записи, то есть по одной записи на каждой ноде.
Tags:
Hubs:
+5
Comments2

Articles

Change theme settings