blog-post

Репликация: создание кластера, подключение, обновление настроек таблиц

Обо мне

Mike

Привет, я Майк.

Я недавно начал работать в Manticore в качестве Developer Advocate. Я человек, который не совсем далек от ИТ, но я догоняю современные технологии. В этом блоге я буду делиться своим опытом и тем, что я узнаю о Manticore. Я планирую документировать свое путешествие в формате дневника, объясняя, что такое Manticore и как его использовать. Давайте узнаем, как все работает вместе, выявим проблемы и взаимодействуем с разработчиками в реальном времени.

Это один из моих первых блогов. Если вам интересно учиться о Manticore вместе со мной, я буду держать вас в курсе в:

Репликация

Какова цель репликации в общем?

В предыдущей статье мы обновили настройки полнотекстового поиска, заменив файл форм слов. В процессе этого наша таблица была недоступна. В контексте нашего примера магазина время простоя было кратким — всего несколько секунд. Для небольших проектов такая краткая остановка может быть незначительной ценой за повышенное удобство. Однако, по мере расширения нашего магазина с большим количеством продуктов и клиентов, изменения в настройках сервера могут теперь привести к простоям системы, продолжающимся несколько часов. Чем больше база данных, тем дольше процесс повторной индексации. Хотя повторная индексация с Manticore занимает всего пару часов — а не дни или недели — мы предпочитаем избегать даже этой короткой задержки. Кроме того, что произойдет, если что-то случится с нашим единственным сервером? Или если количество клиентов станет слишком большим для одного сервера? Все преимущества высокоскоростного поискового движка будут потеряны. Следовательно, мы теперь рассматриваем возможность создания нескольких копий базы данных, которые работают одновременно и параллельно. Эта настройка обеспечит, что когда данные записываются на один сервер, они автоматически реплицируются на другие подключенные серверы или узлы.

В Manticore репликация между узлами реализована через библиотеку Galera . Galera использует технологию синхронной многомастеровской репликации, которая обеспечивает высокую доступность и отказоустойчивость для кластеров баз данных. Когда новая запись добавляется на один из серверов (узел), изменение мгновенно передается всем подключенным узлам. Этот процесс включает три фазы: запись в локальный журнал транзакций на исходном узле, репликация изменений на другие узлы и подтверждение получения данных всеми узлами перед фактическим применением транзакции. Транзакция применяется только после получения подтверждения от всех узлов кластера, что обеспечивает согласованность данных на всех узлах. Для пользователя эти процессы остаются невидимыми, и доступ к новым данным с любого узла происходит мгновенно после успешного завершения транзакции на этом узле.

Начальная настройка

На данный момент наш контейнер из предыдущей статьи работает нормально, но если он остановится и будет удален, данные будут потеряны навсегда. Руководство по Manticore Docker рекомендует сопоставить каталог данных снаружи контейнера. Кроме того, конфигурация, которую мы сделали в прошлый раз, не включала пересылку бинарного порта 9312, необходимого для репликации. Давайте исправим это, создав снимок папки из работающего контейнера и запустив новый с правильными настройками порта и хранения.

Сначала нам нужно обеспечить целостность данных. Мы заходим в контейнер, входим в Manticore и "замораживаем" таблицу, чтобы все данные, которые могут находиться в памяти, были надежно перемещены на диск, и ничего не изменялось на диске во время копирования.

FREEZE products;

Далее, сделаем копию каталога данных из контейнера:

docker cp Manticore:/var/lib/manticore .

Команда состоит из трех частей:

  • cp - копировать,
  • Manticore:/var/lib/manticore - имя контейнера и путь к папке внутри него,
  • . - локальный путь, куда копировать, в данном случае, текущий каталог.

Чтобы текущий контейнер продолжал работать как раньше, мы "размораживаем" таблицу:

UNFREEZE products;

Теперь давайте создадим новый контейнер с нужными нам настройками:

docker run —name manticore_new -v $(pwd)/manticore:/var/lib/manticore -p 10306:9306 -p 10312:9312 -d manticoresearch/manticore
docker exec -it manticore_new mysql

В результате у нас есть клон нашего контейнера с перенаправленными портами и местоположением файла базы данных на сервере вне контейнера. Давайте проверим, все ли на месте в нашем новом контейнере:

New container view

Отлично, все данные были перенесены, включая конфигурацию и файл форм слов, и теперь мы создадим кластер на основе этого контейнера.

Кстати, немного о файле форм слов: в папке, которую мы скопировали, есть копия этого файла. Я рекомендую скопировать его, потому что в будущем, как показала практика, вам может понадобиться его редактировать, и использование файла, расположенного в папке с таблицей, — плохая идея, что в конечном итоге может привести к некоторым проблемам. Я сделал копию вне папки базы данных: cp manticore/products/wf_pet_products.txt wf_pet_products.txt. И немного хороших новостей, я поговорил с коллегами — скоро вам не нужно будет вручную перемещать файл форм слов при использовании mysqldump, все будет автоматически сохранено в дампе. Вот задача на GitHub.

