[Из песочницы] Собираем InnoDB cluster из mysql 5.7 на centos 7

habr.png

Всем привет!

Как-то раз появилась по работе задача — есть вроде как настроенный тестовый innoDB cluster на нескольких виртуалках с centos 7.5, надо его поизучать и добавить еще пару нод. Можно ломать и издеваться как угодно. Звучит заманчиво.
До этого у меня опыта работы с этим кластером не было, ну да гугл в помощь.
За несколькими исключениями, все ссылки что в нем, что в яндексе вели либо на dev.mysql.com, либо на эту статью на Хабре. Вроде как по ней и был настроен кластер из двух нод.

Чтож, статью я прочитал, несколько удивился сложности добавления нод и отсутствию многих подробностей, ну да ладно. Добавил с грехом пополам новую ноду (часть команд не пригодилась, часть вообще все ломала), после чего начал экспериментировать с перезапуском нод и т.д.

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

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

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

Итак, имеем три одинаковых виртуалки со свежеустановленным Centos 7.5 minimal 1804 и отключенными selinux и firewalld:

1.1.1.1
1.1.1.2
1.1.1.3

По работе я использовал mysql 5.7, так что ее и используем. Начнем с 1.1.1.1:

1. Установим репозиторий mysql-community:

rpm -i https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm


Выключим репозиторий для 8, включим для 5.7 и проверим — если все ок, то устанавливаем mysql:

yum install yum-utils
yum-config-manager --disable mysql80-community
yum-config-manager --enable mysql57-community
yum repolist
yum install mysql-community-server mysql-shell


2. Приводим /etc/my.cnf к такому виду:

[mysqld]

datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

bind-address=0.0.0.0
port=3301
# Replication part
server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
plugin-load = group_replication.so
# Group replication part
transaction_write_set_extraction=XXHASH64
loose-group_replication_start_on_boot = OFF
loose-group_replication_local_address = 1.1.1.1:33011
loose-group_replication_bootstrap_group = OFF
report_port = 3301
report_host = 1.1.1.1


Здесь 3301 это порт, на котором будет слушать mysql, а 33011 порт, на котором ноды общаются между собой.

3. Запустим mysql и выполним предварительную настройку:

systemctl start mysqld
grep 'password' /var/log/mysqld.log
mysql_secure_installation


4. Ну и создадим кластер, а так же отдельного пользователя для управления им. Если вы знаете заранее ip-адреса нод, то можно их сразу перечислить в ipWhitelist. Сделаем вид, что мы пока не знаем про 1.1.1.2. и 1.1.1.3:

mysqlsh
> \c 127.0.0.1:3301
> dba.configureLocalInstance("127.0.0.1:3301", {mycnfPath: "/etc/my.cnf", clusterAdmin: "cladmin", clusterAdminPassword: "SomePassword!123"})
> \c cladmin@1.1.1.1:3301
> dba.checkInstanceConfiguration()
> cl=dba.createCluster('TestCluster', {ipWhitelist: '1.1.1.1'})
> dba.configureLocalInstance()
> cl.status()


Готово! cl.status должен вывести что-то типа этого:

{
    "clusterName": "TestCluster",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "1.1.1.1:3301",
        "ssl": "REQUIRED",
        "status": "OK_NO_TOLERANCE",
        "statusText": "Cluster is NOT tolerant to any failures.",
        "topology": {
            "1.1.1.1:3301": {
                "address": "1.1.1.1:3301",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            }
        }
    },
    "groupInformationSourceMember": "mysql://cladmin@1.1.1.1:3301"
}


При изменении кластера надо будет выполнять на всех нодах локально команду dba.configureLocalInstance () для сохранения изменений:

WARNING: On instance '1.1.1.1:3301' membership change cannot be persisted since MySQL version 5.7.23 does not support the SET PERSIST command (MySQL version >= 8.0.11 required). Please use the .configureLocalInstance command locally to persist the changes.


Т.к. мы собираемся добавить еще парочку нод, то не закрываем связь с сервером 1.1.1.1, он нам еще пригодится.

Теперь попробуем добавить в кластер ноду 1.1.1.2. Для этого выполняем на ней все те же команды до 3 шага включительно, не забывая поменять server_id, loose-group_replication_local_address и report_host.

4. Выполняем на 1.1.1.2:

mysql -p
> set GLOBAL group_replication_allow_local_disjoint_gtids_join=ON;


Я пытался задавать эту переменную через mysqlsh, переключаясь в режим sql, но действия там никак не влияли на нее в mysql. Далее:

mysqlsh
> \c 127.0.0.1:3301
> dba.configureLocalInstance("127.0.0.1:3301", {mycnfPath: "/etc/my.cnf", clusterAdmin: "cladmin", clusterAdminPassword: "SomePassword!123"})
> \c cladmin@1.1.1.2:3301
> dba.checkInstanceConfiguration()

5. Возвращаемся к первой ноде 1.1.1.1. Если закрыли соединение, то можно быстро подключиться к кластеру так:

mysqlsh --uri cladmin@1.1.1.1:3301 --cluster
> \sql
> STOP GROUP_REPLICATION;
> SET GLOBAL group_replication_ip_whitelist="1.1.1.1,1.1.1.2";
> START GROUP_REPLICATION;
> \js
> cluster.addInstance('cladmin@1.1.1.2:3301', {ipWhitelist: '1.1.1.1,1.1.1.2'})
> cluster.status()


Почему-то при добавлении ноды без опции ipWhitelist он ей не передается автоматически, поэтому указываем вручную.
Если whitelist у вас изначально настроен на все ноды или подсеть, то команды в sql режиме можно пропустить.

Не забываем выполнить dba.configureLocalInstance () на всех нодах для сохранения конфигурации.

Получился кластер их двух нод:

{
    "clusterName": "TestCluster",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "1.1.1.1:3301",
        "ssl": "REQUIRED",
        "status": "OK_NO_TOLERANCE",
        "statusText": "Cluster is NOT tolerant to any failures.",
        "topology": {
            "1.1.1.1:3301": {
                "address": "1.1.1.1:3301",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "1.1.1.2:3301": {
                "address": "1.1.1.2:3301",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            }
        }
    },
    "groupInformationSourceMember": "mysql://cladmin@1.1.1.1:3301"
}


Чтож, кластер из двух нод есть, но в режиме «Cluster is NOT tolerant to any failures.»
Добавим третью, алгоритм в принципе не отличается от добавления второй.

Если вам опять требуется поменять whitelist, то выполнять команды надо на r/w ноде, т.к. на r/o нодах это ни к чему вроде не приводит. При этом r/o ноды отвалятся и их надо будет пересоединить, попутно сообщив новый whitelist.
В нашем случае:

> cluster.rejoinInstance('cladmin@1.1.1.2:3301', {ipWhitelist: '1.1.1.1,1.1.1.2,1.1.1.3'})


Ну и опять же не забываем выполнить dba.configureLocalInstance () на всех нодах для сохранения конфигурации.

Кластер из трех нод выглядит так:

{
    "clusterName": "TestCluster",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "1.1.1.1:3301",
        "ssl": "REQUIRED",
        "status": "OK",
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
        "topology": {
            "1.1.1.1:3301": {
                "address": "1.1.1.1:3301",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "1.1.1.2:3301": {
                "address": "1.1.1.2:3301",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "1.1.1.3:3301": {
                "address": "1.1.1.3:3301",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            }
        }
    },
    "groupInformationSourceMember": "mysql://cladmin@1.1.1.1:3301"
}


В случае, если кластер развалился до состояния одной ноды, его надо будет запускать с параметром loose-group_replication_bootstrap_group = ON в /etc/my.cnf
После запуска параметр надо будет выключить обратно, иначе эта нода всегда будет отделяться от кластера и поддерживать свой.

Установка mysql-router хорошо описана тут, так что дублировать смысла не вижу.

На этом все вроде все, надеюсь кому-то мой опыт пригодится.

Спасибо за внимание.

© Habrahabr.ru