Sphinx - Distributed Search. Executing REPLACE for a distributed index

The article is aimed at those who already know what Sphinx and SphinxQL are.
Purpose: To ensure the continuity of site search using Sphinx at the time of technical work on one of the Sphinx nodes.

Sphinx is a great tool for organizing site searches. In the project in which I participate, the search for ads occurs using Sphinx. Ads are stored in the database in the EAV model and Sphinx searches for them, then ads are retrieved by the identifiers found by the sphinx. Thus, if Sphinx stops working, then this will affect the entire site.

For work, sphinx rt indexes are used to instantly make changes to the search results if any advertisement is edited or banned. While this worked on one node, everything was fine until there was a need to make changes to the structure of the indices themselves. To change the list of attributes in the search index, you had to edit the configuration, restart the sphinx and reindex ads. In order to do this without stopping the site, it was decided to build a cluster with one main node that actually acts as a balancer and two child nodes that contain an index and are mirror to each other.

Setting up the indexer and searchd sections is generally normal
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 has distributed indexes for organizing a search cluster.
On the main node, all indices have the following form.
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
}

By the way, there is a difference between how to describe child nodes, in the previous example they are described as mirrors, and in the following they are described as nodes storing two different parts of the same index. The difference is that in the first case, the select request is sent to one of the nodes, and in the second example, the select is sent to all nodes and the search result from each of the nodes is combined.
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 - отправляет запросы к не мёртвым нодам
}

On child nodes, indexes are described as the most common real time indexes in 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
}

There are no problems with the selection on the cluster.
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)

It already seemed to me that the task had been solved on this, but it wasn’t right. Sampling works, but what about REPLACE or INSERT queries?
As it turned out there was an ambush - REPLACE and INSERT by default only work on local indexes, and I use distributed.

But it doesn’t matter. Since the sphinx project is open source, I made my assembly which allows you to execute REPLACE queries on distributed indexes.
To build it, you need to download the sources and run the command
cmake . && make

Now starting this assembly with exactly the same settings as the previous request will be executed on all mirror nodes.
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)

I used two mirrors for verification, and we see that 2 records are affected, that is, one record on each node.

Also popular now: