传统主从的缺陷
传统主从模式,主节点负责写日志,从节点照着日志,执行完全相同的操作,从而实现数据同步。
缺点:极端情况下,在主节点坏掉的瞬时,日志没发送到从节点,导致出现少量的差异。
优点:主节点不需要关注从节点的状态,更新数据的效率最高。
尽管存在缺点,但是有些系统,容忍这种问题的存在:像是办公、调度、报表系统,如果出现问题,可以通过人工干预的手段,事后进行数据恢复。
双主模式的缺陷
原理还是主从复制(master-slave),是比较另类的用法,主节点和从节点,都可以进行读写,互相同步对方的数据;
因为原理也是主从复制,所以自然也有主从的缺陷,除此之外,是双写带来的事务冲突问题,两个节点很凑巧的改到同一条数据。
总之就是别用,一旦出现问题,一般就是大问题,数据出现差异之后,如果不产生事务冲突,短期内都不会影响使用,要等很久之后才会发现问题。
组复制
已经知道了主从的问题,那么,假设一个事务,需要等从库收到数据,才能最终提交,是不是就能解决这个问题?
是的,这就引出了“组复制”,它做到了这一点。
MGR(Mysql Group Replication)是 5.7 版本新加的特性,是一个 MySQL 插件(使用的时候需要额外安装)。
(主从复制和组复制,中间有个过渡产品:半同步复制,有兴趣可以自己研究一下。)
my.cnf
[mysqld]
# 软件路径
basedir=D:/soft/mysql/
# 数据路径,log/pid/sock 等文件默认都会放到这个路径
datadir=D:/soft/mysql/data/
# socket文件
#socket=D:/soft/mysql/data/mysql.sock
# 错误日志
#log-error=D:/soft/mysql/data/error.log
# pid文件
#pid-file=D:/soft/mysql/data/mysql.pid
# 文件软连接,允许 datadir 指定的目录,软连接到其它磁盘(类似于超链接)
#symbolic-links=1
# 服务 id:做集群的时候,需要保证唯一
server-id = 1
# 最大连接数
#max-connections=1000
# 解决高版本产生 1055 异常报错的问题
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
# binlog 日志的存储路径和文件名,一般只要写文件名,默认会放到 datadir 下
# log-bin=D:/soft/mysql/data/binlog
# 集群同步时忽略的数据库
# binlog-ignore-db=mysql
# 是否只读,1 代表只读, 0 代表读写
# read-only=0
# 监听的ip地址
# port = 3306
# 监听端口
# bind-address = 0.0.0.0
# 开启 GTID
gtid_mode=ON
# 强制 GTID 一致性
enforce_gtid_consistency=ON
# 将 master.info 文件的内容,存储到 mysql.slave_master_info 表,内容包含主备复制的位置信息
master_info_repository=TABLE
# 将 relay-log.info 文件的内容,存储到 mysql.slave_relay_log_info 表,内容包含主备复制的位置信息
relay_log_info_repository=TABLE
# 从主库获取的数据,也写到 binlog 文件中,既是主又是从,的时候开启
log_slave_updates=ON
# 使用基于行的格式
binlog_format=ROW
# 禁用二进制日志校验
binlog_checksum=NONE
# WriteSet 是一种复制方式,这个参数用于指定哈希算法,可选值:OFF、MURMUR32、XXHASH64,默认值 XXHASH64
transaction_write_set_extraction=XXHASH64
# 组的名字可以随便起,但不能用主机的GTID! 所有节点的这个组名必须保持一致
loose-group_replication_group_name="5db40c3c-180c-11e9-afbf-005056ac6820"
# server 启动的时候,不自动启动组复制
loose-group_replication_start_on_boot=off
# 为了避免每次启动自动引导具有相同名称的第二个组,所以设置为OFF。
loose-group_replication_bootstrap_group=off
# 关闭单主模式的参数
loose-group_replication_single_primary_mode=off
# 开启多主模式的参数
loose-group_replication_enforce_update_everywhere_checks=on
# 插件使用的IP地址,用于接受来自其它成员的连接
loose-group_replication_local_address= "192.168.1.200:24901"
# 允许加入组复制的客户机来源的ip白名单
loose-group_replication_ip_whitelist="192.168.1.0/24,127.0.0.1/8"
# 组成员
loose-group_replication_group_seeds= "192.168.1.200:24901,192.168.1.210:24901,192.168.1.201:24901"
[mysql]
# prompt命令可以在mysql提示符中显示当前用户、数据库、时间等信息
#mysql -uroot -p --prompt="\\u@\\h:\\d \\r:\\m:\\s>"
同步账号
专门构建一个账号,用于同步数据,注意前后两行,不能省略,否则会影响到后续安装
-- 不记录二进制日志,必须使用这个命令,想通过 reset master 清除日志,是没效果的
set sql_log_bin=0;
-- 建立账号(mysql8)
create user 'slave' identified with mysql_native_password by 'slave1122..';
-- 建立账号(mysql5)
create user 'slave' identified by 'slave1122..';
-- 授权
grant replication slave,replication client on *.* to 'slave';
-- 重置日志
reset master;
-- 刷新
flush privileges;
-- 记录二进制日志
set sql_log_bin=1;
安装插件
开启组复制,需要安装新的插件 group_replication.so,插件的位置在 /lib/plugin 目录,可以先提前检查一下文件是否完整
-- 登录账号之后,执行命令即可完成安装
install plugin group_replication soname 'group_replication.so';
-- 查看已安装的插件
show plugins;
-- 设置主机的账号、密码
change master to master_user='slave', master_password='slave1122..' for channel 'group_replication_recovery';
主机设置
第一台机子启用组复制,需要前后两行命令。
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;
需要注意的是 START GROUP_REPLICATION 之前的数据,也会被其它机子同步;
比如:你需要初始化一些数据,不论你在 START GROUP_REPLICATION 步骤之前初始化,还是在之后初始化,数据都会被其它机子同步,最终的结果都是一样的;
因此,这会导致一个问题,你给每一台机子都初始化了数据,然后才开启组复制,因为会互相同步对方的数据,最后反而出现了问题。
从机设置
其它机子启用组复制
START GROUP_REPLICATION;
停用组复制
如果组复制发生故障,需要手动调整数据,则需要下列命令
-- 停用组复制,所有主机都执行
STOP GROUP_REPLICATION;
-- 清理 binlog 文件
RESET MASTER;
RESET SLAVE ALL;
重启机子
更复杂的设计,重启的方式也变得更加复杂。
服务重启之后,重新加入组复制,需要手动执行命令
-- 这一步需要手动执行,数据会自动更新到最新
START GROUP_REPLICATION;
相关重启报错
-- 报错1
-- 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;
mysql> start group_replication;
-- 报错2
-- Plugin group_replication reported: ‘The member contains transactions not present in the group. The member will now exit the group.’
-- Plugin group_replication reported: ‘To force this member into the group you can use the group_replication_allow_local_disjoint_gtids_join option’
-- 根据报错提示,则设置这个参数
mysql> set global group_replication_allow_local_disjoint_gtids_join=ON;
mysql> start group_replication;
-- 报错3
-- 如果节点存在未提交的事务(数据存在差异),会显示该节点状态是:recovering,这就是最麻烦的情况了,需要根据实际情况,想办法手动同步数据;
-- 首次开启组复制,也很容易报 recovering,一般是因为创建账号步骤中,没有执行 set sql_log_bin=0。