⚠️ Эта страница автоматически переведена, и перевод может быть несовершенным.
blog-post

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

Обо мне

Mike

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

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

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

Репликация

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

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

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

Первичная настройка

Сейчас наш контейнер из предыдущей статьи работает нормально, но если он остановится и будет удален, данные будут потеряны навсегда. В руководстве по Docker для Manticore рекомендуется монтировать каталог с данными вне контейнера. Кроме того, в прошлый раз мы не пробросили бинарный порт 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

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

Новый вид контейнера

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

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

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

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

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

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

create cluster pet_shop;
alter cluster pet_shop add products;

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

show status like '%cluster%'

Результат show status

Сейчас нас интересуют следующие строки: 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, для volume задаем 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';

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

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

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

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

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

При работе с данными таблицы в кластере есть некоторые отличия. Команда вставки теперь требует корректировки — помимо имени таблицы нужно указать и имя соответствующего кластера: 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)

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

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

А что если нам нужно изменить конфигурацию таблицы или удалить ее, например, чтобы обновить файл wordforms? В предыдущей статье нам пришлось удалять и заново создавать таблицу, оставляя пользователей без ответов сервера на некоторое время. В том примере время, необходимое для обновления настроек, было совсем небольшим, потому что таблица была маленькой. Но для больших наборов данных, таблиц с миллионами и миллиардами записей и так далее обновление и индексирование могут занять много времени, часто измеряемого часами. Чтобы обеспечить непрерывную работу приложений на базе 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:

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

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

Теперь изменим морфологию со стеммера на лемматайзер, переиндексируем записи и снова все подключим. В предыдущей статье мы заменяли файл wordforms и стеммер грубым способом. Здесь мы воспользуемся более цивилизованными инструментами. Все операции по замене файла wordforms или изменению морфологии, используемой в таблице, можно выполнить одной командой: 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