介绍
MySQL 复制可靠地反映了从一个数据库到另一个数据库的数据和操作。 常规复制涉及一个配置为接受数据库写作操作的主要服务器,其次服务器将从主服务器的日志复制并应用到自己的数据集。
团体复制是实施更灵活,更能容错的复制机制的一种方式. 这一过程涉及建立一套服务器,每个服务器都参与确保正确复制数据。 如果主服务器遇到问题,成员选举可以从组中选择一个新的主服务器. 这使得剩余的节点即使在面临问题的情况下也能继续运行. 通过实施[Paxos concensus算法](https://en.wikipedia.org/wiki/Paxos_(computer_science),提供会员谈判、故障检测和消息发送.
在本教程中,我们将使用三组Ubuntu 16.04服务器设置MySQL组复制,配置将涵盖如何操作单一的主要复制组或多主要复制组。
前提条件
要做到这一点,你需要一组三个Ubuntu 16.04服务器,在每个服务器上,你需要设置一个具有)来满足这些要求,并使每个服务器进入准备状态。
在Ubuntu的默认存储库中,MySQL版本不包含我们需要的群组复制插件。幸运的是,MySQL项目为最新的MySQL版本保留了自己的存储库,其中包括这个组件。 遵循我们在Ubuntu 16.04上安装最新MySQL的指南(https://andsky.com/tech/tutorials/how-to-install-the-latest-mysql-on-ubuntu-16-04)在每个服务器上安装一个群组复制功能的MySQL版本。
生成 UUID 以识别 MySQL 组
在打开 MySQL 配置文件以配置组复制设置之前,我们需要生成一个 UUID,我们可以使用它来识别我们将创建的 MySQL 组。
在 mysqlmember1 上,使用uuidgen
命令生成该组的有效 UUID:
1[environment second]
2uuidgen
1[secondary_label Output]
2[environment second]
3959cf631-538c-415d-8164-ca00181be227
复制您接收的值. 我们在为我们的服务器集群配置组名称时必须在某个时刻参考这一点。
在 MySQL 配置文件中设置组复制
现在我们已经准备好修改MySQL的配置文件,在每个MySQL服务器上打开主MySQL配置文件:
1sudo nano /etc/mysql/my.cnf
默认情况下,此文件仅用于源自子目录的额外文件. 我们将不得不添加我们自己的配置 beneath 的 !includedir
行. 这使我们能够轻松地从包含的文件中取代任何设置。
首先,打开一个 MySQL 服务器组件的部分,包括一个[mysqld]
标题。下面,我们将粘贴我们需要组复制的设置。宽松
前缀允许 MySQL 优雅地处理选项,它不会无故意地识别。我们需要在一瞬间填写和定制许多这些设置:
1[label /etc/mysql/my.cnf]
2. . .
3!includedir /etc/mysql/conf.d/
4!includedir /etc/mysql/mysql.conf.d/
5
6[mysqld]
7
8# General replication settings
9gtid_mode = ON
10enforce_gtid_consistency = ON
11master_info_repository = TABLE
12relay_log_info_repository = TABLE
13binlog_checksum = NONE
14log_slave_updates = ON
15log_bin = binlog
16binlog_format = ROW
17transaction_write_set_extraction = XXHASH64
18loose-group_replication_bootstrap_group = OFF
19loose-group_replication_start_on_boot = OFF
20loose-group_replication_ssl_mode = REQUIRED
21loose-group_replication_recovery_use_ssl = 1
22
23# Shared replication group configuration
24loose-group_replication_group_name = ""
25loose-group_replication_ip_whitelist = ""
26loose-group_replication_group_seeds = ""
27
28# Single or Multi-primary mode? Uncomment these two lines
29# for multi-primary mode, where any host can accept writes
30#loose-group_replication_single_primary_mode = OFF
31#loose-group_replication_enforce_update_everywhere_checks = ON
32
33# Host specific replication configuration
34server_id =
35bind-address = ""
36report_host = ""
37loose-group_replication_local_address = ""
我们已经把上面的配置分成四个部分,现在让我们来谈谈它们。
Boilerplate 组复制设置
第一个部分包含不需要修改的组复制所需的一般设置:
1[label /etc/mysql/my.cnf]
2. . .
3# General replication settings
4gtid_mode = ON
5enforce_gtid_consistency = ON
6master_info_repository = TABLE
7relay_log_info_repository = TABLE
8binlog_checksum = NONE
9log_slave_updates = ON
10log_bin = binlog
11binlog_format = ROW
12transaction_write_set_extraction = XXHASH64
13loose-group_replication_bootstrap_group = OFF
14loose-group_replication_start_on_boot = OFF
15loose-group_replication_ssl_mode = REQUIRED
16loose-group_replication_recovery_use_ssl = 1
17. . .
这些设置启用了全球交易ID,配置了组复制所需的二进制日志,并为组配置了SSL。 配置还设置了一些其他项目,有助于恢复和启动。
共享组复制设置
第二部分为该组设置共享设置. 我们必须一次定制此设置,然后在每个节点上使用相同的设置. 这包括该组的UUID、可接受会员的白名单和种子会员,以便与他们联系以获取初始数据。
将loose-group_replication_group_name
设置为您之前使用uuidgen
命令生成的 UUID。
接下来,将loose-group_replication_ip_whitelist
设置为您的MySQL服务器所有IP地址的列表,分为条纹。loose-group_replication_group_seeds
设置应该与白名单几乎相同,但应该附加我们将使用的组复制端口到每个成员的尽头。
1[label /etc/mysql/my.cnf]
2. . .
3# Shared replication group configuration
4loose-group_replication_group_name = "959cf631-538c-415d-8164-ca00181be227"
5loose-group_replication_ip_whitelist = "203.0.113.1,203.0.113.2,203.0.113.3"
6loose-group_replication_group_seeds = ""203.0.113.1:33061,203.0.113.2:33061,203.0.113.3:33061"
7. . .
这个部分应该在每个MySQL服务器上都是一样的,所以一定要仔细复制。
选择单一或多重初级
接下来,您需要决定是否要配置单一主组或多主组。在官方MySQL文档的某些部分中,这种区别也被称为)来处理写作操作。
如果您想配置多元主组,请删除loose-group_replication_single_primary_mode
和loose-group_replication_enforce_update_everywhere_checks
指令,从而创建一个多元主组。
1[label /etc/mysql/my.cnf]
2. . .
3# Single or Multi-primary mode? Uncomment these two lines
4# for multi-primary mode, where any host can accept writes
5#loose-group_replication_single_primary_mode = OFF
6#loose-group_replication_enforce_update_everywhere_checks = ON
7. . .
**这些设置必须在您的每个MySQL服务器上相同。
您可以稍后更改此设置,但不需要重新启动您的 MySQL 组. 要更改到新配置,您需要停止组中的每个 MySQL 实例,以新设置启动每个成员,然后重新启动组复制。
主机特定的配置设置
第四部分包含在每个服务器上不同的设置,包括:
- 服务器ID * 连接的地址 * 向其他会员报告的地址 * 本地复制地址和收听端口
`server_id ' 指令必须设置为独有的编号。 对于第一位成员,只需将此设定为"1"并增加每个新增主机上的数字. 设置当前服务器的 IP 地址的 ):
1[label /etc/mysql/my.cnf]
2. . .
3# Host specific replication configuration
4server_id = 1
5bind-address = "203.0.113.1"
6report_host = "203.0.113.1"
7loose-group_replication_local_address = "203.0.113.1:33061"
在您的每个MySQL服务器上完成此过程。
完成后,双重检查共享复制设置在每个主机上是相同的,并且每个主机的特定设置是自定义的。
重新启动 MySQL 并启用远程访问
我们的 MySQL 配置文件现在包含启动 MySQL 组复制所需的指令. 若要将新设置应用于 MySQL 实例,请使用以下命令在 每个服务器上 重新启动服务:
1sudo systemctl restart mysql
在MySQL配置文件中,我们将服务配置为在默认端口3306上收听外部连接。
我们需要在我们的防火墙中打开这些两个端口的访问,我们可以通过键入:
1sudo ufw allow 33061
2sudo ufw allow 3306
随着访问开放的MySQL端口,我们可以创建一个复制用户并启用组复制插件。
配置复制用户并启用组复制插件
在您的每一个MySQL服务器上,与管理用户登录您的MySQL实例,以启动交互式会话:
1mysql -u root -p
您将被提示使用 MySQL 管理密码,然后将被放入 MySQL 会话中,我们需要做的第一件事就是创建一个复制用户。
由于每个服务器将有自己的复制用户,我们需要在创建过程中关闭二进制日志,否则,一旦复制开始,该组将尝试将复制用户从主要到其他服务器传播,从而与已经存在的复制用户发生冲突。
我们将为复制用户要求SSL,在服务器上授予复制权限,然后扫除权限以实施更改。
1SET SQL_LOG_BIN=0;
2CREATE USER 'repl'@'%' IDENTIFIED BY 'password' REQUIRE SSL;
3GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
4FLUSH PRIVILEGES;
5SET SQL_LOG_BIN=1;
接下来,我们需要设置group_replication_recovery
频道以使用我们的新复制用户和相关密码,然后每个服务器将使用这些身份验证来验证该组。
1CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='password' FOR CHANNEL 'group_replication_recovery';
有了复制用户,我们可以允许组复制插件准备初始化组. 由于我们正在使用最新版本的MySQL,我们可以通过键入启用插件:
1INSTALL PLUGIN group_replication SONAME 'group_replication.so';
通过键入来验证插件是否活跃:
1SHOW PLUGINS;
1[secondary_label Output]
2+----------------------------+----------+--------------------+----------------------+---------+
3| Name | Status | Type | Library | License |
4+----------------------------+----------+--------------------+----------------------+---------+
5| | | | | |
6| . . . | . . . | . . . | . . . | . . . |
7| | | | | |
8| group_replication | ACTIVE | GROUP REPLICATION | group_replication.so | GPL |
9+----------------------------+----------+--------------------+----------------------+---------+
1045 rows in set (0.00 sec)
group_replication
行确认插件已加载并目前处于活动状态。
开始组复制
现在,每个MySQL服务器都配置了复制用户并启用了群组复制插件,我们可以开始建立我们的群组。
Bootstrap 第一节点
若要启动组,请在 组中的单个成员 上完成下列步骤。
组成员依赖现有成员发送复制数据、最新的会员列表和其他信息,当他们最初加入该组. 因此,我们需要使用略有不同的程序来启动最初的组成员,以便该成员知道不要期望其种子列表中的其他成员提供此信息。
如果设置,则group_replication_bootstrap_group
变量告诉会员不应该期望收到同行信息,而是应该建立一个新组,并自行选出主要会员。
1[environment second]
2SET GLOBAL group_replication_bootstrap_group=ON;
3START GROUP_REPLICATION;
4SET GLOBAL group_replication_bootstrap_group=OFF;
我们可以通过在performance_schema
数据库中检查replication_group_members
表中的条目来验证这一点:
1[environment second]
2SELECT * FROM performance_schema.replication_group_members;
您应该看到代表当前主机的单一行:
1[secondary_label Output]
2[environment second]
3+---------------------------+--------------------------------------+--------------+-------------+--------------+
4| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
5+---------------------------+--------------------------------------+--------------+-------------+--------------+
6| group_replication_applier | 13324ab7-1b01-11e7-9dd1-22b78adaa992 | 203.0.113.1 | 3306 | ONLINE |
7+---------------------------+--------------------------------------+--------------+-------------+--------------+
81 row in set (0.00 sec)
ONLINE
值为MEMBER_STATE
表示该节点在组内完全运行。
接下来,创建一个测试数据库和表来测试我们的复制:
1[environment second]
2CREATE DATABASE playground;
3CREATE TABLE playground.equipment ( id INT NOT NULL AUTO_INCREMENT, type VARCHAR(50), quant INT, color VARCHAR(25), PRIMARY KEY(id));
4INSERT INTO playground.equipment (type, quant, color) VALUES ("slide", 2, "blue");
检查内容,以确保它被正确输入:
1[environment second]
2SELECT * FROM playground.equipment;
1[secondary_label Output]
2[environment second]
3+----+-------+-------+-------+
4| id | type | quant | color |
5+----+-------+-------+-------+
6| 1 | slide | 2 | blue |
7+----+-------+-------+-------+
81 row in set (0.00 sec)
现在我们已经验证了该服务器是组的一员,并且它具有写作功能。
启动剩余节点
接下来,在第二个服务器上,开始组复制,因为我们已经有一个活跃的成员,我们不需要启动组,我们可以加入它:
1[environment third]
2START GROUP_REPLICATION;
在第三个服务器上,以相同的方式开始组复制:
1[environment fourth]
2START GROUP_REPLICATION;
再次检查会员名单,您现在应该看到三个服务器:
1[environment third]
2SELECT * FROM performance_schema.replication_group_members;
1[secondary_label Output]
2+---------------------------+--------------------------------------+--------------+-------------+--------------+
3| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
4+---------------------------+--------------------------------------+--------------+-------------+--------------+
5| group_replication_applier | 13324ab7-1b01-11e7-9dd1-22b78adaa992 | 203.0.113.1 | 3306 | ONLINE |
6| group_replication_applier | 1ae4b211-1b01-11e7-9d89-ceb93e1d5494 | 203.0.113.2 | 3306 | ONLINE |
7| group_replication_applier | 157b597a-1b01-11e7-9d83-566a6de6dfef | 203.0.113.3 | 3306 | ONLINE |
8+---------------------------+--------------------------------------+--------------+-------------+--------------+
93 rows in set (0.01 sec)
对于新组,如果任何节点被列为RECOVERING
超过一秒或两秒,这通常是指错误发生或某些错误配置的迹象。
查看测试数据库信息是否在新成员中复制:
1[environment third]
2SELECT * FROM playground.equipment;
1[secondary_label Output]
2[environment third]
3+----+-------+-------+-------+
4| id | type | quant | color |
5+----+-------+-------+-------+
6| 1 | slide | 2 | blue |
7+----+-------+-------+-------+
81 row in set (0.01 sec)
如果新成员的数据可用,则表示组复制工作正确。
测试新组成员的写作能力
接下来,我们可以尝试从我们的新成员写入数据库. 是否成功或不成功,取决于您是否选择配置单个主组或多主组。
在单一主要环境中测试写作
在单个主组中,您应该预计来自非主服务器的任何写作操作将因一致性原因被拒绝,您可以随时使用以下查询发现当前的主组:
1[environment third]
2SHOW STATUS LIKE '%primary%';
1[secondary_label Output]
2[environment third]
3+----------------------------------+--------------------------------------+
4| Variable_name | Value |
5+----------------------------------+--------------------------------------+
6| group_replication_primary_member | 13324ab7-1b01-11e7-9dd1-22b78adaa992 |
7+----------------------------------+--------------------------------------+
81 row in set (0.01 sec)
查询的值将是一个MEMBER_ID
,您可以通过查询组成员列表来匹配一个主机,就像我们以前一样:
1[environment third]
2SELECT * FROM performance_schema.replication_group_members;
1[secondary_label Output]
2+---------------------------+--------------------------------------+--------------+-------------+--------------+
3| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
4+---------------------------+--------------------------------------+--------------+-------------+--------------+
5| group_replication_applier | 13324ab7-1b01-11e7-9dd1-22b78adaa992 | 203.0.113.1 | 3306 | ONLINE |
6| group_replication_applier | 1ae4b211-1b01-11e7-9d89-ceb93e1d5494 | 203.0.113.2 | 3306 | ONLINE |
7| group_replication_applier | 157b597a-1b01-11e7-9d83-566a6de6dfef | 203.0.113.3 | 3306 | ONLINE |
8+---------------------------+--------------------------------------+--------------+-------------+--------------+
93 rows in set (0.01 sec)
在这个示例中,我们可以看到,当前的203.0.113.1
的主机是主要服务器. 如果我们尝试从其他成员写入数据库,我们应该预期操作会失败:
1[environment third]
2INSERT INTO playground.equipment (type, quant, color) VALUES ("swing", 10, "yellow");
1[secondary_label Output]
2[environment third]
3ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
如果主服务器出现问题并离开该组,该组将自动选择一个新成员作为主,并接受写作。
在多元原始环境中测试写作
对于已配置为多主导方向的组,任何会员都应该能够向数据库订购写作。
您可以通过再次检查group_replication_primary_member
变量的值来双重验证您的组是否处于多原始模式:
1[environment third]
2SHOW STATUS LIKE '%primary%';
1[secondary_label Output]
2[environment third]
3+----------------------------------+-------+
4| Variable_name | Value |
5+----------------------------------+-------+
6| group_replication_primary_member | |
7+----------------------------------+-------+
81 row in set (0.02 sec)
如果变量是空的,这意味着没有指定的主要主机,任何成员都应该能够接受写作。
在您的第二个服务器上测试,键入:
1[environment third]
2INSERT INTO playground.equipment (type, quant, color) VALUES ("swing", 10, "yellow");
1[secondary_label Output]
2[environment third]
3Query OK, 1 row affected (0.00 sec)
第二个服务器在没有任何错误的情况下完成了写作操作。
在第三个服务器上,查询以查看新项目已被添加:
1[environment fourth]
2SELECT * FROM playground.equipment;
1[secondary_label Output]
2[environment fourth]
3+----+-------+-------+--------+
4| id | type | quant | color |
5+----+-------+-------+--------+
6| 1 | slide | 2 | blue |
7| 2 | swing | 10 | yellow |
8+----+-------+-------+--------+
92 rows in set (0.00 sec)
这证实了第二个服务器的写作成功复制。
现在,测试在第三个服务器上的写作能力,键入:
1[environment fourth]
2INSERT INTO playground.equipment (type, quant, color) VALUES ("seesaw", 3, "green");
1[secondary_label Output]
2[environment fourth]
3Query OK, 1 row affected (0.02 sec)
回到 第一个服务器 上,测试以确保两个新成员的写作操作被复制回来:
1[environment second]
2SELECT * FROM playground.equipment;
1[secondary_label Output]
2[environment second]
3+----+--------+-------+--------+
4| id | type | quant | color |
5+----+--------+-------+--------+
6| 1 | slide | 2 | blue |
7| 2 | swing | 10 | yellow |
8| 3 | seesaw | 3 | green |
9+----+--------+-------+--------+
103 rows in set (0.01 sec)
这证实复制在每个方向工作,每个成员都能执行写作操作。
带领团体恢复
一旦组被启动,单个成员可以加入和离开,而不会影响可用性,只要有足够的成员选择主服务器. 但是,如果某些配置更改(如单个和多主环境之间切换),或所有组成员离开,您可能需要重新启动组。
在您的第一个服务器上,设置group_replciation_bootstrap_group
变量,然后开始初始化组:
1[environment second]
2SET GLOBAL GROUP_REPLICATION_BOOTSTRAP_GROUP=ON;
3START GROUP_REPLICATION;
4SET GLOBAL GROUP_REPLICATION_BOOTSTRAP_GROUP=OFF;
一旦第一个成员启动了组,其他成员可以加入:
1[environment third]
2START GROUP_REPLICATION;
对于额外的会员,请遵循此过程:
1[environment fourth]
2START GROUP_REPLICATION;
该组现在应该在线,所有成员可用:
1[environment fourth]
2SELECT * FROM performance_schema.replication_group_members;
1[secondary_label Output]
2[environment fourth]
3+---------------------------+--------------------------------------+--------------+-------------+--------------+
4| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
5+---------------------------+--------------------------------------+--------------+-------------+--------------+
6| group_replication_applier | 13324ab7-1b01-11e7-9dd1-22b78adaa992 | 203.0.113.1 | 3306 | ONLINE |
7| group_replication_applier | 1ae4b211-1b01-11e7-9d89-ceb93e1d5494 | 203.0.113.2 | 3306 | ONLINE |
8| group_replication_applier | 157b597a-1b01-11e7-9d83-566a6de6dfef | 203.0.113.3 | 3306 | ONLINE |
9+---------------------------+--------------------------------------+--------------+-------------+--------------+
103 rows in set (0.01 sec)
这个过程可以用来在必要时重新启动组。
MySQL 启动时自动加入组
使用当前设置,如果会员服务器重新启动,则不会在启动时自动重新加入该组. 如果您希望会员自动重新加入该组,则可以稍微修改配置文件。
我们将概述的设置有助于当您希望会员在启动时自动加入时。
首先,此设置仅在启动 MySQL 实例时才会影响。如果会员由于时间错误而被删除,但 MySQL 实例仍然在线,会员将不会自动重新加入。
其次,在第一次启动组时启用此设置可能会有害。当没有现有组加入时,MySQL过程需要很长时间才能启动,因为它会尝试与其他非现有成员联系以初始化。
考虑到上述警告,如果您想要配置节点在 MySQL 启动时自动加入组,请打开主 MySQL 配置文件:
1sudo nano /etc/mysql/my.cnf
在内部,找到loose-group_replication_start_on_boot
变量,并将其设置为ON
:
1[label /etc/mysql/my.cnf]
2
3[mysqld]
4. . .
5loose-group_replication_start_on_boot = ON
6. . .
完成后保存并关闭文件. 会员应在下次启动其 MySQL 实例时自动尝试加入该组。
结论
在本教程中,我们介绍了如何在三个 Ubuntu 16.04 服务器之间配置 MySQL 群组复制。对于单一的主要设置,成员在需要时会自动选择一个可写的主要组。
组复制提供了灵活的复制 topology,允许成员随意加入或离开,同时同时提供数据一致性和消息排序的保证。