# GreatSQL FAQ

# GreatSQL相关

# 0. GreatSQL简介

GreatSQL开源数据库是适用于金融级应用的国内自主MySQL版本,专注于提升MGR可靠性及性能,支持InnoDB并行查询等特性,可以作为MySQL或Percona Server的可选替换,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

GreatSQL除了提升MGR性能及可靠性,还引入InnoDB事务锁优化及并行查询优化等特性,以及众多BUG修复。

GreatSQL社区官网:https://greatsql.cn (opens new window)

# 1. GreatSQL的特色有哪些

相较于MySQL/Percona Server,GreatSQL主要增加几个特性:

  1. 地理标签
  2. 仲裁节点
  3. 快速单主
  4. 智能选主
  5. 并行查询

选用GreatSQl主要有以下几点优势:

  • 专注于提升MGR可靠性及性能,支持InnoDB并行查询特性
  • 是适用于金融级应用的MySQL分支版本
  • 地理标签,提升多机房架构数据可靠性
  • 仲裁节点,用更低的服务器成本实现更高可用
  • 单主模式下更快,选主机制更完善
  • InnoDB表也支持并行查询,让CPU资源不再浪费
  • 全新流控机制,让MGR运行更流畅不频繁抖动
  • 相对官方社区版,MGR运行更稳定、可靠
  • 其他...

无论是更可靠的MGR还是性能更好的InnoDB,都值得将当前的MySQL或Percona Server升级到GreatSQL。

目前GreatSQL最新版本是8.0.25-17,可点击这里下载最新版本 (opens new window)

关于GreatSQL的优势可阅读下面几篇文章:

# 2. GreatSQL在哪里可以下载

# 二进制包、RPM包

二进制包下载地址:https://gitee.com/GreatSQL/GreatSQL/releases (opens new window)

目前提供CentOS 7、CentOS 8两种操作系统,以及X86和ARM两种不同架构下的二进制包、RPM包。

minimal 关键字的安装包是对二进制文件进行strip后,所以文件尺寸较小,功能上没本质区别,仅是不支持gdb debug功能,可以放心使用。

# 源码

可以直接用git clone的方式下载GreatSQL源码,例如:

# 可从gitee下载
$ git clone https://gitee.com/GreatSQL/GreatSQL.git

# 或从github下载
$ git clone https://github.com/GreatSQL/GreatSQL.git

# Ansible安装包

GreatSQL提供Ansible一键安装包,可在gitee或github下载:

  • https://gitee.com/GreatSQL/GreatSQL-Ansible/releases
  • https://github.com/GreatSQL/GreatSQL-Ansible/releases

# Docker镜像

GreatSQL提供Docker镜像,可直接从docker hub拉取:

# 直接下载最新版本
$ docker pull docker.io/greatsql/greatsql

# 或自行指定版本
$ docker pull docker.io/greatsql/greatsql:8.0.25

# 或指定ARM版本
$ docker pull docker.io/greatsql/greatsql:8.0.25-aarch64

# 3. 使用GreatSQL遇到问题时找谁

使用GreatSQL过程中如果遇到问题,可将问题细节整理清楚后,联系GreatSQL社区寻求帮助。

扫码添加GreatSQL社区助手:
-扫码添加GreatSQL社区助手

或扫码加入GreatSQL社区QQ群(533341697):
-或扫码加入GreatSQL社区QQ群533341697

此外,我们已经在B站发布MGR相关系列视频,可以前往学习,视频链接:https://space.bilibili.com/1363850082 (opens new window)

# 4. GreatSQL相关资源有哪些

一、文档 目前GreatSQL相关文档全部发布在gitee上(https://gitee.com/GreatSQL/GreatSQL-Doc/ (opens new window)),主要有以下几部分

  1. GreatSQL历史版本说明
  1. 《深入浅出MGR》系列
  1. 《GreatSQL手册》系列,地址

二、视频 目前GreatSQL相关视频全部发布在B站上(https://space.bilibili.com/1363850082 (opens new window)),主要有以下几部分

  1. 《实战MGR》
  1. 《深入浅出MGR》
  1. 《零基础学习MySQL》
  1. 万里数据库工程师的公开分享

# 5. GreatSQL版本计划是怎样的

GreatSQL不计划每个小版本都跟随,暂定奇数版本跟随方式,即 8.0.25、8.0.27、8.0.29 ... 以此类推。

未来若有版本计划变更我们再更新。

目前已有的版本:

GreatSQL 8.0

GreatSQL 5.7

# MGR运维部署

# 1. 可以使用MySQL Shell来管理GreatSQL吗

是可以的,最好采用相同版本号的MySQL Shell即可。

GreatSQL 8.0.25-16起,如果有仲裁节点,则需要用GreatSQL MySQL Shell版本才能管理,否则只能在MySQL命令行下管理。

GreatSQL MySQL Shell下载链接 https://gitee.com/GreatSQL/GreatSQL/releases/GreatSQL-8.0.25-16 (opens new window)

# 2. MGR最多可支持多少个节点

MGR最多可支持9个节点,无论是单主还是多主模式。

# 3. MGR可以设置为自启动吗

设置参数 group_replication_start_on_boot = ON 即可。但是当MGR第一个节点初始化启动时,或者整个MGR集群都关闭再重启时,第一个节点都必须先采用引导模式 group_replication_bootstrap_group = ON

# 4. 为什么启动MGR后,多了个33061端口

当启用MGR服务后,MySQL会监听33061端口,该端口用于MGR节点间的通信。因此当服务器间有防火墙策略时,记得针对该端口开放。

当然了,可自行定义该端口,例如 group_replication_local_address=192.168.0.1:33062

# 5. 部署MGR时,务必对所有节点都设置hostname吗

这个不是必须的。

之所以要在每个节点上都加上各节点的hostname对照表,是因为在MGR节点间通信过程中,可能收到的主机名和本地实际配置的不一致。

这种情况下,也可以在每个节点上自行设置 report_hostreport_port 来解决这个问题。

# 6. 可以跨公网部署MGR吗

可以的,但非常不推荐。

此外,由于MGR默认的allowlist不包含公网地址,因此需要将公网地址加进去,例如:

group_replication_ip_allowlist='192.0.2.0/24, 114.114.114.0/24'

顺便提醒下,MGR默认的allowlist范围(group_replication_ip_allowlist=AUTOMATIC)是以下几个

IPv4 (as defined in RFC 1918)
10/8 prefix       (10.0.0.0 - 10.255.255.255) - Class A
172.16/12 prefix  (172.16.0.0 - 172.31.255.255) - Class B
192.168/16 prefix (192.168.0.0 - 192.168.255.255) - Class C

IPv6 (as defined in RFC 4193 and RFC 5156)
fc00:/7 prefix    - unique-local addresses
fe80::/10 prefix  - link-local unicast addresses

127.0.0.1 - localhost for IPv4
::1       - localhost for IPv6

有时候docker容器的IP地址不在上述范围中,也会导致MGR服务无法启动。

# 7. 怎么查看MGR当前是单主还是多主模式

执行下面的命令:

[root@GreatSQL]> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+-----------...-+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID ... | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+-----------...-+-------------+--------------+-------------+----------------+
| group_replication_applier | 4ebd3504-1... |        3306 | ONLINE       | SECONDARY   | 8.0.25         |
| group_replication_applier | 549b92bf-1... |        3307 | ONLINE       | SECONDARY   | 8.0.25         |
| group_replication_applier | 5596116c-1... |        3308 | ONLINE       | SECONDARY   | 8.0.25         |
| group_replication_applier | ed5fe7ba-3... |        3309 | ONLINE       | PRIMARY     | 8.0.25         |
+---------------------------+-----------...-+-------------+--------------+-------------+----------------+

如果只看到一个节点的 MEMBER_ROLE 值为 PRIMARY,则表示这是单主模式。如果看到所有节点上该状态值均为 PRIMARY,则表示这是多主模式。

另外,也可以通过查询MySQL选项值来确认:

[root@GreatSQL]# mysqladmin var|grep -i group_replication_single_primary_mode
| group_replication_single_primary_mode        | ON

值为 ON,这表示采用单主模式。如果该值为 OFF,则表示采用多主模式。

在MySQL Shell中也可以查看状态来确认:

MySQL  GreatSQL:3306 ssl  JS > var c=dba.getCluster()
MySQL  GreatSQL:3306 ssl  JS > c.describe() /* 或者 c.status() */
...
        "topologyMode": "Single-Primary"
...

P.S,强烈建议采用单主模式,遇到bug或其他问题的概率更低,运行MGR更稳定可靠。

# 8. 怎么切换单主或多主

在MySQL客户端命令行模式下,执行下面的命令即可:

-- 从单主切换为多主
[root@GreatSQL]> SELECT group_replication_switch_to_multi_primary_mode();
+--------------------------------------------------+
| group_replication_switch_to_multi_primary_mode() |
+--------------------------------------------------+
| Mode switched to multi-primary successfully.     |
+--------------------------------------------------+

-- 从多主切换为单主
[root@GreatSQL]> SELECT group_replication_switch_to_single_primary_mode();
+---------------------------------------------------+
| group_replication_switch_to_single_primary_mode() |
+---------------------------------------------------+
| Mode switched to single-primary successfully.     |
+---------------------------------------------------+

注意: 切换时会重新选主,新的主节点有可能不是切换之前的那个,这时可以运行下面的命令来重新指定:

[root@GreatSQL]> SELECT group_replication_set_as_primary('ed5fe7ba-37c2-11ec-8e12-70b5e873a570');
+--------------------------------------------------------------------------+
| group_replication_set_as_primary('ed5fe7ba-37c2-11ec-8e12-70b5e873a570') |
+--------------------------------------------------------------------------+
| Primary server switched to: ed5fe7ba-37c2-11ec-8e12-70b5e873a570         |
+--------------------------------------------------------------------------+

也可以通过MySQL Shell来操作:

MySQL  GreatSQL:3306 ssl  JS > var c=dba.getCluster()
> c.switchToMultiPrimaryMode()  /*切换为多主模式*/
Switching cluster 'MGR27' to Multi-Primary mode...

Instance 'GreatSQL:3306' was switched from SECONDARY to PRIMARY.
Instance 'GreatSQL:3307' was switched from SECONDARY to PRIMARY.
Instance 'GreatSQL:3308' was switched from SECONDARY to PRIMARY.
Instance 'GreatSQL:3309' remains PRIMARY.

The cluster successfully switched to Multi-Primary mode.

> c.switchToSinglePrimaryMode()  /*切换为单主模式*/
Switching cluster 'MGR27' to Single-Primary mode...

Instance 'GreatSQL:3306' remains PRIMARY.
Instance 'GreatSQL:3307' was switched from PRIMARY to SECONDARY.
Instance 'GreatSQL:3308' was switched from PRIMARY to SECONDARY.
Instance 'GreatSQL:3309' was switched from PRIMARY to SECONDARY.

WARNING: The cluster internal session is not the primary member anymore. For cluster management operations please obtain a fresh cluster handle using dba.getCluster().

WARNING: Existing connections that expected a R/W connection must be disconnected, i.e. instances that became SECONDARY.

The cluster successfully switched to Single-Primary mode.

> c.setPrimaryInstance('GreatSQL:3309');  /*重新设置主节点*/
Setting instance 'GreatSQL:3309' as the primary instance of cluster 'MGR27'...

Instance 'GreatSQL:3306' was switched from PRIMARY to SECONDARY.
Instance 'GreatSQL:3307' remains SECONDARY.
Instance 'GreatSQL:3308' remains SECONDARY.
Instance 'GreatSQL:3309' was switched from SECONDARY to PRIMARY.

The instance 'GreatSQL:3309' was successfully elected as primary.

P.S,强烈建议采用单主模式,遇到bug或其他问题的概率更低,运行MGR更稳定可靠。

# 9. MySQL Router支持单机多实例部署吗

是的,支持。 在MySQL Router初始化部署时,添加 --name--directory 及端口号等参数即可,例如:

-- 部署第一个实例
root@GreatSQL# mysqlrouter --bootstrap mymgr@192.168.1.1:3306 --name=MGR1 --directory=/etc/mysqlrouter/MGR1  --user=mysqlrouter --conf-base-port=6446 --https-port=8443

-- 部署第二个实例
root@GreatSQL# mysqlrouter --bootstrap mymgr@192.168.1.1:4306 --name=MGR2 --directory=/etc/mysqlrouter/MGR2  --user=mysqlrouter --conf-base-port=7446 --https-port=9443

然后每个实例用各自目录下的 start.shstop.sh 脚本启停即可。

关于MySQL Router多实例部署的方法,可以参考这篇参考文档:《叶问》38期,MGR整个集群挂掉后,如何才能自动选主,不用手动干预 (opens new window)

# 10. MySQL Shell 8.0能管理MySQL 5.7的MGR集群吗

答案是肯定的。

不过由于MySQL 5.7里没有MGR管理的几个UDF,因此在MySQL Shell里调用 setPrimaryInstance()switchToMultiPrimaryMode() 等函数时会报错,是不支持的。

所以说,还是尽量升级到MySQL 8.0吧。

# 11. GreatSQL 支持ARBITRATOR节点冗余(多个ARBITRATOR节点)吗

支持的,可以同时有多个ARBITRATOR节点。

# 12. 当ARBITRATOR节点异常退出后剩下的两个节点会有脑裂风险吗

是的,当ARBITRATOR节点退出后,只剩下两个节点,存在脑裂风险。因此当ARBITRATOR节点异常退出时,应当尽快重新拉起,做好监控及自愈处理。

# 13. 多个mgr集群,是否可以共用ARBITRATOR节点

不可以,不同集群的ARBITRATOR节点可以交叉部署,同一集群不能放一起。也可以在一台专属服务器上部署多实例,专门用作ARBITRATOR节点。 仲裁节点对系统负载的影响很小,可以参考下面的数据:

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  1      0    894    206  12238    0    0     0 27186 32669 44745 12  8 68 13  0
 1  0      0    893    206  12239    0    0     0 27555 34887 47219 12 10 64 14  0
 2  1      0    891    206  12240    0    0     0 27756 35025 47353 13  8 66 13  0

#Secondary节点
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  3      0   1950    168  11988    0    0     0 27236 23333 35077 25 19 42 15  0
 2  2      0   1946    168  11990    0    0     0 25950 22254 34017 23 21 42 13  0
 1  0      0   1943    168  11993    0    0     0 26382 21943 33385 24 20 41 14  0

#Arbitrator节点
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0     22    328    193  14132    0    0     0     0 13587 14159  2  2 96  0  0
 1  0     22    326    193  14132    0    0     0     0 15274 15714  3  3 95  0  0
 0  0     22    324    193  14132    0    0     0     0 14983 15155  2  3 95  0  0

# 基于MGR的架构方案

# 1. GreatSQL支持读写分离吗

可以利用MySQL Router来实现读写分离。

# 2. MGR支持读负载均衡吗

支持的。可以在MGR集群的前端挂载MySQL Router,即可实现读负载均衡。

# 3. MGR支持写负载均衡吗

不支持。由于MGR采用shared nothing模式,每个节点都存储全量数据,因此所有写入每个节点都要再应用一次。

# 4. 两个MGR集群间还可以构建主从复制关系吗

首先,答案是肯定的,可以的。

其次,为了保障MGR的数据安全性,对不同角色节点的要求是这样的:

  • 在单主模式(Single-Primary)时,从节点(Secondary)不能同时作为Master-Slave的从节点(Slave)
  • 在单主模式时,主节点(Primary)可以同时作为M-S的从节点(Slave)
  • 在多主模式时,任何节点可以作为MS的从节点(Slave)。提醒:强烈建议不要使用多主模式
  • 要求都是InnoDB表,且没有数据冲突(例如数据重复、数据不存在等),没有使用外键
  • 节点重启时,注意要先启动MGR服务,再启动M-S服务。这时候可以设置 group_replication_start_on_boot=ONskip_slave_start=ON 予以保证

在这两个MGR集群间的主从复制可以采用异步复制,也可以采用半同步复制,主要取决于两个集群间的网络延迟情况及架构设计方案。这时候,整体架构方案类似下面这样: -两个MGR间构建M-S复制架构

在这个架构下,两个MGR集群间是相互独立的,如果前端挂载MySQL Router的话,需要单独创建对应的连接。

如果担心MGR节点因为发生切换,只要原来指向的Master没有退出MGR集群,则这个主从复制关系还是存在的,不受影响。如果担心原来的Master节点退出MGR集群而导致复制中断,则可以采用MySQL 8.0.22后推出的新特性 Async Replication Auto failover 来解决,把各节点都加到复制源中,可以参考下面的资料:

# 5. MGR可以像主从复制那样只启动两个节点吗

MGR在初始化启动时,是可以只启动两个节点,甚至只有一个节点,但是这样就失去MGR的意义了。因为只要少于三个节点,就没办法进行多数派投票,当发生网络故障等情况时,无法投票确认哪些节点该被踢出集群。

如果是为了节省服务器成本,则可以选用 GreatSQL 8.0.25-16 及以上版本,它支持仲裁节点角色,可以用一个低配服务器来运行,也就是几乎可以用接近于两台服务器的成本来运行 一个三节点的MGR集群。详情参考:1.1 新增仲裁节点(投票节点)角色 (opens new window)

# 6. MySQL Router可以配置在MGR主从节点间轮询吗

MySQL Router通过两个端口来区分读写服务请求,默认是 6446端口提供读写服务,6447端口提供只读服务。 在单主模式下,读写服务只会连接到Primary节点。对于读写服务端口,可选的策略有以下两种:

  • first-available,只连接第一个可用节点
  • round-robin(默认),在多个主节点间轮询

只读服务默认是对所有Secondary节点轮询。对于只读服务端口,可选的策略有以下3种:

  • first-available,只连第一个可用节点
  • round-robin,在所有可用Secondary节点间轮询,如果所有Secondary节点都不可用时,只读服务则不可用,不会连接到Primary节点
  • round-robin-with-fallback(默认),在所有Secondary节点间轮询,跳过不可用节点。如果所有Secondary节点都不可用时,会再连接到Primary节点

现在我们知道了,MySQL Router只有在所有Secondary节点都不可用时,才会去连接Primary节点读数据,无法做到在发起只读请求时,同时连接主从节点。

更多关于 MySQL Router 可用的策略请参见文档 routing_strategy参数/选项 (opens new window)

# MGR监控及故障处理

# 1. 怎么查看MGR从节点是否有延迟

首先,可以执行下面的命令查看当前除了 PRIMARY 节点外,其他节点的 trx_tobe_certifiedrelaylog_tobe_applied 值是否较大:

[root@GreatSQL]> SELECT MEMBER_ID AS id, COUNT_TRANSACTIONS_IN_QUEUE AS trx_tobe_certified, COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE AS relaylog_tobe_applied, COUNT_TRANSACTIONS_CHECKED AS trx_chkd, COUNT_TRANSACTIONS_REMOTE_APPLIED AS trx_done, COUNT_TRANSACTIONS_LOCAL_PROPOSED AS proposed FROM performance_schema.replication_group_member_stats;
+--------------------------------------+-------------------+---------------------+----------+----------+----------+
| id                                   |trx_tobe_certified |relaylog_tobe_applied| trx_chkd | trx_done | proposed |
+--------------------------------------+-------------------+---------------------+----------+----------+----------+
| 4ebd3504-11d9-11ec-8f92-70b5e873a570 |                 0 |                   0 |   422248 |        6 |   422248 |
| 549b92bf-11d9-11ec-88e1-70b5e873a570 |                 0 |              238391 |   422079 |   183692 |        0 |
| 5596116c-11d9-11ec-8624-70b5e873a570 |              2936 |              238519 |   422115 |   183598 |        0 |
| ed5fe7ba-37c2-11ec-8e12-70b5e873a570 |              2976 |              238123 |   422167 |   184044 |        0 |
+--------------------------------------+-------------------+---------------------+----------+----------+----------+

其中,relaylog_tobe_applied 的值表示远程事务写到relay log后,等待回放的事务队列,trx_tobe_certified 表示等待被认证的事务队列大小,这二者任何一个值大于0,都表示当前有一定程度的延迟。

另外,也可以查看接收到的事务和已执行完的事务之间的差距来判断:

[root@GreatSQL]> SELECT RECEIVED_TRANSACTION_SET FROM performance_schema.replication_connection_status WHERE  channel_name = 'group_replication_applier' UNION ALL SELECT variable_value FROM performance_schema.global_variables WHERE  variable_name = 'gtid_executed'\G
*************************** 1. row ***************************
RECEIVED_TRANSACTION_SET: 6cfb873b-573f-11ec-814a-d08e7908bcb1:1-3124520
*************************** 2. row ***************************
RECEIVED_TRANSACTION_SET: 6cfb873b-573f-11ec-814a-d08e7908bcb1:1-3078139

可以看到,接收到的事务 GTID 已经到了 3124520,而本地只执行到 3078139,二者的差距是 46381。可以顺便持续关注这个差值的变化情况,估算出本地节点是否能追平延迟,还是会加大延迟。

# 2. 三节点的MGR集群,有两个节点宕机后还能正常工作吗

要看具体是哪种情况。

如果两个节点是正常关闭的话,则会向MGR集群发送退出信号,这种情况下,这两个节点属于正常退出,最后仅剩的节点会被提升为Primary角色,还可以正常工作,允许对其进行读写,只是此时没有可用性冗余了。当其他节点再次启动并加入集群后,又能恢复正常服务。

如果是因为网络故障,或者mysqld进程发生oom、或被误杀、或其他原因退出了,则这些节点会被标识为 UNREACHABLE 状态,等待直到 group_replication_member_expel_timeout 时长(单位:秒)后这个节点才会正式退出集群。在这种情况下,一旦超过多数派节点处于 UNREACHABLE 状态时,则整个集群不可用,无法提供读写服务。这种情况下,需要把剩下的节点重启MGR服务才能恢复。

正常情况下,不要把 group_replication_member_expel_timeout 值调整太大,并且MGR的事务一致性级别尽量不要选择 AFTER 模式,以防出现整个集群服务不可用的问题,详细参见这篇文章:为什么MGR一致性模式不推荐AFTER (opens new window)

# 3. 都有哪些情况可能导致MGR服务无法启动

简单整理了下,大概有以下原因可能导致MGR服务无法启动:

  1. 网络原因,例如网络本来就不通,或被防火墙拦住。防火墙通常至少有两道,操作系统默认的firewall策略,以及云主机被默认的安全策略。
  2. 第一个启动的节点没先做初始引导操作(group_replication_bootstrap_group=ON)。
  3. 没有正确配置group_name,所有节点的 group_replication_group_name 值要一致才可以。
  4. 没正确配置 group_replication_group_name,常见于新手。要为MGR服务专门新开一个服务端口,常用33061端口,但新手可能会照样写成3306端口。
  5. 通常,我们会在各MGR节点的 hosts 文件里加上所有节点的hostname。这是为了防止本地节点使用的hostname和MGR收到的hostname不一致,这种情况下,可以在每个本地节点设置 report-host,主动上报hostname即可解决。
  6. 没设置正确的allowlist。有可能加入MGR各节点的IP不在默认的allowlist中,可参考这篇文章:MySQL Group Replication集群对IP地址的限制导致的一些问题与解决办法 (opens new window)
  7. 个别节点的本地事务更多,例如误操作写入数据,也会无法加入MGR,这种情况需要重建本地节点。
  8. 个别节点的本地事务缺失太多,且加入MGR时无法自动完成恢复,这种情况比较少见,需要手动执行clone复制数据,或者其他类似操作。

# 4. 为什么InnoDB并行查询(PQ)不可用

可能原因有几种:

  1. 优化器认为没必要走并行,比如因为cost太小了。
  2. 不支持的SQL类型,目前还不支持子查询。
  3. 优化器认为可用资源不足,"无法"使用并行查询。

例如,有个场景是因为 parallel_memory_limit 设置过低,优化器判断SQL的cost较大,所以只是尝试去使用并行,但没发挥最大优势

mysql> show global status like 'PQ_%';
| PQ_memory_refused  | 0     |
| PQ_memory_used     | 0     |  <-- 没真正用上,因为可用buffer不够
| PQ_threads_refused | 82    |
| PQ_threads_running | 4     |  <-- 尝试并行

在调大 parallel_memory_limit 之后就好了

mysql> show global status like 'PQ_%';
| PQ_memory_refused  | 0       |
| PQ_memory_used     | 4801552 |  <-- PQ消耗的内存
| PQ_threads_refused | 82      |
| PQ_threads_running | 4       |  <-- 并行线程4

# 其他问题

# 1. 使用MGR有什么限制吗

下面是关于MGR使用的一些限制:

  • 所有表必须是InnoDB引擎。可以创建非InnoDB引擎表,但无法写入数据,在利用Clone构建新节点时也会报错。
  • 所有表都必须要有主键。同上,能创建没有主键的表,但无法写入数据,在利用Clone构建新节点时也会报错。
  • 不要使用大事务,默认地,事务超过150MB会报错,最大可支持2GB的事务(在GreatSQL未来的版本中,会增加对大事务的支持,提高大事务上限)。
  • 如果是从旧版本进行升级,则不能选择 MINIMAL 模式升级,建议选择 AUTO 模式,即 upgrade=AUTO
  • 由于MGR的事务认证线程不支持 gap lock,因此建议把所有节点的事务隔离级别都改成 READ COMMITTED。基于相同的原因,MGR集群中也不要使用 table lockname lock(即 GET_LOCK() 函数 )。
  • 在多主(multi-primary)模式下不支持串行(SERIALIZABLE)隔离级别。
  • 不支持在不同的MGR节点上,对同一个表分别执行DML和DDL,可能会造成数据丢失或节点报错退出。
  • 在多主(multi-primary)模式下不支持多层级联外键表。另外,为了避免因为使用外键造成MGR报错,建议设置 group_replication_enforce_update_everywhere_checks=ON
  • 在多主(multi-primary)模式下,如果多个节点都执行 SELECT ... FOR UPDATE 后提交事务会造成死锁。
  • 不支持复制过滤(Replication Filters)设置。

看起来限制有点多,但绝大多数时候并不影响正常的业务使用。

此外,想要启用MGR还有几个要求:

  • 每个节点都要启用binlog。
  • 每个节点都要转存binlog,即设置 log_slave_updates=1
  • binlog format务必是row模式,即 binlog_format=ROW
  • 每个节点的 server_idserver_uuid 不能相同。
  • 在8.0.20之前,要求 binlog_checksum=NONE,但是从8.0.20后,可以设置 binlog_checksum=CRC32
  • 要求启用 GTID,即设置 gtid_mode=ON
  • 要求 master_info_repository=TABLErelay_log_info_repository=TABLE,不过从MySQL 8.0.23开始,这两个选项已经默认设置TABLE,因此无需再单独设置。
  • 所有节点上的表名大小写参数 lower_case_table_names 设置要求一致。
  • 最好在局域网内部署MGR,而不要跨公网,网络延迟太大的话,会导致MGR性能很差或很容易出错。
  • 建议启用writeset模式,即设置以下几个参数
    • slave_parallel_type = LOGICAL_CLOCK
    • slave_parallel_workers = N,N>0,可以设置为逻辑CPU数的2倍
    • binlog_transaction_dependency_tracking = WRITESET
  • slave_preserve_commit_order = 1
    • slave_checkpoint_period = 2

# 2. MGR相对传统主从复制是不是会更耗CPU、内存和带宽等资源

一定程度上来说,是的。因为MGR需要在多个节点间进行事务冲突检测,不过这方面的开销有限,总体来说也还好。

# 3. MGR中可以创建无主键的InnoDB表吗

是可以的,并且会复制到所有MGR节点,但是仅能创建空表,业务上不能写入数据。

往无主键的InnoDB表中写入数据时,会报告类似下面的错误:

[root@GreatSQL] [test]> insert into t3 select 1;
ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin.

同理,也可以创建MyISAM表,但写入时会提示失败。

此外,当欲加入MGR集群的新实例中有无主键的InnoDB表时,如果要通过 MySQL Shell 添加该节点,会发出类似下面的报错,无法加入:

Validating instance configuration at mgr03:3306...

This instance reports its own address as mgr03:3306
ERROR: The following tables do not have a Primary Key or equivalent column:
test.t3

Group Replication requires tables to use InnoDB and have a PRIMARY KEY or PRIMARY KEY Equivalent (non-null unique key). Tables that do not follow these requirements will be readable but not updateable when used with Group Replication. If your applications make updates (INSERT, UPDATE or DELETE) to these tables, ensure they use the InnoDB storage engine and have a PRIMARY KEY or PRIMARY KEY Equivalent.
If you can't change the tables structure to include an extra visible key to be used as PRIMARY KEY, you can make use of the INVISIBLE COLUMN feature available since 8.0.23: https://dev.mysql.com/doc/refman/8.0/en/invisible-columns.html

ERROR: Instance must be configured and validated with dba.checkInstanceConfiguration() and dba.configureInstance() before it can be used in an InnoDB cluster.
Cluster.addInstance: Instance check failed (RuntimeError)

这个报错在MySQL 8.0.25依然存在,据说在MySQL 8.0.27得到解决。

如果改成手动加入新节点,或者直接删除无主键表,则可以成功。

从上面的错误提示也能看出来,如果创建一个和主键等价的唯一索引(且要求不允许为NULL),该唯一索引可用做InnoDB表的聚集索引,就不会再报错了,业务也能正常写入数据。

# 4. GreatSQL怎么备份

可以利用GreatSQL安装包中提供的mysqldump工具执行逻辑备份。 也可以利用相同版本号的Percona Xtrabackup执行物理备份,例如利用Percona XtraBackup 8.0.25-17备份GreatSQL 8.0.25-15、GreatSQL 8.0.25-16版本,利用Percona XtraBackup 2.4备份GreatSQL 5.7.36-39版本。

# 5. 用MySQL Shell创建MGR时新增的 mysql_innodb_cluster_* 账号是干嘛用的

这是用MySQL Shell创建MGR时才有的特点,这些账户用于后续的节点分布式恢复场景。其账户名规则是:mysql_innodb_cluster_server_id@%,

详情见手册 Internal User Accounts Created by InnoDB Cluster (opens new window) 中的描述:

As part of using Group Replication, InnoDB Cluster creates internal recovery users which enable connections between the servers in the cluster. 
These users are internal to the cluster, and the user name of the generated users follows a naming scheme of mysql_innodb_cluster_server_id@%, 
where server_id is unique to the instance. In versions earlier than 8.0.17 the user name of the generated users followed a naming 
scheme of mysql_innodb_cluster_r[10_numbers].

# 6. 当一个SQL中既有普通JOIN又有子查询时,能否用到InnoDB并行查询(PQ)特性

这种情况下是不支持的。 目前GreatSQL 的 InnoDB并行查询还不支持子查询,未来会增加支持。

# 7. MySQL 5.7可以和GreatSQL 5.7混用datadir吗

是可以的。

不过也提醒下:如果有是在原有MySQL datadir上直接启动GreatSQL的话,记得执行mysql_upgrade哦,要不然是没有MEMBER_ROLE列的。

升级/切换步骤:

  1. 执行mysql_upgrade -f -s(至少加 -s,升级system schema) 2.重启实例(重启后才能识别到新的schema metadata)

同理,如果有跑MySQL 8.0.x和GreatSQL 8.0.x版本也是如此。

但还不支持5.7和8.0跨版本混跑。

# 8. MGR里推荐用哪个事务隔离级别

在GreatSQL MGR FAQ中提到一个限制条件:

  • 由于MGR的事务认证线程不支持 gap lock,因此建议把所有节点的事务隔离级别都改成 READ COMMITTED。基于相同的原因,MGR集群中也不要使用 table lock 及 name lock(即 GET_LOCK() 函数 )。

这句话的意思是,由于MGR的事务认证线程不支持gap lock,因此在MGR中,不能实现跨节点间的RR隔离级别保证。也就是说,在s1、s2两个MGR节点间,无法像是在同一个本地节点间实现RR隔离级别保证。

例如下面这样:

表t1,只有一个主键列id,已有3条数据:1、3、10,采用RR级别。

案例1:

时间线 节点1 节点2
T1 begin;
select * from t1;
| 1 |
| 3 |
|10 |
begin;
select * from t1 where id>=3;
| 3 |
| 10 |
T2 insert into t1 select 6;
commit;
select * from t1;
| 1 |
| 3 |
| 6 |
| 10 |
T3 begin;
select * from t1 where id>=3; -- 还是只有两条记录
| 3 |
| 10 |
T4 begin;
select * from t1 where id>=3 for update; -- 可以看到新插入的记录
| 3 |
| 6 |
| 10 |

案例2(先删掉上面插入的6这条记录):

时间线 节点1 节点2
T1 begin;
select * from t1;
| 1 |
| 3 |
| 10 |
T2 begin;
select * from t1 where id>=3 for update; -- 加锁
| 3 |
| 10 |
T3 insert into t1 select 6; -- 不会被阻塞(如果是在同一个节点上执行,RR级别,这个SQL下会被阻塞)
commit;
select * from t1;
| 1 |
| 3 |
| 6 |
| 10 |
T4 select * from t1 where id>=3 for update; -- 这里无论是否加for update,都会触发死锁
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

综上,在MGR中,即便本地节点选择的事RR级别,依然无法跨节点实现gap lock加锁,因此也就无法跨节点保证RR级别。但如果写入事务都在同一个节点的话,则设置RR是有意义的

# 9. GreatSQL性能表现如何

GreatSQL相对于MySQL官方社区版本有非常大的性能提升,尤其是引入了InnoDB并行查询特性,在TPC-H测试中,平均提升15倍以上,最高提升43倍,表现非常优异。

更多关于GreatSQL性能提升方面的内容可以参考下面几个测评报告: