暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

万里数据库GreatDB故障诊断:MySQL 组复制问题处理

原创 Dbb 2024-06-06
499


集群 MGR 故障监控规则

目前,集群在添加 sqlnode 节点和 datanode 节点过程中,会持久化如下 MGR 的系统变量,用户故障的处理:

  1. group_replication_start_on_boot: ON,重启后自动尝试加入 MGR 集群。
  2. group_replication_autorejoin_tries: 2016,在 MySQL 服务没有停止的情况下,出现故障时,会自动尝试加入集群,尝试次数为 2016 次,每次失败后,会间隔 5 分钟进行下一次尝试。总的尝试时间大概为 7 天。
  3. group_replication_unreachable_majority_timeout: 30,默认情况下,如果多数节点同时故障(或者网络分区),剩余的少数节点会一直保持 ONLINE 状态,影响系统使用。集群将该值设置为 30 s的时间,超过该时间后,该节点状态会变成 ERROR 状态。如果是因为网络故障,网络恢复后,故障的节点通过 group_replication_autorejoin_tries 配置,会再次加入集群。
  4. group_replication_member_expel_timeout: 5s,保持默认值为 5 秒。如果一个节点出现故障,5-10s后,其它正常节点会将节点自动踢出 MGR 集群。

通过上述规则,无论 sqlnode 节点和 datanode 节点,如果故障时,存在多数节点可用,则:

  1. 非 MySQL 服务宕机的情况下,故障节点能够自动尝试加入集群,尝试的时间最多为 7 天。由于每次尝试间隔时间为 5 分钟,当故障恢复时,可能节点不一定能马上恢复,最长可能需要5分钟以上的时间。
  2. MySQL 服务宕机的情况下,重启后,节点会自动尝试加入集群。此时不能存在其它故障,如果失败,则无法自动加入集群。

MGR 主节点切换

在单主模式下(datanode节点为单主),如果 MGR 中的主节点发生故障,5-10s后,MGR 集群会自动选出新主并切换。

注意:当前 MGR 的选主逻辑可能存在一些问题,比如 3 个节点的 MGR,主节点为 A,其它节点为 B,C。A 故障时,假设 B,C均接收到了最新数据,但 B 回放的 gtid 为 100,C 回放的 gtid 为 200,MGR 仍可以选主 B 为新主。此时 B需要将所有的 relaylog 回放完成才能提供服务,会造成集群一段时间不可用。

在多主模式下,不涉及选主问题。

SQLNODE 节点 MGR 监控规则

在 MGR 本身配置基础上,sqlnode 节点会主动监听 MGR 节点的状态变化,并及时更新 SQLNODE 节点集群变化。用户可以通过查询 information_schema.greatdb_sqlnodes 查询 sqlnode 节点的实时状态信息。

DATANODE 节点 MGR 监控规则

在 sqlnode 节点上,会定期(每隔 2s)查看后端 datanode 节点的 MGR 状态,并更新相应的节点状态。用户可以通过查询information_schema.greatdb_datanodes 查询 datanode 节点的状态信息。该状态信息会存在短暂的时延(几秒的时延范围)。

另外,如果一个 shard 中所有的 datanode 节点都因为故障退出了 MGR 集群,但所有的 datanode 节点的 MySQL 服务都已经启动并可以正常连接访问,此时 sqlnode 会尝试自动重建该 shard 的 MGR 集群。

插件安装问题

安装成功的错误日志问题

执行如下 SQL 语句,安装组复制插件。

 INSTALL PLUGIN group_replication SONAME 'group_replication.so';

插件安装成功时,在 MySQL 的错误日志中,可能会写入如下日志:

[ERROR] [MY-011685] [Repl] Plugin group_replication reported: 'The group name option is mandatory'
[ERROR] [MY-011660] [Repl] Plugin group_replication reported: 'Unable to start Group Replication on boot'

处理方案:

  1. 忽略该错误日志。
  2. 配置文件中,指定参数 loose-group_replication_start_on_boot= OFF

启动失败问题

参数配置问题

  1. 没有配置 group_replication_group_name 变量

    mysql> start group_replication;
    ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log.
    

    执行启动命令,并没有详细的错误信息,根据提示,查看错误日志,有如下信息,表示 group_replication_group_name 变量没有配置。

    [ERROR] [MY-011685] [Repl] Plugin group_replication reported: 'The group name option is mandatory'
    

    注意:在组复制集群中,同一个复制组的所有节点,都需要配置该参数,且所有节点的配置保持一致。该参数的格式同 server_uuid ,但不能和任何节点的 server_uuid 一样。

  2. 没有配置 group_replication_local_address 变量

    mysql> start group_replication;
    ERROR 3096 (HY000): The START GROUP_REPLICATION command failed as there was an error when initializing the group communication layer.
    

    执行启动命令,同样没有提示关键的错误信息。此时,同样查看错误日志,会发现如下错误信息,其中最关键的是第一行的错误,表示 group_replication_local_address参数没有正确配置。

    [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Invalid hostname or IP address () assigned to the parameter local_node!'
    [ERROR] [MY-011674] [Repl] Plugin group_replication reported: 'Unable to initialize the group communication engine'
    [ERROR] [MY-011637] [Repl] Plugin group_replication reported: 'Error on group communication engine initialization'
    [Note] [MY-011649] [Repl] Plugin group_replication reported: 'Requesting to leave the group despite of not being a member'
    [ERROR] [MY-011718] [Repl] Plugin group_replication reported: 'Error calling group communication interfaces while trying to leave the group'
    

    注意:在组复制集群中,每个节点需要单独配置 group_replication_local_address,该参数为 hostname/ip 和 port 的组合,其中 port 为组复制的端口号,而不是 mysql 服务进程的端口号。参数的格式为 [ipv6]:port ,或者 ipv4:port 或者 hostname:port。其中,hostname/ip需要能够被集群其它节点正常访问。

  3. 没有配置 group_replication_group_seeds 参数

     mysql> start group_replication;
     ERROR 3097 (HY000): The START GROUP_REPLICATION command failed as there was an error when joining the communication group.
    

    执行启动命令,提示无法加入复制组,但没有更具体的错误提示。此时,同样查看错误日志,有如下信息,其中关键的为第一行,perrs not configured,表示没有配置 group_replication_group_seeds 参数。

     [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Unable to join the group: peers not configured. '
     [ERROR] [MY-011639] [Repl] Plugin group_replication reported: 'Error on group communication engine start'
     [Note] [MY-011649] [Repl] Plugin group_replication reported: 'Requesting to leave the group despite of not being a member'
     [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] The member is leaving a group without being on one.'
    

    注意:该参数格式为多个 group_replication_local_address的组合,使用逗号分隔。一般配置时,需要将所有包含所有节点的 group_replication_local_address 值。

集群初始化及脑裂问题

当初始化组复制集群时,对于第一个节点,需要将参数 group_replication_bootstrap_group 设置为 ON,否则会报错。

mysql> start group_replication;
ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log.

mysql> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)

mysql> start group_replication;
Query OK, 0 rows affected (3.09 sec)

mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)

group_replication_bootstrap_group参数的作用是标记是不是初始化组复制集群,如果设置为 ON,则将以执行节点初始化一个全新的组复制集群。否则,如果设置为 OFF (默认值),该节点将尝试去加入到一个现有的组复制集群中。在上述示例中,因为无法连接到 33061,33062 的组复制端口,所以节点无法加入到一个现有组复制集群中(因为这样的集群不存在),所以启动失败。

[ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Error on opening a connection to 127.0.0.1:33061 on local port: 33060.'
[ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Error on opening a connection to 127.0.0.1:33062 on local port: 33060.'
[ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] Error connecting to all peers. Member join failed. Local port: 33060'
[ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] The member was unable to join the group. Local port: 33060'
[ERROR] [MY-011640] [Repl] Plugin group_replication reported: 'Timeout on wait for view after joining group'
[Note] [MY-011649] [Repl] Plugin group_replication reported: 'Requesting to leave the group despite of not being a member'
[ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] The member is leaving a group without being on one.'

注意:当初始化节点启动组复制成功后,因立即将参数 group_replication_bootstrap_group 设置为 OFF。非初始化节点禁止设置参数为ON,否则会导致集群脑裂问题。如下示例可以看出,在相同的配置下,13000,和13001两个mysql并没有出现在同一个组复制集群下。此时,可以认为是出现了脑裂的问题。因此,一定要注意 group_replication_bootstrap_group 参数的配置问题。

connect 13000:

mysql> set global group_replication_group_name='11223344-1122-1122-1122-112233445566';
Query OK, 0 rows affected (0.00 sec)

mysql> set global group_replication_local_address='127.0.0.1:33060';
Query OK, 0 rows affected (0.00 sec)

mysql> set global group_replication_group_seeds='127.0.0.1:33060,127.0.0.1:33061,127.0.0.1:33062';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)

mysql> start group_replication;
Query OK, 0 rows affected (3.09 sec)

mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)

connect 13001:

mysql> set global group_replication_group_name='11223344-1122-1122-1122-112233445566';
Query OK, 0 rows affected (0.00 sec)

mysql> set global group_replication_local_address='127.0.0.1:33061';
Query OK, 0 rows affected (0.00 sec)

mysql> set global group_replication_group_seeds='127.0.0.1:33060,127.0.0.1:33061,127.0.0.1:33062';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)

mysql> start group_replication;
Query OK, 0 rows affected (3.27 sec)

mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)

+-------------+-------------+--------------+-------------+
| MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE |
+-------------+-------------+--------------+-------------+
| 127.0.0.1   |       13001 | ONLINE       | PRIMARY     |
+-------------+-------------+--------------+-------------+
1 row in set (0.02 sec)

重新 connect 13000:

mysql> SELECT MEMBER_HOST,MEMBER_PORT,MEMBER_STATE,MEMBER_ROLE FROM performance_schema.replication_group_members;
+-------------+-------------+--------------+-------------+
| MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE |
+-------------+-------------+--------------+-------------+
| 127.0.0.1   |       13000 | ONLINE       | PRIMARY     |
+-------------+-------------+--------------+-------------+
1 row in set (0.00 sec)

当出现脑裂问题时,会导致数据的异常行为,避免脑裂问题的关键是需要保证 group_replication_bootstrap_group 参数在初始化集群后处于 OFF 状态。

RECOVING 状态问题

  1. 初始化节点也可能处于 RECOVING 状态,属于正常状态,其余节点需要等待初始节点处于 ONLINE 状态后,才能加入集群
  2. 启动组复制集群前,需要在所有节点上执行如下命令,初始化组复制通道。并保证所有的节点需要使用统一的用户名和密码。

    CHANGE MASTER TO MASTER_USER="my_user", MASTER_PASSWORD="my_password," FOR CHANNEL "group_replication_recovery"
    

    如果没有执行该语句,新加入的节点将长期处于 RECOVING 状态, 如下示例。

    mysql> start group_replication;   
    Query OK, 0 rows affected (4.21 sec)
    
    mysql> do sleep(30);
    Query OK, 0 rows affected (30.00 sec)
    
    mysql> SELECT MEMBER_HOST,MEMBER_PORT,MEMBER_STATE,MEMBER_ROLE FROM performance_schema.replication_group_members;
    +-------------+-------------+--------------+-------------+
    | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE |
    +-------------+-------------+--------------+-------------+
    | 127.0.0.1   |       13000 | ONLINE       | PRIMARY     |
    | 127.0.0.1   |       13001 | RECOVERING   | SECONDARY   |
    +-------------+-------------+--------------+-------------+
    2 rows in set (0.00 sec)
    

    查看错误日志,有如下错误信息,提示错误的组复制通过的用户。

    [ERROR] [MY-013117] [Repl] Slave I/O for channel 'group_replication_recovery': Fatal error: Invalid (empty) username when attempting to connect to the master server. Con    nection attempt terminated. Error_code: MY-013117
    
  3. 如果组复制集群中写入了大量的事务,新节点加入集群后,也可能长时间处于 RECOVING 状态,此时,新节点可能是在同步事务。因此,无法根据长时间处于 RECOVING 状态判断节点是否异常,此时可以查看错误日志进行判断。

无法加入集群问题

  1. 节点数据不一致。

    如果新节点中存在一个事务,该事务在现有的组复制集群中并不存在,则新节点无法加入集群。如下示例:

     mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY);
     Query OK, 0 rows affected (0.10 sec)
    
     mysql> start group_replication;
     ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log.
    

    查看错误日志,有如下错误信息。

     [ERROR] [MY-011526] [Repl] Plugin group_replication reported: 'This member has more executed transactions than those present in the group. Local transactions: 
     286 2657a7b1-fe43-11ea-ad01-ec5c6826bca3:1 > Group transactions: 11223344-1122-1122-1122-112233445566:1-5'
     [ERROR] [MY-011522] [Repl] Plugin group_replication reported: 'The member contains transactions not present in the group. The member will now exit the group.'
    
  2. 无法连接到集群其它节点。

    前文中介绍了,集群启动时需要配置参数 group_replication_group_seeds 参数。如果节点无法连接到 seeds 中的其它节点,则无法加入集群。

    此时,需要根据错误日志进行具体分析,可能原因包括:

    1. group_replication_group_seeds 参数配置错误
    2. group_replication_local_address 配置错误
    3. group_replication_group_name 配置错误
    4. 节点网络异常,网络分区等
    5. 组复制尚未初始化
    6. 组复制其它节点发生异常,或者已经退出了组复制
    7. 其它异常

      此时需要根据具体的原因进行相应的分析和处理。

集群规模退化问题

根据组复制本身的设计原则,如果节点中少数节点发生故障,一段时间后,节点会被踢出集群。此时组复制集群规模自动退化,这属于正常行为,不需要处理。如果需要将故障的节点重新加入集群,再修复故障后,再次执行 START GROUP_REPLICATION 命令即可。

集群规模退化和参数 group_replication_member_expel_timeout 相关,当一个节点故障时,在 expel_timeout 超时时间后,才会主动将该节点踢出集群,实现集群规模的退化。

!!!注意:在该参数超时之前,故障的节点无法通过 START GROUP_REPLICATION 命令重新加入集群,因为节点仍在集群中,所以该参数不宜设置过大,否则会导致节点长时间无法重新加入集群的问题。另外一个问题,当有节点故障时,整个组复制集群的性能吞吐会有较大程度的下降,所以在 expel_timeout 超时之前的时间内,集群性能会急剧下降。

异常及恢复问题

单个节点异常及恢复

可能包含如下情形:

  1. 单个节点网络异常
  2. 网络分区
  3. 节点 mysql 服务进程异常
  4. 其它异常

恢复方案有:

  1. 配置参数 group_replication_autorejoin_tries,在网络异常,或者网络分区恢复后,节点会自动尝试重新加入集群。该参数最大值为 2016,代表最多尝试 2016 次,每次间隔 5 分钟,也就是最大尝试时间为 2016 * 5min = 168h = 7d,即最大尝试恢复时间大概在1周左右。
  2. 配置参数 group_replication_start_on_boot,如果是 mysql 服务进程退出,当参数为 ON 时,重启阶段会自动尝试加入集群。
  3. 手动执行 START GROUP_REPLICATION 命令

这里最需要注意的是 group_replication_start_on_boot,只会在 mysql 服务进程重启的时候自动尝试加入集群,并且不受参数 group_replication_autorejoin_tries 参数控制。如果重启后因其它原因导致加入集群失败,则不会继续自动尝试了,此时需要进行手动恢复。

多数节点同时故障的问题

可能包含的原因有:

  1. 集群节点数量为 2n,网络分区导致每个分区数为 n
  2. 集群节点数为 2n 或者 2n + 1,网络分为多个分区,导致每个节点分区数小于 n
  3. 多数节点网络同时异常,如机房网络异常等
  4. 多数节点的 mysql 服务进程同时异常退出,如机房断电等
  5. 其它异常

