Если большинство участников вашего набора реплик становятся UNREACHABLE
, то в этом наборе нет большинства и он больше не будет иметь кворум и не сможет принимать решения о любых изменениях в наборе реплик. Также если участник группы, ставший UNREACHABLE
,вернется в ONLINE
, он не сможет снова присоединиться к группе до тех пор, пока она заблокирована.
Разберем ситуацию, когда вы потеряли 2 реплики на трехнодном MySQL InnoDB Cluster 8.0.
1. Потеря двух R/O реплик. Будет потерян кворум. Если вам повезет, то PRIMARY
будет продолжать работать в режимеR/W
. Если не повезет, то PRIMARY
перейдет в режим R/O
.
2. Потеря 2 инстансов, один из котрых или оба (Multi-Primary Mode
) были R/W
. Будет потерян кворум и оставшийся инстанс будет в режиме R/O
.
Ниже приведен пример кластера, в котором выключили 2 R/O
реплики. PRIMARY
перешел из режима R/W
в R/O
.
MySQL localhost:33060+ ssl JS > cluster=dba.getCluster()
WARNING: Cluster has no quorum and cannot process write transactions: Group has no quorum
<Cluster:UAT>
MySQL localhost:33060+ ssl JS > c.status()
{
"clusterName": "UAT_LOAN",
"defaultReplicaSet": {
"name": "default",
"primary": "db8-lt.com:3306",
"ssl": "REQUIRED",
"status": "NO_QUORUM",
"statusText": "Cluster has no quorum as visible from 'db8-lt.com:3306' and cannot process write transactions. 2 members are not active.",
"topology": {
"db6-lt.com:3306": {
"address": "db6-lt.com:3306",
"memberRole": "SECONDARY",
"memberState": "(MISSING)",
"mode": "n/a",
"readReplicas": {},
"role": "HA",
"shellConnectError": "MySQL Error 2003 (HY000): Can't connect to MySQL server on 'db6-lt.com:3306' (111)",
"status": "UNREACHABLE",
"version": "8.0.26"
},
"db7-lt.com:3306": {
"address": "db7-lt.com:3306",
"memberRole": "SECONDARY",
"memberState": "(MISSING)",
"mode": "n/a",
"readReplicas": {},
"role": "HA",
"shellConnectError": "MySQL Error 2003 (HY000): Can't connect to MySQL server on 'db7-lt.com:3306' (111)",
"status": "UNREACHABLE",
"version": "8.0.26"
},
"db8-lt.com:3306": {
"address": "db8-lt.com:3306",
"memberRole": "PRIMARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.26"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "db8-lt.com:3306"
}
ПРЕДУПРЕЖДЕНИЕ ! ! !
Важно понимать, что в примере выше db8-lt.com
был PRIMARY
(остается им, но только в режиме R/O
) и последняя транзакция зафиксирована в нем. Поэтому мы можем вернуть ему возможность полноценной работы не боясь потери транзакциий. Если у вас PRIMARY
стал недоступен и осталась ONLINE
только R/O
реплика, то хорошо подуймате, прежде чем ее активировать. Оцените все риски для бизнеса, т.к. вы очевидно потеряте какое-то количество транзакции.
Чтобы восстановииться после такого сценария, мы должны сначала разблокировать группу (репликации), перенастроив ее так, чтобы учитывались только текущие ONLINE
участники и игнорировались все остальные. Для этого используйте командуcluster.forceQuorumUsingPartitionOf()
, передав URI одного из ONLINE
членов вашего набора реплик. Все участники, видимые ONLINE
со стороны этого участника, будут добавлены в переопределенную группу.
ПРЕДУПРЕЖДЕНИЕ ! ! !
Обратите внимание, что это опасная команда. Вы можете случайно создать split-brain, что приведет к несогласованности базы данных. Напимер, если члены группы находятся в разных сетях и связь между ними нарушена. В этом случае все члены группы могут быть ONLINE
, но члены одной группы будут восприниматься другой как UNREACHABLE
, и наоборот. Из-за требования большинства, только одна группа сможет получать обновления, сохраняя согласованность базы данных. При использовании cluster.forceQuorumUsingPartitionOf()
, вы можете создать две отдельные группы, которые будут получать обновления по отдельности, что приведет к тому, что ваша база данных будет обрабатывать транзакции независимо друг от друга и окажется в несогласованном состоянии.
Группа из 5 участников, все ONLINE
Группа из 5 участников, разделенная на две
Перед использованием команды cluster.forceQuorumUsingPartitionOf()
убедитесь, что все члены группы, которые являются UNREACHABLE
, действительно OFFLINE
.
Итак, выполняя командуcluster.forceQuorumUsingPartitionOf()
мы должны перевести PRIMARY
в режим R/W
. В большинстве случаев это сработает как надо. После того, как PRIMARY
стал R/W
, вы восстанавлиаете реплики. Кластер обнаружит реплики, начнет на них накатывать изменения, но вам нужно еще сделать cluster.rescan()
, вы увидите данное напоминаие, запросив статус кластера:
MySQL localhost:33060+ ssl JS > cluster.status()
{
"clusterName": "UAT",
"defaultReplicaSet": {
"name": "default",
"primary": "db8-lt.com:3306",
"ssl": "REQUIRED",
"status": "OK_NO_TOLERANCE",
"statusText": "Cluster is NOT tolerant to any failures.",
"topology": {
"db6-lt.com:3306": {
"address": "db6-lt.com:3306",
"instanceErrors": [
"NOTE: instance server_id is not registered in the metadata. Use cluster.rescan() to update the metadata."
],
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"recovery": {
"state": "ON"
},
"recoveryStatusText": "Distributed recovery in progress",
"role": "HA",
"status": "RECOVERING",
"version": "8.0.26"
},
"db8-lt.com:3306": {
"address": "db8-lt.com:3306",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.26"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "db8-lt.com:3306"
}
Я же получил ошибку «Variable ‘group_replication_force_members’ can’t be set to the value of ‘db8-lt.com:33061’ (MYSQLSH 1231)»
MySQL localhost:33060+ ssl JS > cluster.forceQuorumUsingPartitionOf("gpadmin@db8-lt.com:3306")
Restoring cluster 'UAT' from loss of quorum, by using the partition dbposed of [db8-lt.com:3306]
Restoring the InnoDB cluster ...
Cluster.forceQuorumUsingPartitionOf: Variable 'group_replication_force_members' can't be set to the value of 'db8-lt.com:33061' (MYSQLSH 1231)
Чтобы решить проблему, нужно:
1.Перезапустить инстант mysql:
В режиме sql: restart;
В консоли операционной системы: sudo service mysqld restart
2. Подключиться к инстансу и выполнить команду dba.rebootClusterFromdbpleteOutage()
MySQL localhost:33060+ ssl JS > dba.rebootClusterFromdbpleteOutage()
Restoring the default cluster from dbplete outage...
Could not open a connection to 'db6-lt.com:3306': 'MySQL Error 2003: Could not open connection to 'db6-lt.com:3306': Can't connect to MySQL server on 'db6-lt.com:3306' (111)'
Would you like to remove it from the cluster's metadata? [y/N]: y
Could not open a connection to 'db7-lt.com:3306': 'MySQL Error 2003: Could not open connection to 'db7-lt.com:3306': Can't connect to MySQL server on 'db7-lt.com:3306' (111)'
Would you like to remove it from the cluster's metadata? [y/N]: y
NOTE: The instance 'localhost:3306' is running auto-rejoin process, which will be cancelled.
NOTE: Cancelling active GR auto-initialization at db8-lt.com:3306
db8-lt.com:3306 was restored.
The cluster was successfully rebooted.
<Cluster:UAT>
MySQL localhost:33060+ ssl JS > cluster = dba.getCluster()
<Cluster:UAT>
MySQL localhost:33060+ ssl JS > c.status()
{
"clusterName": "UAT",
"defaultReplicaSet": {
"name": "default",
"primary": "db8-lt.com:3306",
"ssl": "REQUIRED",
"status": "OK_NO_TOLERANCE",
"statusText": "Cluster is NOT tolerant to any failures.",
"topology": {
"db8-lt.com:3306": {
"address": "db8-lt.com:3306",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.26"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "db8-lt.com:3306"
}
3. После этого восстанавливаем реплики и делаем cluster.rescan()