传统MySQL复制备份架构是将数据从一个数据库同步到另一个数据库。主要操作是将主数据库的数据复制到辅助服务器,当主服务器数据出问题时,自动同步辅助服务器的数据到主服务器,以便恢复数据。但是这种架构有不少缺点,比如数据不够安全,同步可能会丢失等问题,可能会影响主服务器性能。
组复制是MySQL服务器插件,通过这种插件可以实现弹性、高可用、容错复制拓扑结构。 组复制是一种实现更灵活,容错的复制机制的方法。此过程涉及建立一个服务器池,每个服务器都参与确保正确复制数据。如果主服务器遇到问题,成员选举可以从组中选择新的主服务器。这允许其余节点继续运行,即使面对问题。通过实施Paxos一致性算法提供成员协商,故障检测和消息传递。
在本教程中,我们将使用三个Ubuntu服务器设置MySQL组复制。该配置将介绍如何操作单个主要或多主要复制组。
sudo
命令的非root账号的Ubuntu服务器,并且已开启防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后在购买服务器。在打开MySQL配置文件以配置组复制设置之前,我们需要生成一个UUID,我们可以使用它来识别我们将要创建的MySQL组。
在第一台服务器上,使用uuidgen
命令为组生成有效的UUID:
uuidgen
959cf631-538c-415d-8164-ca00181be227
复制输出的值,后面的步骤会用到它。
现在我们准备修改MySQL的配置文件了。打开每个MySQL服务器上的MySQL配置文件:
sudo nano /etc/mysql/my.cnf
默认情况下,该文件仅用于从子目录中寻找其他文件。我们将不得不在!includedir
行下面添加我们自己的配置。这使我们可以轻松地覆盖所包含文件中的任何设置。
首先,通过包含[mysqld]
打开MySQL服务器组件的一个部分。在此之下,我们将粘贴组复制所需的设置。以loose-
前缀的允许MySQL的正常处理不无故障正常识别选项。我们需要填写其中许多设置:
. . .
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[mysqld]
# General replication settings
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
transaction_write_set_extraction = XXHASH64
loose-group_replication_bootstrap_group = OFF
loose-group_replication_start_on_boot = OFF
loose-group_replication_ssl_mode = REQUIRED
loose-group_replication_recovery_use_ssl = 1
# Shared replication group configuration
loose-group_replication_group_name = ""
loose-group_replication_ip_whitelist = ""
loose-group_replication_group_seeds = ""
# Single or Multi-primary mode? Uncomment these two lines
# for multi-primary mode, where any host can accept writes
#loose-group_replication_single_primary_mode = OFF
#loose-group_replication_enforce_update_everywhere_checks = ON
# Host specific replication configuration
server_id =
bind-address = ""
report_host = ""
loose-group_replication_local_address = ""
我们将上面的配置分为四个部分。
第一部分包含不需要修改的组复制所需的常规设置:
. . .
# General replication settings
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
transaction_write_set_extraction = XXHASH64
loose-group_replication_bootstrap_group = OFF
loose-group_replication_start_on_boot = OFF
loose-group_replication_ssl_mode = REQUIRED
loose-group_replication_recovery_use_ssl = 1
. . .
你无需修改本节中的任何内容,因此你可以在粘贴后继续操作。
第二部分为组设置共享设置。我们需要修改,然后在每个节点上使用相同的设置。这包括组的UUID、可接受成员的白名单和要联系的种子成员以获取初始数据。
将loose-group_replication_group_name
设置为您以前使用uuidgen
命令生成的UUID。
接下来,将loose-group_replication_ip_whitelist
设置为所有MySQL服务器IP地址的列表,以逗号分隔。loose-group_replication_group_seeds
设置应该与白名单几乎相同,但应该设置每个成员组复制端口。在这里,我们将使用推荐的33061
端口进行组复制:
. . .
# Shared replication group configuration
loose-group_replication_group_name = "959cf631-538c-415d-8164-ca00181be227"
loose-group_replication_ip_whitelist = "203.0.113.1,203.0.113.2,203.0.113.3"
loose-group_replication_group_seeds = ""203.0.113.1:33061,203.0.113.2:33061,203.0.113.3:33061"
. . .
每个MySQL服务器上的此部分应该相同,因此请务必仔细复制。
接下来,你需要决定是配置单主组还是多主组。在官方MySQL文档中,这种区别也称为“单一”与“多主”复制。在单个主要配置中,MySQL指定一个主服务器来处理写入操作,其他服务器为只读。多主组允许写入任何组成员。
如果要配置多主组,请取消注释loose-group_replication_single_primary_mode
和loose-group_replication_enforce_update_everywhere_checks
指令。这将设置一个多主要组。对于单个主要组,只需将这两行注释掉:
. . .
# Single or Multi-primary mode? Uncomment these two lines
# for multi-primary mode, where any host can accept writes
#loose-group_replication_single_primary_mode = OFF
#loose-group_replication_enforce_update_everywhere_checks = ON
. . .
你可以稍后更改此设置,改完需要重新启动MySQL。要切换到新配置,你必须停止每个MySQL实例,使用新设置启动每个成员,然后重新引导组复制。这不会影响你的任何数据,但需要一小段停机时间。
第四部分包含每个服务器上不同的设置,包括:
必须将server_id
指令设置为唯一编号。 第一个成员是1,后面的每个成员逐渐+1。 将bind-address
和report_host
设置为当前服务器的IP地址,以便MySQL实例监听外部连接并将其地址正确报告给其他主机。 loose-group_replication_local_address
还应设置为当前服务器的IP地址,并将组复制33061
端口添加都到IP地址后面:
. . .
# Host specific replication configuration
server_id = 1
bind-address = "203.0.113.1"
report_host = "203.0.113.1"
loose-group_replication_local_address = "203.0.113.1:33061"
在每个MySQL服务器上完成此过程。
完成后,请仔细检查每台主机上的共享复制设置是否相同,以及是否为每台主机自定义了特定于主机的设置。完成后,在每台主机上保存并关闭文件。
我们的MySQL配置文件现在包含引导MySQL组复制所需的指令。要设置新的应用于MySQL实例,请使用以下命令在每台服务器上重新启动服务:
sudo systemctl restart mysql
在MySQL配置文件中,我们将服务配置为侦听默认3306
端口上的外部连接。我们还将33061
端口定义为成员应用于复制协调的端口。
我们需要在防火墙中打开对这两个端口的访问,我们可以通过输入以下命令来完成:
sudo ufw allow 33061
sudo ufw allow 3306
通过访问MySQL端口,我们可以创建复制用户并启用组复制插件。
在每个MySQL服务器上,登录MySQL:
mysql -u root -p
系统将提示你输入MySQL管理密码。之后,你将进入MySQL会话。我们需要做的第一件事是创建一个复制用户。
每台服务器上都需要一个复制用户来建立组复制。因为每个服务器都有自己的复制用户,所以我们需要在创建过程中关闭二进制日志记录。不然,一旦复制开始,该组将尝试将复制用户从主服务器传播到其他服务器,从而与已经存在的复制用户产生冲突。
我们将为复制用户请求SSL,在服务器上授予它们复制权限,然后刷新权限以实现更改。之后,我们将重新启用二进制日志记录以恢复正常操作。创建复制用户时,请确保使用安全密码:
SET SQL_LOG_BIN=0;
CREATE USER 'repl'@'%' IDENTIFIED BY 'password' REQUIRE SSL;
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
SET SQL_LOG_BIN=1;
接下来,我们需要设置group_replication_recovery
,以使用我们的新复制用户和相关密码。然后,每个服务器将使用这些凭据对组进行身份验证。
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='password' FOR CHANNEL 'group_replication_recovery';
使用复制用户,我们可以启用组复制插件以准备初始化组。由于我们使用的是最新版本的MySQL,我们可以通过输入以下内容来启用插件:
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
输入以下命令验证插件是否处于活动状态:
SHOW PLUGINS;
+----------------------------+----------+--------------------+----------------------+---------+
| Name | Status | Type | Library | License |
+----------------------------+----------+--------------------+----------------------+---------+
| | | | | |
| . . . | . . . | . . . | . . . | . . . |
| | | | | |
| group_replication | ACTIVE | GROUP REPLICATION | group_replication.so | GPL |
+----------------------------+----------+--------------------+----------------------+---------+
45 rows in set (0.00 sec)
group_replication
行确认插件已加载且当前处于活动状态。
既然每个MySQL服务器都配置了复制用户并启用了组复制插件,我们就可以开始启动我们的组了。
要启动该组,请在该组单个成员上完成以下步骤。
组成员依赖现有成员在最初加入组时发送复制数据,最新成员列表和其他信息。因此,我们需要使用稍微不同的过程来启动初始组成员,以便它知道不希望来自其种子列表中的其他成员的此信息。
如果设置group_replication_bootstrap_group
变量告诉成员不用从同一等级的用户上获取信息,而是应该自己添加一个组,把自己作为主要成员。但是这是在没有现有的组成员时情况下是适用的,在这里我们要把这个功能关掉:
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;
应该以此服务器作为唯一成员启动该组。我们可以通过检查数据库中的replication_group_members
表中的performance_schema
条目来验证这一点:
SELECT * FROM performance_schema.replication_group_members;
你应该看到代表当前主机的单行:
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 13324ab7-1b01-11e7-9dd1-22b78adaa992 | 203.0.113.1 | 3306 | ONLINE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
1 row in set (0.00 sec)
ONLINE
是意思是表示正在运行。
接下来,创建一个测试数据库和表来测试我们的复制:
CREATE DATABASE playground;
CREATE TABLE playground.equipment ( id INT NOT NULL AUTO_INCREMENT, type VARCHAR(50), quant INT, color VARCHAR(25), PRIMARY KEY(id));
INSERT INTO playground.equipment (type, quant, color) VALUES ("slide", 2, "blue");
查看内容以确保输入正确:
SELECT * FROM playground.equipment;
+----+-------+-------+-------+
| id | type | quant | color |
+----+-------+-------+-------+
| 1 | slide | 2 | blue |
+----+-------+-------+-------+
1 row in set (0.00 sec)
我们现在已经验证该服务器是该组的成员,并且它具有写入功能。现在其他服务器可以加入该组。
接下来,在第二台服务器上,启动组复制。由于我们已经拥有一个活跃的成员,我们不需要引导该组,只需加入它:
START GROUP_REPLICATION;
在第三台服务器上,以相同的方式启动组复制:
START GROUP_REPLICATION;
再次检查会员列表。你现在应该看到三个服务器:
SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 13324ab7-1b01-11e7-9dd1-22b78adaa992 | 203.0.113.1 | 3306 | ONLINE |
| group_replication_applier | 1ae4b211-1b01-11e7-9d89-ceb93e1d5494 | 203.0.113.2 | 3306 | ONLINE |
| group_replication_applier | 157b597a-1b01-11e7-9d83-566a6de6dfef | 203.0.113.3 | 3306 | ONLINE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
3 rows in set (0.01 sec)
所有成员的MEMBER_STATE
值都应该是ONLINE
。如果任何节点列出RECOVERING
的时间超过一两秒,则通常表示发生了错误或某些配置错误。检查日志/var/log/mysql/error.log
,获取有关出错的其他信息。
检查是否已在新成员上复制测试数据库信息:
SELECT * FROM playground.equipment;
+----+-------+-------+-------+
| id | type | quant | color |
+----+-------+-------+-------+
| 1 | slide | 2 | blue |
+----+-------+-------+-------+
1 row in set (0.01 sec)
如果新成员上的数据可用,则表示组复制正常。
接下来,我们可以尝试从新成员写入数据库。这是否成功取决于你是选择配置单个主要组还是多个主要组。
在单个主要组中,出于一致性原因,应该拒绝来自非主服务器的任何写入操作。你可以使用以下查询随时发现当前主节点:
SHOW STATUS LIKE '%primary%';
+----------------------------------+--------------------------------------+
| Variable_name | Value |
+----------------------------------+--------------------------------------+
| group_replication_primary_member | 13324ab7-1b01-11e7-9dd1-22b78adaa992 |
+----------------------------------+--------------------------------------+
1 row in set (0.01 sec)
查询的值将是MEMBER_ID
,您可以通过查询组成员列表来匹配主机
SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 13324ab7-1b01-11e7-9dd1-22b78adaa992 | 203.0.113.1 | 3306 | ONLINE |
| group_replication_applier | 1ae4b211-1b01-11e7-9d89-ceb93e1d5494 | 203.0.113.2 | 3306 | ONLINE |
| group_replication_applier | 157b597a-1b01-11e7-9d83-566a6de6dfef | 203.0.113.3 | 3306 | ONLINE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
3 rows in set (0.01 sec)
在此示例中,我们可以看到主机 203.0.113.1
当前是主服务器。如果我们尝试从另一个成员写入数据库,操作应该会失败:
INSERT INTO playground.equipment (type, quant, color) VALUES ("swing", 10, "yellow");
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
这是正常的,因为该组当前配置了一个可写入的主要组。如果主服务器出现问题并离开组,则该组将自动选择新成员作为主要成员并接受写入。
对于以多主方向配置的组,任何成员都应该能够提交对数据库的写入。
你可以通过group_replication_primary_member
再次检查变量的值来仔细检查你的组是否在多主模式下运行:
SHOW STATUS LIKE '%primary%';
+----------------------------------+-------+
| Variable_name | Value |
+----------------------------------+-------+
| group_replication_primary_member | |
+----------------------------------+-------+
1 row in set (0.02 sec)
如果变量为空,则表示没有指定的主要主机,并且任何成员都应该能够接受写入。
输入以下命令在第二台服务器上测试:
INSERT INTO playground.equipment (type, quant, color) VALUES ("swing", 10, "yellow");
Query OK, 1 row affected (0.00 sec)
第二个服务器提交了写操作,没有任何错误。在第三台服务器上,查询是否添加了新项:
SELECT * FROM playground.equipment;
+----+-------+-------+--------+
| id | type | quant | color |
+----+-------+-------+--------+
| 1 | slide | 2 | blue |
| 2 | swing | 10 | yellow |
+----+-------+-------+--------+
2 rows in set (0.00 sec)
这确认第二台服务器的写入已成功复制。
现在,通过输入以下内容来测试第三台服务器
INSERT INTO playground.equipment (type, quant, color) VALUES ("seesaw", 3, "green");
Query OK, 1 row affected (0.02 sec)
回到第一台服务器上,进行测试以确保两个新成员的写入操作都被复制回来:
SELECT * FROM playground.equipment;
+----+--------+-------+--------+
| id | type | quant | color |
+----+--------+-------+--------+
| 1 | slide | 2 | blue |
| 2 | swing | 10 | yellow |
| 3 | seesaw | 3 | green |
+----+--------+-------+--------+
3 rows in set (0.01 sec)
这确认了复制在每个方向上都有效,并且每个成员都能够执行写操作。
一旦组被引导,只要有足够的成员选择主服务器,个人成员就可以加入和离开而不影响可用性。但是,如果进行了某些配置更改(如在单主环境和多主环境之间切换),或者该组的所有成员都离开,则可能需要重新引导该组。你的操作方式与最初完成的方式完全相同。
在第一台服务器上,设置group_replciation_bootstrap_group
变量,然后开始初始化组:
SET GLOBAL GROUP_REPLICATION_BOOTSTRAP_GROUP=ON;
START GROUP_REPLICATION;
SET GLOBAL GROUP_REPLICATION_BOOTSTRAP_GROUP=OFF;
一旦第一个成员启动了该组,其他成员就可以加入:
START GROUP_REPLICATION;
为其他成员执行此操作:
START GROUP_REPLICATION;
该小组现在应该在线,所有成员都可以使用:
SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
| group_replication_applier | 13324ab7-1b01-11e7-9dd1-22b78adaa992 | 203.0.113.1 | 3306 | ONLINE |
| group_replication_applier | 1ae4b211-1b01-11e7-9d89-ceb93e1d5494 | 203.0.113.2 | 3306 | ONLINE |
| group_replication_applier | 157b597a-1b01-11e7-9d83-566a6de6dfef | 203.0.113.3 | 3306 | ONLINE |
+---------------------------+--------------------------------------+--------------+-------------+--------------+
3 rows in set (0.01 sec)
必要时,重复过程可用于再次启动组。
使用当前设置,如果成员服务器重新启动,它将不会在启动时自动重新加入该组。如果希望成员自动重新加入组,则可以稍微修改配置文件。
当你希望成员在启动时自动加入时,我们接下来的的设置很有用。但是,你应该注意一些事项:
首先,此设置仅影响MySQL实例本身何时启动。如果由于超时问题而从组中删除该成员,但MySQL实例仍处于联机状态,则该成员将不会自动重新加入。
其次,在第一次引导组时启用此设置可能会出问题。当没有要加入的现有组时,MySQL进程将需要很长时间才能启动,因为它将尝试联系其他不存在的成员进行初始化。只有在很长的超时后才会放弃并正常启动。之后,你将必须使用上面概述的过程来引导组。
考虑到上述注意事项,如果你希望在MySQL启动时配置节点自动加入组,请打开主MySQL配置文件:
sudo nano /etc/mysql/my.cnf
在里面,找到loose-group_replication_start_on_boot
变量,并将其设置为“ON”:
[mysqld]
. . .
loose-group_replication_start_on_boot = ON
. . .
完成后保存并关闭文件。该成员应在下次启动MySQL实例时自动尝试加入该组。
在本教程中,我们介绍了如何在三个Ubuntu服务器之间配置MySQL组复制。对于单个主要设置,成员将在必要时自动选择可写入的主要设备。对于多主组,任何成员都可以执行写入和更新。组复制提供灵活的复制拓扑,允许成员随意加入或离开,同时提供有关数据一致性和消息排序的保证。MySQL组复制的配置可能有点复杂,但它提供了传统复制中无法实现的功能。但是,自建数据库组复制方式运行可能会出问题,如果在生产环境使用,我建议您使用腾讯云云关系型数据库来存储您的数据。云关系型数据库让您在云中轻松部署、管理和扩展的关系型数据库,提供安全可靠、伸缩灵活的按需云数据库服务。腾讯云关系型数据库提供 MySQL、SQL Server、MariaDB、PostgreSQL 数据库引擎,并针对数据库引擎的性能进行了优化。云关系型数据库是一种高度可用的托管服务,提供容灾、备份、恢复、监控、迁移等数据库运维全套解决方案,可将您从耗时的数据库管理任务中解放出来,让您有更多时间专注于您的应用和业务。 更多Linux教程请前往腾讯云+社区学习更多知识。
参考文献:《How To Configure MySQL Group Replication on Ubuntu 16.04》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。