当多数节点故障后,整个集群将不可用。此时,需要重新初始化组复制集群。此时的恢复方案一般为:

  1. 恢复故障,比如恢复网络,或者重启节点
  2. 登录所有节点,执行 SHOW MASTER STATUS 查看 gtid 信息,选择包含最新 gtid 信息的节点作为初始化节点,假设为 node-A
  3. 如果node-A没有重启,首先在 node-A 上执行 STOP GROUP_REPLICATION 命令,退出上一次的集群
  4. 在 node-A 上执行如下命令,启动组复制

     mysql> SET GLOBAL group_replication_bootstrap_group=ON;
     Query OK, 0 rows affected (0.00 sec)
    
     mysql> start group_replication; 
     Query OK, 0 rows affected (3.18 sec)
    
     mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
     Query OK, 0 rows affected (0.00 sec)
    
  5. 等待 node-A 节点处于 ONLINE 状态
  6. 对于其它节点,分别执行如下步骤,重新加入集群

    1. 如果该节点没有重启,执行 STOP GROUP_REPLICATION 命令,退出上一次的集群
    2. 执行 START GROUP_REPLICATION 命令加入新的组复制集群
    3. 等待集群处于 ONLINE 状态

因为组复制本身设计实现存在的一些问题,这里需要特别注意如下一些问题:

  1. 可能出现 STOP GROUP_REPLICATION 无法退出上一次组复制集群的问题,此时可能需要重启节点。
  2. 可以设置参数 group_replication_unreachable_majority_timeout ,比如 30s,或者 60s 之类,如果节点没有重启,在 node-A 重新初始化集群后,且该节点已经处于 ERROR 状态时,可以自动加入到新的组复制集群中
  3. 由于执行 START GROUP_REPLICATION 命令时,会先应用 relaylog 日志,可能导致其它节点比 node-A 多执行了事务,此时该节点无法加入集群中。这是组复制的bug,如果出现上述问题,只能先将该节点数据恢复后再加入集群。

大事务问题

组复制对大事务处理不好,如果出现大事务,可能导致集群性能吞吐下降等各种问题。解决方案是,尽量避免大事务语句。

执行语句限制问题

LOCK TABLE 语句

当集群的数据一致性级别,即参数 group_replication_consistency 大于 BEFORE 级别时,不支持执行 LOCK TABLE 语句,否则可能造成集群死锁,无法执行任何事务。

XA事务不支持

目前,组复制不能很好的支持 XA 事务,在节点出现异常时,执行 XA 事务可能导致各种问题。

无法执行只读语句

如果节点处于 ERROR 状态时,可能无法执行任何语句,包括只读的查询语句,查询 INFOMATION_SCHEMAmysql等系统表也无法执行。此时,需要执行 STOP GROUP_REPLICATION 后,才能正常执行只读语句。

DDL语句问题

组复制支持多主写模式,但是多写不能很好的支持 DDL 语句。如果多个节点同时对同一张表进行 DDL 操作,可能导致集群异常。如果其中一个节点执行 DDL 语句,其它节点执行该表的 DML 写事务,也可能导致问题。

读写一致性问题

当前,组复制支持多种不同的一致性级别,包括:

  1. EVENTUAL:默认级别,不保证任何的数据一致性
  2. BEFORE_ON_PRIMARY_FAILOVER: 一般用于单写集群中,即 group_replication_single_primary_mode=on 时,从 secondly 节点读取数据时,不保证读取到最新数据。但是如果发生主节点切换,新主会先将所有的数据应用完成之后才能提供服务。此时可能切换时间过长,导致切换时间内集群不可用。
  3. BEFORE:保证 secondly 节点能够读取到最新数据。同 BEFORE_ON_PRIMARY_FAILOVER 一样,存在切换时间过长的问题。
  4. AFTER:保证主节点写事务能够同步复制到所有的 secondly 节点,保证读写一致性。但性能消耗较大。
  5. BEFORE_AND_AFTER:最严格级别,保证读写一致性。

实际部署时,需要根据业务情况选择一致性级别,否则可能出现的问题包括:

  1. 业务不需要读一致性,但级别设置太高,导致集群性能太低
  2. 级别设置太低,无法满足业务读写一致性的要求
  3. secondly 节点配置太低,延迟太大时,导致故障切换时间太长而无法使用的问题
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论