- 简介
- 传统复制 async_replication_diggram
传统mysql复制是完全异步化的复制
master事务的提交不需要经过slave的确认,slave是否接收到master的binlog,master并不care。slave接收到master binlog后先写relay log,最后异步地去执行relay log中的sql应用到自身。由于master的提交不需要确保slave relay log是否被正确接受,当slave接受master binlog失败或者relay log应用失败,master无法感知。
假设master发生宕机并且binlog还没来得及被slave接收,而切换程序将slave提升为新的master,就会出现数据不一致的情况!另外,在高并发的情况下,传统的主从复制,从节点可能会与主产生较大的延迟(当然mysql后续版本陆续做了优化,推出了并行复制,以此降低异步复制的延迟)。
基于传统异步存在的缺陷,mysql在5.5版本推出半同步复制。可以说半同步复制是传统异步复制的改进,在master事务的commit之前,必须确保一个slave收到relay log并且响应给master以后,才能进行事务的commit。但是slave对于relay log的应用仍然是异步进行的
因为slave接受relay log之后有可能apply失败。这个时候master其实不知道slave的失败,照常提交了这个事务。并且,半同步复制只确保一个slave能够收到relay log,多slave的场景下,不能保证其他节点正确收到relay log,由此,当发生master切换后,半同步复制一样也会出现数据不一致的情况。
基于传统异步复制和半同步复制的缺陷——数据的一致性问题无法保证,MySQL官方在5.7.17版本正式推出组复制(MySQL Group Replication,简称MGR)
由若干个节点共同组成一个复制组,一个事务的提交,必须经过组内大多数节点(N / 2 + 1)决议并通过,才能得以提交。如上图所示,由3个节点组成一个复制组,Consensus层为一致性协议层,在事务提交过程中,发生组间通讯,由2个节点决议(certify)通过这个事务,事务才能够最终得以提交并响应。
引入组复制,主要是为了解决传统异步复制和半同步复制可能产生数据不一致的问题。组复制依靠分布式一致性协议(Paxos协议的变体),实现了分布式下数据的最终一致性,提供了真正的数据高可用方案(是否真正高可用还有待商榷)。其提供的多写方案,给我们实现多活方案带来了希望。
一个复制组由若干个节点(数据库实例)组成,组内各个节点维护各自的数据副本(Share Nothing),通过一致性协议实现原子消息和全局有序消息,来实现组内实例数据的一致
- 部署案列
- 角色划定
主机名 | IP地址 | MGR角色 |
mgr001 | 192.168.80.232 | seconde |
mgr002 | 192.168.80.231 | seconde |
mgr003 | 192.168.80.230 | primary |
- 创建目录 增加用户
# groupadd mysql
# useradd -g mysql -M mysql
# passwd mysql
# mkdir -p /ops/mysql/{data,logs,temp}
# chown -R mysql:mysql /ops/mysql
- 下载mysql-5.7.23
# cd /home/mysql/software
# wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.20-linux-glibc2.12-x86_64.tar.gz
- 安装mysql-5.7.23
# tar -xvf mysql-5.7.23-linux-glibc2.12-x86_64.tar.gz -C /ops/mysql/
# cd /ops/mysql
# mv mysql-5.7.23-linux-glibc2.12-x86_64 mysql-5.7.23
- 修改配置文件
- 增加mgr001配置文件
# rm -f /etc/my.cnf
# touch /etc/my.cnf
# cat <<EOF > /etc/my.cnf
[client]
port=36806
socket=/ops/mysql/mysql.sock
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
log-bin-trust-function-creators=1
skip-external-locking
#skip-name-resolve
user=mysql
port=36806
basedir=/ops/mysql/mysql-5.7.23
datadir=/ops/mysql/data
tmpdir=/ops/mysql/temp
server_id=1
log_bin=mysql-bin
relay-log=mgr001-relay-bin
binlog_format=row
gtid_mode=on
enforce_gtid_consistency=on
master_info_repository=table
relay_log_info_repository=table
binlog_checksum=none
log_slave_updates=on
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address="192.168.80.232:24901"
loose-group_replication_group_seeds="192.168.80.232:24901,192.168.80.231:24902,192.168.80.230:24903"
loose-group_replication_bootstrap_group=off
socket=/ops/mysql/mysql.sock
log-error=/ops/mysql/logs/mysql_error.log
pid-file=/ops/mysql/mysqld.pid
open_files_limit=10240
back_log=600
max_connections=500
max_connect_errors=6000
wait_timeout=605800
max_allowed_packet=32M
sort_buffer_size=4M
join_buffer_size=4M
thread_cache_size=300
query_cache_type=1
query_cache_size=256M
query_cache_limit=2M
query_cache_min_res_unit=16k
tmp_table_size=256M
max_heap_table_size=256M
key_buffer_size=256M
read_buffer_size=1M
read_rnd_buffer_size=16M
bulk_insert_buffer_size=64M
lower_case_table_names=1
default-storage-engine=INNODB
innodb_buffer_pool_size=2G
innodb_log_buffer_size=32M
innodb_log_file_size=128M
innodb_flush_method=O_DIRECT
long_query_time=2
slow-query-log=on
slow-query-log-file=/ops/mysql/logs/mysql-slow.log
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[mysqldump]
quick
max_allowed_packet=32M
[mysqld_safe]
log-error=/ops/mysql/logs/mysqld.log
pid-file=/ops/mysql/mysqld.pid
EOF
- 增加mgr002配置文件
# rm -f /etc/my.cnf
# touch /etc/my.cnf
# cat <<EOF > /etc/my.cnf
[client]
port=36806
socket=/ops/mysql/mysql.sock
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
log-bin-trust-function-creators=1
skip-external-locking
#skip-name-resolve
user=mysql
port=36806
basedir=/ops/mysql/mysql-5.7.23
datadir=/ops/mysql/data
tmpdir=/ops/mysql/temp
server_id=2
log_bin=mysql-bin
relay-log=mgr001-relay-bin
binlog_format=row
gtid_mode=on
enforce_gtid_consistency=on
master_info_repository=table
relay_log_info_repository=table
binlog_checksum=none
log_slave_updates=on
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address="192.168.80.231:24902"
loose-group_replication_group_seeds="192.168.80.232:24901,192.168.80.231:24902,192.168.80.230:24903"
loose-group_replication_bootstrap_group=off
socket=/ops/mysql/mysql.sock
log-error=/ops/mysql/logs/mysql_error.log
pid-file=/ops/mysql/mysqld.pid
open_files_limit=10240
back_log=600
max_connections=500
max_connect_errors=6000
wait_timeout=605800
max_allowed_packet=32M
sort_buffer_size=4M
join_buffer_size=4M
thread_cache_size=300
query_cache_type=1
query_cache_size=256M
query_cache_limit=2M
query_cache_min_res_unit=16k
tmp_table_size=256M
max_heap_table_size=256M
key_buffer_size=256M
read_buffer_size=1M
read_rnd_buffer_size=16M
bulk_insert_buffer_size=64M
lower_case_table_names=1
default-storage-engine=INNODB
innodb_buffer_pool_size=2G
innodb_log_buffer_size=32M
innodb_log_file_size=128M
innodb_flush_method=O_DIRECT
long_query_time=2
slow-query-log=on
slow-query-log-file=/ops/mysql/logs/mysql-slow.log
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[mysqldump]
quick
max_allowed_packet=32M
[mysqld_safe]
log-error=/ops/mysql/logs/mysqld.log
pid-file=/ops/mysql/mysqld.pid
EOF
- 增加mgr003配置文件
# rm -f /etc/my.cnf
# touch /etc/my.cnf
# cat <<EOF > /etc/my.cnf
[client]
port=36806
socket=/ops/mysql/mysql.sock
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
log-bin-trust-function-creators=1
skip-external-locking
#skip-name-resolve
user=mysql
port=36806
basedir=/ops/mysql/mysql-5.7.23
datadir=/ops/mysql/data
tmpdir=/ops/mysql/temp
server_id=3
log_bin=mysql-bin
relay-log=mgr001-relay-bin
binlog_format=row
gtid_mode=on
enforce_gtid_consistency=on
master_info_repository=table
relay_log_info_repository=table
binlog_checksum=none
log_slave_updates=on
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address="192.168.80.230:24903"
loose-group_replication_group_seeds="192.168.80.232:24901,192.168.80.231:24902,192.168.80.230:24903"
loose-group_replication_bootstrap_group=off
socket=/ops/mysql/mysql.sock
log-error=/ops/mysql/logs/mysql_error.log
pid-file=/ops/mysql/mysqld.pid
open_files_limit=10240
back_log=600
max_connections=500
max_connect_errors=6000
wait_timeout=605800
max_allowed_packet=32M
sort_buffer_size=4M
join_buffer_size=4M
thread_cache_size=300
query_cache_type=1
query_cache_size=256M
query_cache_limit=2M
query_cache_min_res_unit=16k
tmp_table_size=256M
max_heap_table_size=256M
key_buffer_size=256M
read_buffer_size=1M
read_rnd_buffer_size=16M
bulk_insert_buffer_size=64M
lower_case_table_names=1
default-storage-engine=INNODB
innodb_buffer_pool_size=2G
innodb_log_buffer_size=32M
innodb_log_file_size=128M
innodb_flush_method=O_DIRECT
long_query_time=2
slow-query-log=on
slow-query-log-file=/ops/mysql/logs/mysql-slow.log
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[mysqldump]
quick
max_allowed_packet=32M
[mysqld_safe]
log-error=/ops/mysql/logs/mysqld.log
pid-file=/ops/mysql/mysqld.pid
EOF
- 解释
server_id 每个实例都必须不一样,范围1-255
loose-group_replication_group_name 为mgr高可用组起一个名字,这个名字一定要是uuid格式的,但是不能与UUID重复
loose-group_replication_local_address 成员的本地地址,不同节点此处要修改为相应的IP地址,此处的port是mgr各实例间进行通信的,非实例端口,按照官网的例子如此24901,24902,24903顺序填写即可
loose-group_replication_group_seeds 成员地址格式如loose-group_replication_local_address,多个用逗号分隔
loose-group_replication_start_on_boot =OFF 避免每次启动自动引导具有相同名称的第二个组
loose-group_replication_bootstrap_group =OFF 避免每次启动自动引导具有相同名称的第二个组
loose-group_replication_single_primary_mode =FALSE 多主模式需要设置成false,默认是true
loose-group_replication_enforce_update_everywhere_checks =ON 避免未检测到的外键冲突
- mysql服务配置
# scp -P 56422 /usr/lib/systemd/system/mysqld.service mysql@mgr002:/ops/
# scp -P 56422 /usr/lib/systemd/system/mysqld.service mysql@mgr003:/ops/
# cat <<EOF > /usr/lib/sysytemd/system/mysqld.service
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Service]
User=mysql
Group=mysql
ExecStart=/ops/mysql/mysql-5.7.23/bin/mysqld_safe --defaults-file=/etc/my.cnf
#LimitNOFILE = 5000
#Restart=on-failure
#RestartPreventExitStatus=1
[Install]
WantedBy=multi-user.target
EOF
- 初始化mysql-5.7.23数据库
# ln -s /ops/mysql/mysql-5.7.23/bin/* /usr/local/bin
# ln -s /ops/mysql/mysql-5.7.23/lib/* /usr/lib/
# ln -s /ops/mysql/mysql-5.7.23/include/mysql/* /usr/include
# mysqld_safe --defaults-file=/etc/my.cnf --datadir=/ops/mysql/data --user=mysql --initialize-insecure
- 启动数据库 开机自启
# systemctl start mysqld
# systemctl enable mysqld
- 设置数据库密码 mgr001 mgr002 mgr003
所有节点上设置root密码时的sql一定要设置不能写进二进制日志里面,否则同步会报错
# mysqladmin -uroot
mysql> set sql_log_bin=0;
mysql> update mysql.user set authentication_string=password('Q!anda0') where user='root' and Host='localhost';
- 初始化第一个节点
- 创建用于复制的用户
mysql> set sql_log_bin=0;
mysql> create user mgruser@'%' identified by 'Q!anda0';
mysql> grant replication slave,replication client on *.* to mgruser@'%';
mysql> grant replication slave,replication client on *.* to mgruser@'127.0.0.1' identified by 'Q!anda0';
mysql> grant replication slave,replication client on *.* to mgruser@'localhost' identified by 'Q!anda0';
mysql> flush privileges;
mysql> set sql_log_bin=1;
- 配置复制所使用的用户
mysql> change master to master_user='mgruser',master_password='Q!anda0' for channel 'group_replication_recovery';
- 安装mysql group replication 插件
mysql> install plugin group_replication soname 'group_replication.so';
- 初始化一个复制组
mysql> set global group_replication_bootstrap_group=on;
mysql> start group_replication;
mysql> set global group_replication_bootstrap_group=off;
- 配置mgr的其它结点
mysql> set sql_log_bin=0;
mysql> create user mgruser@'%' identified by 'Q!anda0';
mysql> grant replication slave,replication client on *.* to mgruser@'%';
mysql> grant replication slave,replication client on *.* to mgruser@'127.0.0.1' identified by 'Q!anda0';
mysql> grant replication slave,replication client on *.* to mgruser@'localhost' identified by 'Q!anda0';
mysql> flush privileges;
mysql> set sql_log_bin=1;
mysql> change master to master_user='mgruser',master_password='Q!anda0' for channel 'group_replication_recovery';
mysql> install plugin group_replication soname 'group_replication.so';
mysql> start group_replication;
- 验证mgr各个结点是否正常
3个结点的状态都是online 说明它们是正常的、进一步说明mgr的安装成功了
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 185807d7-0fe6-11e9-8470-0050569b577d | mgr003 | 36806 | ONLINE |
| group_replication_applier | 27d6eb2a-0fe3-11e9-91e9-0050569b04e1 | mgr001 | 36806 | ONLINE |
| group_replication_applier | 2e5ad763-0fe3-11e9-a2c1-0050569b188e | mgr002 | 36806 | ONLINE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.00 sec)