Создание нашего первого кластера

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

  • Чтобы добавить кластер, используйте команду CREATE CLUSTER.
  • Чтобы добавить таблицу в кластер, используйте команду ALTER CLUSTER ADD. Важно отметить, что кластеризация, репликация и другие функции Manticore доступны только для реальных таблиц !

Итак, давайте создадим наш первый кластер и сразу добавим к нему нашу таблицу:

create cluster pet_shop;
alter cluster pet_shop add products;

Теперь давайте проверим, что у нас есть. Для этого используйте команду show status, но она выдаст много информации, и чтобы не потеряться в ней, вы можете использовать фильтр с оператором like:

show status like '%cluster%'

Результат показа статуса

На данный момент нас интересуют следующие строки: cluster_name, cluster_pet_shop_status, cluster_pet_shop_indexes. Они показывают имя кластера, статус (если указано Primary, значит, все в порядке) и таблицы, которые в данный момент находятся в кластере.
Также стоит отметить строку cluster_pet_shop_incoming_addresses. В моей настройке она выглядит так: 172.17.0.5:9312,172.17.0.5:9315:replication. Нам понадобится адрес 172.17.0.5:9312. У нас порт 9312 сопоставлен с портом 10312 вне Docker, но в примере мы запустим новый узел в той же сети Docker 172.17.0.0, что упростит использование портов.

Технически, мы могли бы использовать оригинальный контейнер из статьи о Wordforms , просто добавив к нему кластер и подключив таблицу. Затем мы могли бы создать новый контейнер с внешним хранилищем, и репликация скопировала бы все в локальный образ. Но тогда я бы не показал, как решить проблему другим способом, сохранив дамп через копирование папки из контейнера... =)
Мы сами делаем свою постель, а затем в ней лежим.

Первый узел уже настроен, больше никаких дополнительных действий не требуется. Просто? Это легко!

Добавление другого узла в кластер

Сначала нам нужно запустить другой контейнер с Manticore. Мы ничего не будем переносить в него, просто подключим его к существующему кластеру. Локальное хранилище должно быть другим (папки, которые вы подключаете, должны быть разными, если вы делаете это на одном сервере). Важно напомнить о портах, так как мы уже использовали порты 9306, 10306 и 10312. Итак, давайте назначим другие порты, например, 11306 и 11312.

Мы создаем другой контейнер с экземпляром Manticore, называя его Manticore_new_1. Мы указываем порты 11306 и 11312, для тома указываем manticore_new_1 (локальная папка должна уже существовать).

Новый узел

Или все то же самое в одной команде:

docker run --name manticore_new_1 -v $(pwd)/manticore_new_1:/var/lib/manticore -p 11306:9306 -p 11312:9312 -d manticoresearch/manticore

Войдите через клиент MySQL. Вот нюанс: если вы используете локальный клиент MySQL для подключения, а не тот, что внутри контейнера, то используйте внешний порт, который вы указали при создании узла — 11306. Если вы используете интерфейс Docker и входите через терминал контейнера (docker exec), то используйте порт по умолчанию для Manticore — 9306. В любом случае, подключитесь. Есть ли таблицы (show tables). Результат ожидаемо пуст, так как мы только что создали пустой контейнер с Manticore. Теперь подключим его к существующему кластеру — join cluster pet_shop at '172.17.0.5:9312';

Подключение к кластеру и проверка параметров

Для ясности я изменил цвет консоли для второго узла.

Как мы видим, таблица была добавлена, количество записей совпадает с оригинальным узлом, и конфигурация файла стеммера и форм слов правильная.
В принципе, на этом все. Кластер собран и работает, данные передаются между узлами.

Важное замечание. Если узел, который вы подключаете к кластеру, имеет таблицы с теми же именами, что и таблицы в кластере, таблицы на узле будут перезаписаны данными из кластера. Данные кластера имеют более высокий приоритет над локальными таблицами, поэтому, если вы подключаете существующий узел, который уже имеет некоторые данные, убедитесь, что имена существующих таблиц отличаются от тех, что в кластере. И, как всегда, в любой рискованной ситуации, сделайте резервную копию .

Управление данными в кластере

При работе с данными таблиц в кластере есть некоторые отличия. Команда вставки теперь требует некоторых корректировок — нам нужно указать, помимо имени таблицы, имя соответствующего кластера: insert into <cluster name>: <table name>(<fields>) values (<values>). Не забудьте обновить эту команду в вашем клиенте.

Давайте добавим еще одну запись, находясь в только что созданном узле:

insert into pet_shop:products (name, info, price, avl) values ('Aquarium ship', 'Decorative ship model for aquarium', 6, 1);

Результат добавления новой записи

Согласно результату, запись добавлена, но как насчет другого узла?
Результат для второго узла

Все на месте и здесь!
Давайте попробуем обновить данные:

mysql> update products set price = 8.0 where id = 3317338896206921730;
ERROR 1064 (42000): table products: table 'products' is a part of cluster 'pet_shop', use 'pet_shop:products'

Для обновления, изменения и особенно удаления записей нам теперь также нужно указывать имя кластера в имени таблицы:

