如何在Ubuntu上配置MySQL组复制

介绍

传统MySQL复制备份架构是将数据从一个数据库同步到另一个数据库。主要操作是将主数据库的数据复制到辅助服务器,当主服务器数据出问题时,自动同步辅助服务器的数据到主服务器,以便恢复数据。但是这种架构有不少缺点,比如数据不够安全,同步可能会丢失等问题,可能会影响主服务器性能。

组复制是MySQL服务器插件,通过这种插件可以实现弹性、高可用、容错复制拓扑结构。 组复制是一种实现更灵活,容错的复制机制的方法。此过程涉及建立一个服务器池,每个服务器都参与确保正确复制数据。如果主服务器遇到问题,成员选举可以从组中选择新的主服务器。这允许其余节点继续运行,即使面对问题。通过实施Paxos一致性算法提供成员协商,故障检测和消息传递。

在本教程中,我们将使用三个Ubuntu服务器设置MySQL组复制。该配置将介绍如何操作单个主要或多主要复制组。

准备

  1. 三台已经设置好可以使用sudo命令的非root账号的Ubuntu服务器,并且已开启防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后在购买服务器
  2. 在三台服务器上安装Mysql,Ubuntu默认存储库中的MySQL版本不包括我们需要的组复制插件。值得庆幸的是,MySQL项目为包含此组件的最新MySQL版本维护了自己的存储库。按照这个在Ubuntu 16.04上安装最新的MySQL教程,这样就可以在每台服务器上安装支持组复制的MySQL版本。

生成UUID以识别MySQL组

在打开MySQL配置文件以配置组复制设置之前,我们需要生成一个UUID,我们可以使用它来识别我们将要创建的MySQL组。

在第一台服务器上,使用uuidgen命令为组生成有效的UUID:

uuidgen
959cf631-538c-415d-8164-ca00181be227

复制输出的值,后面的步骤会用到它。

在MySQL配置文件中设置组复制

现在我们准备修改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 = ""

我们将上面的配置分为四个部分。

Boilerplate组复制设置

第一部分包含不需要修改的组复制所需的常规设置:

. . .
# 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_modeloose-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。要切换到新配置,你必须停止每个MySQL实例,使用新设置启动每个成员,然后重新引导组复制。这不会影响你的任何数据,但需要一小段停机时间。

特定于主机的配置设置

第四部分包含每个服务器上不同的设置,包括:

  • 服务器ID
  • 要绑定的地址
  • 要向其他成员报告的地址
  • 本地复制地址和侦听端口

必须将server_id指令设置为唯一编号。 第一个成员是1,后面的每个成员逐渐+1。 将bind-addressreport_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组复制所需的指令。要设置新的应用于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启动时配置节点自动加入组,请打开主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》

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏cs

知识点找回2.0

Servlet(server Applet),全称Java Servlet, 是用java编写的服务器端程序。而这些Servlet都要实现Servlet的这个借...

9310
来自专栏Jackson0714

【T-SQL性能优化】01.TempDB的使用和性能问题

383130
来自专栏性能与架构

MySql 查看Query Cache的状态

query cache 是mysql性能优化时的重要指标,通过查看query cache的状态信息,就可以知道例如 缓存是否有碎片、命中缓存的数量、没用到缓存的...

37870
来自专栏杨建荣的学习笔记

MySQL中批量初始化数据的对比测试(r12笔记第71天)

一直以来对于MySQL的存储过程性能还是颇有微词的,说实话够慢的。有时候想做一些对比测试,存储过程初始化几万条数据都得好一会儿,这功夫Oracle类似的测试...

34070
来自专栏Java帮帮-微信公众号-技术文章全总结

Sharding-JDBC—分库分表实例【面试+工作】

Sharding-JDBC是一个开源的适用于微服务的分布式数据访问基础类库,它始终以云原生的基础开发套件为目标。

53320
来自专栏云计算

如何在Debian 7上安装MySQL

MySQL是一种流行的数据库管理系统,用于Web和服务器应用程序。本指南将介绍如何在Debian 7(Wheezy)的Linode上安装,配置和管理MySQL。

13730
来自专栏芋道源码1024

数据库中间件 MyCAT源码分析 —— XA分布式事务

---- 1. 概述 2. XA 概念 3. MyCAT 代码实现 3.1 JDBC Demo 代码 3.2 MyCAT 开启 XA 事务 3.3 MyCAT...

45490
来自专栏做全栈攻城狮

C#(Net)软件开发常用工具汇总,提高你的开发效率

作为C#语言官方的开发工具,VS的强大只有在多种语言开发工具使用之后,你才会明白VS的强大之处。可谓神器。其中,开发工具尽量选择版本高的。数据库尽量选择版本低的...

20920
来自专栏重庆的技术分享区

如何在Debian 8上安装MySQL

MySQL是一种流行的数据库管理系统,用于Web和服务器应用程序。本指南将介绍如何在运行Debian 8(Jessie)的Linode上安装,配置和管理MySQ...

96920
来自专栏Jackson0714

【T-SQL性能优化】01.TempDB的使用和性能问题

21020

扫码关注云+社区

领取腾讯云代金券