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

Статья нацелена на тех кто уже знает что такое 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 записи, то есть по одной записи на каждой ноде.

© Habrahabr.ru