update pet_shop:products set price = 8 where id = 3317338896206921730;
Query OK, 1 row affected (0.01 sec)

Таким образом, данные теперь передаются между узлами автоматически и без особых сложностей, за исключением небольшого изменения в командах записи.

Изменение настроек реплицированной таблицы

Что делать, если нам нужно изменить конфигурацию таблицы или удалить её, например, чтобы обновить файл форм слов? В предыдущей статье нам пришлось удалить и воссоздать таблицу, оставив пользователей без ответов от сервера на некоторое время. В том примере время, необходимое для обновления настроек, было очень коротким, потому что таблица была маленькой. Но с большими наборами данных, таблицами с миллионами и миллиардами записей и т.д., обновление и индексация могут занять много времени, часто измеряемого часами. Чтобы обеспечить бесперебойную работу приложений на базе Manticore, существуют распределенные таблицы , но мы обсудим это в другой статье.

На данный момент у нас есть реплицированная база данных на нескольких узлах с таблицей products. Мы можем изменить конфигурацию этой таблицы, используя префикс имени кластера, но не можем её удалить, даже с префиксом. Чтобы изменить настройки реплицированной таблицы, сначала отключите её от кластера: ALTER CLUSTER <cluster name> DROP <table name>. Это удалит таблицу только из кластера, но не из базы данных. После того как таблица будет отсоединена от кластера, обновление данных из приложения будет невозможно, потому что оно ссылается на кластер (например, insert into pet_shop:products ...), и таблицы больше нет в нём (приложение должно обрабатывать эту ситуацию). Теперь мы можем удалить или перенастроить таблицу.

Например, давайте обновим конфигурацию таблицы: переключимся с стеммера на лемматизатор. Вот шаги:

  • Отключите таблицу от кластера.
  • Измените морфологию в таблице с стеммера на лемматизатор.
  • Перезагрузите данные в таблицу.
  • Восстановите таблицу в кластере.
  • Проверьте на втором узле.

Отключение таблицы от кластера:

ALTER CLUSTER pet_shop DROP products;

Теперь таблица на всех узлах кластера отключена от него, и её схему и настройки можно изменять. Логика нашей работы подразумевает, что на одном узле мы выполняем некоторые технические работы, в то время как другой обрабатывает запросы select от пользователей. В качестве меры защиты добавление новых записей больше не будет возможным, так как приложение использует команды в формате <cluster>:<table>, и этой таблицы больше нет в кластере.

update pet_shop:products set price = 9 where id = 3317338896206921730;
ERROR 1064 (42000): table products: table 'products' is not in any cluster, use just 'products'

После того как мы отсоединили таблицу от кластера, давайте попробуем выполнить запрос select:

Результат для другого узла

Как мы видим, запрос обрабатывается, данные предоставляются, и конечный пользователь должен быть доволен.

Теперь давайте изменим морфологию с стеммера на лемматизатор, переиндексируем записи и снова подключим всё. В предыдущей статье мы заменили файл форм слов и стеммер, используя некоторые грубые методы. Здесь мы будем использовать более цивилизованные инструменты. Все операции по замене файла форм слов или изменению морфологии, используемой в таблице, можно выполнить одной командой: ALTER TABLE <table name> morphology='<morph type>'. Давайте заменим наш стеммер на лемматизатор:

ALTER TABLE products morphology='lemmatize_en_all';

После изменения любых параметров, связанных с предварительной обработкой текста в базе данных, необходимо переиндексировать все существующие записи, чтобы морфология и другие настройки токенизации применялись к старым документам:

mysqldump -P9306 -h0 --replace --skip-comments manticore products | mysql -P9306 -h0;

Здесь мы используем технику mysqldump, перенаправляя вывод дампа непосредственно в Manticore через MySQL. Опция --replace заставляет mysqldump генерировать команды REPLACE вместо INSERT, что позволяет нам "перезагрузить" всю таблицу сразу. Имейте в виду, что время выполнения этой команды для большой таблицы или на слабом сервере может быть долгим, но это нас не пугает, так как у нас есть резервный узел, который в настоящее время обрабатывает запросы пользователей, и команда mysqldump не блокирует таблицу.

После выполнения этой простой перенастройки таблицы с таблицей products мы получаем новую версию:

Новая таблица

Новые настройки и все данные применены, теперь давайте добавим эту таблицу обратно в кластер:

ALTER CLUSTER pet_shop ADD products;

Вот и всё, теперь таблица обновлена на всех серверах, и данные были доступны пользователям всё время со второго узла, пока мы настраивали и проверяли всё, чтобы убедиться, что это работает правильно.

Другой узел

Важно обратить внимание на восстановление всего кластера, если все узлы выходят из строя — при неправильной последовательности восстановления есть шанс потерять все его настройки. Подробные методы восстановления описаны в документации .


Кстати, вы можете легко поиграть с репликацией в нашем интерактивном курсе play.manticoresearch.com.

На этом всё на сегодня! Удачи впереди! Это был Майк, желающий вам удачи!

Установить Manticore Search

Установить Manticore Search