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

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

Кстати, немного о файле wordforms: в папке, которую мы скопировали, есть копия этого файла. Рекомендую скопировать его, потому что в будущем, как показала практика, вам может понадобиться его редактировать, и использование файла, расположенного в папке с таблицей, — плохая идея, что в конечном итоге может привести к некоторым проблемам. Я сделал копию вне папки базы данных: cp manticore/products/wf_pet_products.txt wf_pet_products.txt. И несколько хороших новостей: я поговорил с коллегами — вскоре вам не придется вручную перемещать файл wordforms при использовании 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';

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

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

Как мы видим, таблица добавлена, количество записей совпадает с оригинальным узлом, а конфигурация стеммера и файла 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)

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

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

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