MySQL主从搭建与维护

1、环境准备

操作系统版本及内核版本:
CentOS release 6.8 (Final)
2.6.32-642.el6.x86_64

[root@localhost tmp]# cat /etc/redhat-release
CentOS release 6.8 (Final)

[root@localhost tmp]# uname -r
2.6.32-642.el6.x86_64

数据库版本:
mysql-5.6.38-linux-glibc2.12-x86_64

主机及IP分配:

ip用户名状态
10.1.1.98mysql01Master
10.1.1.197mysql02Slave

基本环境配置:

要保证防火墙对3306端口的开启,如果只是为了学习数据库的主从配置,

以使用service iptables stop 命令直接关闭防火墙。 还有关闭selinux,使用如下命令关闭,

setenforce 0

[root@localhost tmp]# service iptables stop
[root@localhost tmp]# setenforce 0
setenforce: SELinux is disabled

建立双击互信:

Slave上执行
ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ''
ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.1.1.197

Master上执行

ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ''
ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.1.1.98
这个不是必要,但是为了方便管理主从的两台机器,所以建立了互信关系

编辑两台主机的/etc/hosts,添加如下内容

vim /etc/hosts

10.1.1.98   mysql01
10.1.1.197  mysql02


然后可以在两台机子之间进行 ping操作,确保两台机器之间能够相通

2、安装数据库

首先先卸载系统自带的MySQL

rpm -qa| grep mysql 查看相关的安装包

使用rpm -e 进行卸载,卸载时可能会有依赖 加–nodeps进行卸载

rpm -e mysql-5.1.73-7.el6.x86_64  mysql-server-5.1.73-7.el6.x86_64 mysql-libs-5.1.73-7.el6.x86_64  qt-mysql-4.6.2-28.el6_5.x86_64  --nodeps

删除mysql的相关文件

find  / -name mysql  查找目录并删除

删除 my.cnf

rm -rf /etc/my.cnf

再次查找机器是否安装mysql

rpm -qa|grep -i mysql

无结果,说明已经卸载彻底

数据库的安装
这里采用二进制的安装方式
1.上传软件到tmp目录下

[root@CentOS tmp]# ls -lrt
total 307748
-rw-r--r-- 1 root root    529744 Aug  4 05:08 mysql_all_backup.sql
-rw-r--r-- 1 root root       900 Aug  4 15:33 my.cnf
-rw-r--r-- 1 root root 314592758 Aug  9  2017 mysql-5.6.38-linux-glibc2.12-x86_64.tar.gz

2.解压文件到/usr/local下

tar -zvxf  mysql-5.6.38-linux-glibc2.12-x86_64.tar.gz  -C /usr/local

ln -sv /usr/local/mysql-5.6.38-linux-glibc2.12-x86_64  /usr/local/mysql


产生如下的软链接效果
[root@localhost tmp]# ls -lrt /usr/local/mysql
lrwxrwxrwx. 1 mysql mysql 36 Dec  6 14:02 /usr/local/mysql -> mysql-5.6.38-linux-glibc2.12-x86_64/

3.创建mysql用户和用户组

groupadd mysql;

useradd -s /sbin/nologin -M -g  mysql  mysql

4.设置权限

cd /usr/local

chown -R mysql:mysql mysql/

5.初始化数据库

 cd /usr/local/mysql/scripts/
 
  ./mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data

6.拷贝启动文件

cp support-files/mysql.server /etc/init.d/mysqld

7.拷贝并修改my.cnf配置文件

[root@localhost mysql]# vi /etc/my.cnf  
[client]   
port  = 3306  
default-character-set=utf8  
  
[mysqld]  
datadir = /usr/local/mysql/data  
port            = 3306  
character_set_server=utf8  
character_set_client=utf8  
collation-server=utf8_general_ci  
lower_case_table_names=1  
max_connections=1000  
  
[mysql]  
default-character-set=utf8 

8.添加开机自启动并启动测试MySQL

chkconfig --add mysqld
chkconfig mysqld on


[root@localhost init.d]# service mysqld status  
MySQL running (2068)                                       [ok] 

9.添加环境变量

vi /etc/profile

export PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH
source /etc/profile

10.执行MySQL安全配置向导mysql_secure_installation

[root@localhost ~]# mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MySQL to secure it, we'll need the current
password for the root user. If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):<–初次运行直接回车
OK, successfully used password, moving on…
Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.
Set root password? [Y/n] <– 是否设置root用户密码,输入y并回车或直接回车
New password: <– 设置root用户的密码
Re-enter new password: <– 再输入一次你设置的密码
Password updated successfully!
Reloading privilege tables..
… Success!
By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] <– 是否删除匿名用户,生产环境建议删除,所以直接回车
… Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] <–是否禁止root远程登录,根据自己的需求选择Y/n并回车,建议禁止
… Success!
By default, MySQL comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] <– 是否删除test数据库,直接回车
- Dropping test database…
… Success!
- Removing privileges on test database…
… Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] <– 是否重新加载权限表,直接回车
… Success!
Cleaning up…
All done! If you've completed all of the above steps, your MySQL
installation should now be secure.
Thanks for using MySQL!
[root@localhost ~]#

11、测试登陆MySQL

[root@localhost tmp]# mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 25
Server version: 5.6.38-log MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

至此MySQL安装完成

3、主从复制介绍

MySQL数据复制的原理图大致如下:
在这里插入图片描述

从上图我们可以看出MySQL数据库的复制需要启动三个线程来实现:

  • 其中1个在主服务器上,另两个在从服务器上。当发出START SLAVE时,从服务器创建一个I/O线程,以连接主服务器并让它发送记录在其二进制日志中的语句。主服务器创建一个线程将二进制日志中的内容发送到从服务器。该线程可以识别为主服务器上SHOW PROCESSLIST的输出中的Binlog Dump线程。从服务器I/O线程读取主服务器Binlog Dump线程发送的内容并将该数据拷贝到从服务器数据目录中的本地文件中,即中继日志。第3个线程是SQL线程,是从服务器创建用于读取中继日志并执行日志中包含的更新。

  • 在前面的描述中,每个从服务器有2个线程。有多个从服务器的主服务器创建为每个当前连接的从服务器创建一个线程;每个从服务器有自己的I/O和SQL线程。

  • 这样读取和执行语句被分成两个独立的任务。如果语句执行较慢则语句读取任务没有慢下来。例如,如果从服务器有一段时间没有运行了,当从服务器启动时,其I/O线程可以很快地从主服务器索取所有二进制日志内容,即使SQL线程远远滞后。如果从服务器在SQL线程执行完所有索取的语句前停止,I/O 线程至少已经索取了所有内容,以便语句的安全拷贝保存到本地从服务器的中继日志中,供从服务器下次启动时执行。这样允许清空主服务器上的二进制日志,因为不再需要等候从服务器来索取其内容。

一个从库只能属于一个主服务器

MySQL主从复制模式主要有三种模式:

  • 1.异步复制
    通常没说明指的都是异步,即主库执行完Commit后,在主库写入Binlog日志后即可成功返回客户端,无需等等Binlog日志传送给从库,一旦主库宕机,有可能会丢失日志。

  • 2.半同步复制
    而半同步复制,是等待其中一个从库也接收到Binlog事务并成功写入Relay Log之后,才返回Commit操作成功给客户端;如此半同步就保证了事务成功提交后至少有两份日志记录,一份在主库Binlog上,另一份在从库的Relay Log上,从而进一步保证数据完整性;半同步复制很大程度取决于主从网络RTT(往返时延),以插件 semisync_master/semisync_slave 形式存在。

  • 3.基于GTID的主从复制
    从服务器连接到主服务器之后,把自己执行过的GTID(Executed_Gtid_Set)<SQL线程> 、获取到的GTID(Retrieved_Gtid_Set)<IO线程>发给主服务器,主服务器把从服务器缺少的GTID及对应的transactions发过去补全即可。当主服务器挂掉的时候,找出同步最成功的那台从服务器,直接把它提升为主即可。如果硬要指定某一台不是最新的从服务器提升为主, 先change到同步最成功的那台从服务器, 等把GTID全部补全了,就可以把它提升为主了。

4、配置异步主从复制

按照前面的安装步骤,已有两个全新的数据库实例,并且无应用数据。

1、主服务器上进行的操作

配置my.cnf 把binlog打开,并设置二进制日志模式为row模式,并设置唯一的server-id

vim /etc/my.cnf
log-bin = master-bin
log-bin-index= master-bin.index
server-id=98

my.cnf的配置内容为

[root@localhost tmp]# cat /etc/my.cnf
[client]
port        = 3306
default-character-set  = utf8
socket      = /tmp/mysql.sock

[mysqld]
character-set-server   = utf8 
collation-server       = utf8_general_ci 
port                   = 3306
socket                 = /tmp/mysql.sock
basedir                = /usr/local/mysql
datadir                = /usr/local/mysql/data
skip-external-locking
key_buffer_size    = 16M  索引的缓存大小
max_allowed_packet = 1M 	通讯中允许单个最大的包
table_open_cache   = 1024   打开表的数量
sort_buffer_size   = 512K   排序缓存大小
net_buffer_length  = 8K  网络链接缓存大小
read_buffer_size   = 256K  读取缓存大小
read_rnd_buffer_size    = 512K   
myisam_sort_buffer_size = 8M  

log-bin=master-bin  #开启binlog日志
log-bin-index= master-bin.index
binlog_format=row  #设置binlog的格式为行级模式
server-id  =  98   #设置server-id
skip_slave_start=1  #设置slave进程不随mysql启动而启动

lower_case_table_names=1
innodb_file_per_table=1

[mysqldump]
quick
max_allowed_packet = 16M 备份的最大包的大小

[mysql]
no-auto-rehash

[myisamchk]
key_buffer_size = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout
2、重启mysql
/etc/init.d/mysqld restart

授权给从数据库服务器10.1.1.197

mysql> GRANT REPLICATION SLAVE ON *.* to 'repl'@'10.1.1.%' identified by ‘repl’;

查询数据库状态

mysql> show master status;
+-------------------+----------+--------------+------------------+------------------------------------------+
| File        | Position   | Binlog_Do_DB | Binlog_Ignore_DB                |
+-------------------+----------+--------------+------------------+------------------------------------------+
| master-bin.000003 |      711 |             |                          | 
+-------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)

记录下 FILE 及 Position 的值,在后面进行从服务器操作的时候需要用到.

3、从服务器上进行的操作

配置my.cnf 把relay-log打开,并设置二进制日志模式为row模式,并设置唯一的server-id
启用中继日志

relay-log = relay-log
relay-log-index = relay-log.index
server-id = 197

my.cnf的配置如下

[root@mysql02 ~]# cat /etc/my.cnf
[client]
port        = 3306
default-character-set  = utf8
socket      = /tmp/mysql.sock

[mysqld]
character-set-server   = utf8 
collation-server       = utf8_general_ci 
port                   = 3306
socket                 = /tmp/mysql.sock
basedir                = /usr/local/mysql
datadir                = /usr/local/mysql/data
skip-external-locking
key_buffer_size    = 16M
max_allowed_packet = 1M
table_open_cache   = 64
sort_buffer_size   = 512K
net_buffer_length  = 8K
read_buffer_size   = 256K
read_rnd_buffer_size    = 512K
myisam_sort_buffer_size = 8M

relay-log = relay-log           #开启中继日志
relay-log-index = relay-log.index
log-bin=slave-bin             #将二进制打开
log-bin-index=slave-bin.index  
log_slave_updates=1     #将中继日志执行的时候,将二进制日志记录到本地的二进制日志
binlog_format=row           #设置binlog的模式
server-id   = 197
skip_slave_start=1            #设置slave进程不随mysql启动而启动

lower_case_table_names=1
innodb_file_per_table=1

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash

[myisamchk]
key_buffer_size = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout
4、重启mysql
/etc/init.d/mysqld restart

连接至主服务器,并开始复制

 mysql>CHANGE MASTER TO MASTER_HOST='10.1.1.98',MASTER_PORT=3306,MASTER_LOG_FILE='master-bin.000003',MASTER_LOG_POS='711',MASTER_USER='repl',MASTER_PASSWORD='repl';
mysql> START SLAVE;
mysql>show slave status\G
mysql> show slave status\G
==============================================
**************** 1. row *******************
Slave_IO_State:
Master_Host: 10.1.1.98
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 415
Relay_Log_File: localhost-relay-bin.000008
Relay_Log_Pos: 561
Relay_Master_Log_File: mysql-bin.000005
Slave_IO_Running: YES
Slave_SQL_Running: YES
Replicate_Do_DB:
……………省略若干……………
Master_Server_Id: 1

1 row in set (0.01 sec)
==============================================

其中Slave_IO_Running 与 Slave_SQL_Running 的值都必须为YES,才表明状态正常。

如果主服务器已经存在应用数据,则在进行主从复制时,需要做以下处理:
(1)主数据库进行锁表操作,不让数据再进行写入动作

mysql> FLUSH TABLES WITH READ LOCK;

(2)查看主数据库状态

mysql> show master status;

(3)记录下 FILE 及 Position 的值。
将主服务器的数据文件(整个/usr/local/mysql/data目录)复制到从服务器,建议通过tar归档压缩后再传到从服务器解压。

(4)取消主数据库锁定

mysql> UNLOCK TABLES;

验证主从复制
主库上执行

mysql> create database db1;
Query OK, 1 row affected (0.00 sec)

从库上查看

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| db_test            |
| mysql              |
| performance_schema |
+--------------------+
5 rows in set (0.00 sec)

db1已经复制到从库上,主从同步正常

5、异步复制小结:

由于二进制文件的缓冲区内,当我们的服务器宕机的时候,缓存区内的数据并没有同步到二进制日志文件内的时候,那就悲剧了,缓冲区内的数据就无法找回了,为了防止这种情况的发送,我们通过设置mysql直接把二进制文件记录到二进制文件而不再缓冲区内停留。sync-binlog = ON 在主服务器上进行设置,用于事务安全从上面我们可以看到从服务器启动的时候其Slave_IO_Running: Yes和Slave_SQL_Running: Yes是自动启动的,但是有时候我们在主服务上进行的误操作等,也会直接同步到从服务器上的,要想恢复那就难了,所以我们需要关闭其自动执行功能,让其能够停止,skip-slave-start = 1 ,让其不开启自动同步,但是遗憾的是mysql5.28上已经没有了,我们可以通过停止相关线程来实现:

mysql>STOP SLAVE 或STOP SLAVE  IO_THREAF或STOP SLAVE SQL_THREAD

注意:从服务器的所有操作日志都会被记录到数据目录下的错误日志中!

5.配置半主从复制

MySQL的半同步复制-semisync是基于默认的异步复制和完全同步复制之间,它是在master在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个slave收到并写到relay log中才返回给客户端。相对于异步复制,semisync提高了数据的安全性,但是又比完全同步性能好,所以master和slave之间的时间一定要一致,以免造成semisync失败。MySQL的半同步复制的插件是由Google免费提供的在MySQL的$basedir/lib/plugin下有相应的动态库文件,linux中是.so,DOS系统中是.dll,在默认情况下MySQL是没有装载semisync的插件,所以要制作semisync要手动在MySQL的shell中装载插件,下面就简单的说一说MySQL的semisync配置,这里要注意要使用MySQL的super用户来配置,并且MySQL要5.5及以上版本才有,并且要在有异步复制的基础上才可以做配置.

实现半同步复制的功能很简单,只需在mysql的主服务器和从服务器上安装个google提供的插件即可实现,

主服务上使用semisync_master.,从服务器上使用sosemisync_slave.so插件即可实现,插件在mysql通用二进制的mysql/lib/plugin目录内。

1、主库操作:
mysql> grant replication slave on *.* to "repl"@"10.1.1.%" identified by "repl";
Query OK, 0 rows affected (0.18 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
         
mysql> show binary logs;
+-------------------+-----------+
| Log_name           | File_size |
+-------------------+-----------+
| master-bin.000001    |  120   |
+-------------------+-----------+
1 row in set (0.00 sec)
2、从库上操作:
mysql> CHANGE MASTER TO MASTER_HOST="10.1.1.98",MASTER_USER="repl",MASTER_PASSWORD="repl",MASTER_LOG_FILE="master-bin.000001",MASTER_LOG_POS=120;
Query OK, 0 rows affected, 2 warnings (0.47 sec)

mysql> START SLAVE IO_THREAD;START SLAVE SQL_THREAD;
  Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.13 sec) 

安装插件配置半主从复制:
在master和SLAVE的Mysql命令行运行如下命令:

root@node ~]# cd /usr/local/mysql/lib/plugin/
[root@node plugin]# ls
adt_null.so     auth_test_plugin.so  innodb_engine.so      mypluglib.so       qa_auth_interface.so  semisync_slave.so
 auth.so         daemon_example.ini   libdaemon_example.so  mysql_no_login.so  qa_auth_server.so     validate_password.so
auth_socket.so  debug                libmemcached.so       qa_auth_client.so  semisync_master.so

#ON MASTER
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> SET GLOBAL rpl_semi_sync_master_enabled=1;
mysql> SET GLOBAL rpl_semi_sync_master_timeout=1000;
       


#ON SLAVE
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_slave.so';
mysql> SET GLOBAL rpl_semi_sync_slave_enabled=1; 
mysql> STOP SLAVE IO_THREAD;START SLAVE IO_THREAD;

上面的设置时在mysql进程内动态设定了,会立即生效但是重启服务以后就会失效,为了保证永久有效,需要把相关配置写到主、从服务器的配置文件my.cnf内:

在Master和Slave的my.cnf中编辑:

 Master
[mysqld]
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000   #此单位是毫秒
 Slave  
[mysqld]  
rpl_semi_sync_slave_enabled=1

查看插件是否加载成功

mysql> show plugins;
 +----------------------------+----------+--------------------+--------------------+---------+
 | Name                       | Status   | Type               | Library            | License |
 +----------------------------+----------+--------------------+--------------------+---------+
 | rpl_semi_sync_master       | ACTIVE   | REPLICATION        | semisync_master.so | GPL     |
 +----------------------------+----------+--------------------+--------------------+---------+   

或者:

 mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS  WHERE PLUGIN_NAME LIKE '%semi%';
  +----------------------+---------------+
  | PLUGIN_NAME          | PLUGIN_STATUS |
  +----------------------+---------------+
  | rpl_semi_sync_master | ACTIVE        |
  +----------------------+---------------+
  1 row in set (0.07 sec)

重启从数据库上的IO线程

mysql> START SLAVE IO_THREAD;

如果没有重启,则默认还是异步复制,重启后,slave会在master上注册为半同步复制的slave角色。

这时候,主的error.log中会打印如下信息:

[root@mysqlnode1 plugin]# tail /var/logs/mysqld.err 
2017-11-11 12:25:19 2556 [Warning] Neither --relay-log nor --relay-log-index were used; so replication may break when this MySQL server acts as a slave and has his hostname changed!! Please use '--relay-log=mysqlnode1-relay-bin' to avoid this problem.
2017-11-11 12:25:20 2556 [Note] 'CHANGE MASTER TO executed'. Previous state master_host='', master_port= 3306, master_log_file='', master_log_pos= 4, master_bind=''. New state master_host='192.168.137.172', master_port= 3306, master_log_file='master-bin.000001', master_log_pos= 413, master_bind=''.
2017-11-11 14:05:16 2556 [Note] Semi-sync replication initialized for transactions.
2017-11-11 14:05:16 2556 [Note] Semi-sync replication enabled on the master.
2017-11-11 14:09:29 2556 [Note] Stop asynchronous binlog_dump to slave (server_id: 2)
2017-11-11 14:09:29 2556 [Note] Start semi-sync binlog_dump to slave (server_id: 2), pos(master-bin.000001, 516)

查看半同步是否在运行
主库:

 mysql> show status like "%semi%";
 +--------------------------------------------+-------+
 | Variable_name                              | Value |
 +--------------------------------------------+-------+
 | Rpl_semi_sync_master_clients               | 1     |
 | Rpl_semi_sync_master_net_avg_wait_time     | 0     |
 | Rpl_semi_sync_master_net_wait_time         | 0     |
 | Rpl_semi_sync_master_net_waits             | 0     |
 | Rpl_semi_sync_master_no_times              | 0     |
 | Rpl_semi_sync_master_no_tx                 | 0     |
 | Rpl_semi_sync_master_status                | ON    |
 | Rpl_semi_sync_master_timefunc_failures     | 0     |
 | Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
 | Rpl_semi_sync_master_tx_wait_time          | 0     |
 | Rpl_semi_sync_master_tx_waits              | 0     |
 | Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
 | Rpl_semi_sync_master_wait_sessions         | 0     |
 | Rpl_semi_sync_master_yes_tx                | 0     |
 +--------------------------------------------+-------+
 14 rows in set (0.10 sec)

从库:

mysql> show status like "%semi%";
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

这两个变量常用来监控主从是否运行在半同步复制模式下

事实上,半同步复制并不是严格意义上的半同步复制
当半同步复制发生超时时(由rpl_semi_sync_master_timeout参数控制,单位是毫秒,默认为10000,即10s),会暂时关闭半同步复制,转而使用异步复制。当master dump线程发送完一个事务的所有事件之后,如果在rpl_semi_sync_master_timeout内,收到了从库的响应,则主从又重新恢复为半同步复制。

3、测试半异步主从同步:

该验证分为三个阶段

  • 1、在Slave执行stop slave之前,主的insert操作很快就能返回。

  • 2.在Slave执行stop slave后,主的insert操作需要10.01s才返回,而这与rpl_semi_sync_master_timeout参数的时间相吻合。
    这时,查看两个状态的值,均为“OFF”了。
    同时,主的error.log中会打印如下信息:

[root@mysqlnode1 plugin]# tail /var/logs/mysqld.err
2017-11-11 14:20:25 2556 [ERROR] Read semi-sync reply network error:  (errno: 1158)
2017-11-11 14:20:35 2556 [Warning] Timeout waiting for reply of binlog (file: master-bin.000001, pos: 1126), semi-sync up to file master-bin.000001, position 917.
2017-11-11 14:20:35 2556 [Note] Semi-sync replication switched OFF. 
  • 3.在Slave执行start slave后,主的insert操作很快就能返回,此时,两个状态的值也变为“ON”了。
    同时,主的error.log中会打印如下信息:
[root@mysqlnode1 plugin]# tail /var/logs/mysqld.err  
2017-11-11 14:23:48 2556 [Note] Stop semi-sync binlog_dump to slave (server_id: 2)
2017-11-11 14:23:48 2556 [Note] Start semi-sync binlog_dump to slave (server_id: 2), pos(master-bin.000001, 917)
2017-11-11 14:23:48 2556 [Note] Semi-sync replication switched ON with slave (server_id: 2) at (master-bin.000001, 1126)
4、常用参数:
mysql > show variables like "%rpl_semi%";
+------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled       | OFF   |
| rpl_semi_sync_master_timeout       | 10000 |
| rpl_semi_sync_master_trace_level   | 32    |
| rpl_semi_sync_master_wait_no_slave | ON    |
| rpl_semi_sync_slave_enabled        | OFF   |
| rpl_semi_sync_slave_trace_level    | 32    |
+------------------------------------+-------+

说明:
rpl_semi_sync_master_enabled 控制在主库是否开启了异步复制模式,可以设置为ON,OFF ,默认是off 。
rpl_semi_sync_master_timeout 控制主库等待备库反馈已提交事务在备库落地的时间,以毫秒为单位默认是10s 。
rpl_semi_sync_slave_enabled 控制在从库是否开启了异步复制模式,可以设置为ON,OFF ,默认是off 。

rpl_semi_sync_master_trace_level和rpl_semi_sync_slave_trace_level是可以组合(求或)的参数,可以是下面值的组合:
1 = general level (for example, time function failures)
16 = detail level (more verbose information)
32 = net wait level (more information about network waits)
64 = function level (information about function entry and exit)

rpl_semi_sync_master_wait_no_slave
表示是否允许master每个事务提交后都要等待slave的接收确认信号。默认为ON,即每一个事务都会等待。如果为OFF,则slave追赶上后,也不会开启半同步复制模式,需要手工开启。

查看运行状态

mysql > show status like "%rpl_semi%";
+--------------------------------------------+---------------+
| Variable_name                              | Value         |
+--------------------------------------------+---------------+
| Rpl_semi_sync_master_clients               | 1             |# 有多少个Semi-sync的备库
| Rpl_semi_sync_master_net_avg_wait_time     | 732           |# 事务提交后,等待备库响应的平均时间
| Rpl_semi_sync_master_net_wait_time         | 27885         |# 等待网络响应的总次数
| Rpl_semi_sync_master_net_waits             | 1323          |# 总的网络等待时间
| Rpl_semi_sync_master_no_times              | 0             |# 一共有几次从Semi-sync跌回普通状态
| Rpl_semi_sync_master_no_tx                 | 0             |# 备库未及时响应的事务数
| Rpl_semi_sync_master_status                | ON            |# 主库上Semi-sync是否正常开启
| Rpl_semi_sync_master_timefunc_failures     | 0             |# 时间函数未正常工作的次数
| Rpl_semi_sync_master_tx_avg_wait_time      | 59            |# 开启Semi-sync,事务返回需要等待的平均时间
| Rpl_semi_sync_master_tx_wait_time          | 8649          |# 事务等待备库响应的总时间
| Rpl_semi_sync_master_tx_waits              | 809           |# 事务等待备库响应的总次数
| Rpl_semi_sync_master_wait_pos_backtraverse | 9398          |# 改变当前等待最小二进制日志的次数
| Rpl_semi_sync_master_wait_sessions         | 230           |# 当前有几个线程在等备库响应
| Rpl_semi_sync_master_yes_tx                | 801           |# Semi-sync模式下,成功的事务数

上面比较重要的状态值有:
Rpl_semi_sync_master_tx_avg_wait_time:事务因开启Semi_sync,平均需要额外等待的时间
Rpl_semi_sync_master_net_avg_wait_time:事务进入等待队列后,到网络平均等待时间
依据上面两个状态值可以知道,Semi-sync的网络消耗有多大,给某个事务带来的额外的消耗有多大。
Rpl_semi_sync_master_status 则表示当前Semi-sync是否正常工作。
从Rpl_semi_sync_master_no_times变量,可以知道一段时间内,Semi-sync是否有超时失败过,该计数器则记录了这样的失败次数。

5、总结
  1. 在一主多从的架构中,如果要开启半同步复制,并不要求所有的从都是半同步复制。

  2. MySQL 5.7极大的提升了半同步复制的性能。
    5.6版本的半同步复制,dump thread 承担了两份不同且又十分频繁的任务:传送binlog 给slave ,还需要等待slave反馈信息,而且这两个任务是串行的,dump thread
    必须等待 slave 返回之后才会传送下一个 events 事务。dump thread 已然成为整个半同步提高性能的瓶颈。在高并发业务场景下,这样的机制会影响数据库整体的TPS 。
    5.7版本的半同步复制中,独立出一个 ack collector thread ,专门用于接收slave 的反馈信息。这样master 上有两个线程独立工作,可以同时发送binlog 到slave ,和接收slave的反馈。

6.基于GTID及多线程的复制

1、MySQL5.6 新特性之GTID

背景:
MySQL5.6在5.5的基础上增加了一些改进,本文章先对其中一个一个比较大的改进"GTID"进行说明。

概念:
GTID即全局事务ID(global transaction identifier),GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。下面是一个GTID的具体形式:
4e659069-3cd8-11e5-9a49-001c4270714e:1-77

GTID意义:
引入GTID的意义是什么?
1)因为清楚了GTID的格式,所以通过UUID可以知道这个事务在哪个实例上提交的。
2)通过GTID可以极方便的进行复制结构上的故障转移,新主设置。很好的解决了下面这个图的问题。

在这里插入图片描述上面图的意思是:Server1(Master)崩溃,根据从上show slave status获得Master_log_File/Read_Master_Log_Pos的值,Server2(Slave)已经跟上了主,Server3(Slave)没有跟上主。这时要是把Server2提升为主,Server3变成Server2的从。这时在Server3上执行change的时候需要做一些计算,这里就不做说明了,相对来说是比较麻烦的。

这个问题在5.6的GTID出现后,就显得非常的简单。由于同一事务的GTID在所有节点上的值一致,那么根据Server3当前停止点的GTID就能定位到Server2上的GTID。甚至由于MASTER_AUTO_POSITION功能的出现,我们都不需要知道GTID的具体值,直接使用CHANGE MASTER TO MASTER_HOST=‘xxx’, MASTER_AUTO_POSITION命令就可以直接完成failover的工作。

原理:
从服务器连接到主服务器之后,把自己执行过的GTID(Executed_Gtid_Set)<SQL线程> 、获取到的GTID(Retrieved_Gtid_Set)<IO线程>发给主服务器,主服务器把从服务器缺少的GTID及对应的transactions发过去补全即可。当主服务器挂掉的时候,找出同步最成功的那台从服务器,直接把它提升为主即可。如果硬要指定某一台不是最新的从服务器提升为主, 先change到同步最成功的那台从服务器, 等把GTID全部补全了,就可以把它提升为主了。

2、搭建

1)复制环境的搭建:
因为支持GTID,所以5.6多了几个参数:

mysql> show variables like "%gtid%";
+---------------------------------+-----------+
| Variable_name                | Value     |
+---------------------------------+-----------+
| binlog_gtid_simple_recovery     | OFF       |
| enforce_gtid_consistency        | ON        |
| gtid_executed                   |           |
| gtid_mode                       | ON        |
| gtid_next                       | AUTOMATIC |
| gtid_owned                      |           |
| gtid_purged                     |           |
| simplified_binlog_gtid_recovery | OFF       |
+---------------------------------+-----------+
8 rows in set (0.00 sec)

主从环境的搭建和5.5没有什么区别,唯一需要注意的是:开启GTID需要启用这三个参数:

#GTID
gtid_mode = on
enforce_gtid_consistency = 1
log_slave_updates   = 1

任意一个参数不开启则都会报错:

2017-08-09 02:33:57 6512 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates
2017-08-09 02:33:57 6512 [ERROR] Aborting

2017-08-09 02:39:58 9860 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 requires --enforce-gtid-consistency
2017-08-09 02:39:58 9860 [ERROR] Aborting

两个实例开启之后(10.1.1.98,10.1.1.197),执行change的时候也要注意:
使用5.6之前的主从change:

mysql>change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_log_file='mysql-bin3306.000001',master_log_pos=151,/*master_auto_position=1*/;
报错:
ERROR 1776 (HY000): Parameters MASTER_LOG_FILE, MASTER_LOG_POS, RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active.

当使用 MASTER_AUTO_POSITION 参数的时候,MASTER_LOG_FILE,MASTER_LOG_POS参数不能使用。

使用5.6之后的主从change:

mysql>change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1;

从总体上看来,由于要支持GTID,所以不需要手工确定主服务器的MASTER_LOG_FILE及MASTER_LOG_POS。要是不需要GTID则需要指定FILE和POS。在2个从上执行上面命令,到此主从环境搭建完成。GTID的主从完成之后可以通过show processlist查看:

mysql> show processlist\G;
*************************** 1. row ***************************
           Id: 38
         User: rep
         Host: localhost:52321
           db: NULL
      Command: Binlog Dump GTID   #通过GTID复制
         Time: 48
        State: Master has sent all binlog to slave; waiting for binlog to be updated
         Info: NULL
    Rows_sent: 0
Rows_examined: 0

跳过复制错误:gtid_next、gtid_purged
从服务器跳过一个错误的事务:

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin3306.000001
          Read_Master_Log_Pos: 38260944
               Relay_Log_File: mysqld-relay-bin3307.000002
                Relay_Log_Pos: 369
        Relay_Master_Log_File: mysql-bin3306.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 1008
                   Last_Error: Error 'Can't drop database 'mablevi'; database doesn't exist' on query. Default database: 'mablevi'. Query: 'drop database mablevi'
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 151
              Relay_Log_Space: 38261371
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 1008
               Last_SQL_Error: Error 'Can't drop database 'mablevi'; database doesn't exist' on query. Default database: 'mablevi'. Query: 'drop database mablevi'
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0  #通过在change的时候指定,如:change master to master_delay=600,延迟10分钟同步。
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 150810 23:38:39
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
            Executed_Gtid_Set: 
                Auto_Position: 1

在MySQL5.6之前,只需要执行:

mysql> set global sql_slave_skip_counter=1;

跳过一个错误的事务,就可以继续进行复制了。但在MySQL5.6之后则不行:

mysql> set global sql_slave_skip_counter=1;
ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction

分析:因为是通过GTID来进行复制的,也需要跳过这个事务从而继续复制,这个事务可以到主上的binlog里面查看:因为不知道找哪个GTID上出错,所以也不知道如何跳过哪个GTID。但在show slave status里的信息里可以找到在执行Master里的POS:151

Exec_Master_Log_Pos: 151的时候报错,
所以通过mysqlbinlog找到了GTID:

at 151主机的数据库
#150810 22:57:45 server id 1  end_log_pos 199 CRC32 0x5e14d88f     GTID [commit=yes]
SET @@SESSION.GTID_NEXT= '4e659069-3cd8-11e5-9a49-001c4270714e:1'/*!*/;

找到这个GTID之后执行:必须按照下面顺序执行

mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)

mysql> set session gtid_next='4e659069-3cd8-11e5-9a49-001c4270714e:1';  #在session里设置gtid_next,即跳过这个GTID
Query OK, 0 rows affected (0.01 sec)

mysql> begin;      #开启一个事务
Query OK, 0 rows affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> SET SESSION GTID_NEXT = AUTOMATIC;   #把gtid_next设置回来
Query OK, 0 rows affected (0.00 sec)

mysql> start slave;  #开启复制
Query OK, 0 rows affected (0.01 sec)

查看复制状态:

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin3306.000001
          Read_Master_Log_Pos: 38260944
               Relay_Log_File: mysqld-relay-bin3307.000003
                Relay_Log_Pos: 716
        Relay_Master_Log_File: mysql-bin3306.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 38260944
              Relay_Log_Space: 38261936
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0  #延迟同步
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
            Executed_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
                Auto_Position: 1

在此成功跳过了错误,同步继续。

注意:通过GTID的复制都是没有指定MASTER_LOG_FILE和MASTER_LOG_POS的,所以通过GTID复制都是从最先开始的事务开始,除非在自己的binlog里面有执行过之前的记录,才会继续后面的执行。
要是事务日志被purge,再进行change:

mysql> show master logs;   
+----------------------+-----------+
| Log_name             | File_size |
+----------------------+-----------+
| mysql-bin3306.000001 |  38260944 |
+----------------------+-----------+
row in set (0.00 sec)

mysql> flush logs;
Query OK, 0 rows affected (0.03 sec)

mysql> show tables;
+---------------+
| Tables_in_mmm |
+---------------+
| patent_family |
| t1            |
| t2            |
+---------------+
rows in set (0.01 sec)

mysql> create table t3(id int)engine = tokudb;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t3 values(3),(4);
Query OK, 2 rows affected (0.05 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> flush logs;
Query OK, 0 rows affected (0.02 sec)

mysql> create table ttt(id int)engine = tokudb;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into ttt values(1),(2),(3),(4),(5);
Query OK, 5 rows affected (0.03 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> show master logs;
+----------------------+-----------+
| Log_name             | File_size |
+----------------------+-----------+
| mysql-bin3306.000001 |  38260995 |
| mysql-bin3306.000002 |       656 |
| mysql-bin3306.000003 |       619 |
+----------------------+-----------+
rows in set (0.00 sec)

mysql> purge binary logs to 'mysql-bin3306.000003';  #日志被purge
Query OK, 0 rows affected (0.02 sec)

mysql> show master logs;   #日志被purge之后等下的binlog 
+----------------------+-----------+
| Log_name             | File_size |
+----------------------+-----------+
| mysql-bin3306.000003 |       619 |
+----------------------+--------

3308登陆之后执行:

mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.04 sec)

mysql> start slave;
Query OK, 0 rows affected (0.02 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 127.0.0.1
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: 
          Read_Master_Log_Pos: 4
               Relay_Log_File: mysqld-relay-bin3308.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: 
             Slave_IO_Running: No
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 0
              Relay_Log_Space: 151
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 1236
                Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
             Master_Info_File: /var/lib/mysql3/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 150811 00:02:50
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 1

报错:

Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'

这里需要解决的是:Slave如何跳过purge的部分,而不是在最先开始的事务执行。
在主上执行,查看被purge的GTID:

mysql> show global variables like 'gtid_purged';
+---------------+-------------------------------------------+
| Variable_name | Value                                     |
+---------------+-------------------------------------------+
| gtid_purged   | 4e659069-3cd8-11e5-9a49-001c4270714e:1-50 |
+---------------+-------------------------------------------+
row in set (0.00 sec)

在从上执行,跳过这个GTID:

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> set global gtid_purged = '4e659069-3cd8-11e5-9a49-001c4270714e:1-50';
Query OK, 0 rows affected (0.02 sec)

mysql> reset master;
Query OK, 0 rows affected (0.04 sec)

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

要是出现:

ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

则需要执行:

reset master;

到这从的同步就正常了。

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin3306.000003
          Read_Master_Log_Pos: 619
               Relay_Log_File: mysqld-relay-bin3308.000002
                Relay_Log_Pos: 797
        Relay_Master_Log_File: mysql-bin3306.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 619
              Relay_Log_Space: 1006
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
             Master_Info_File: /var/lib/mysql3/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:51-52
            Executed_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-52
                Auto_Position: 1
row in set (0.00 sec)

mysql> use mmm
Database changed
mysql> show tables;
+---------------+
| Tables_in_mmm |
+---------------+
| ttt           |
+---------------+
row in set (0.00 sec)
3、通过另一个从库恢复从库数据

比如一台从库误操作,数据丢失了,可以通过另一个从库来进行恢复:

slave2(3308):
mysql> use mmm
Database changed
mysql> show tables;
+---------------+
| Tables_in_mmm |
+---------------+
| patent_family |
| t             |
| tt            |
+---------------+
rows in set (0.00 sec)

mysql> truncate table tt;  #误操作,把记录删除了
Query OK, 0 rows affected (0.02 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin3306.000001
          Read_Master_Log_Pos: 38260553
               Relay_Log_File: mysqld-relay-bin3308.000002
                Relay_Log_Pos: 38260771
        Relay_Master_Log_File: mysql-bin3306.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 38260553
              Relay_Log_Space: 38260980
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e
             Master_Info_File: /var/lib/mysql3/master.info
                    SQL_Delay: 0  #延迟同步
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-46
            Executed_Gtid_Set: 081ccacf-3ce4-11e5-9a95-001c4270714e:1,  #多出了一个GTID(本身实例执行的事务)
4e659069-3cd8-11e5-9a49-001c4270714e:1-46
                Auto_Position: 1

数据被误删除之后,最好停止复制:stop slave;

恢复数据从slave1(3307)上备份数据,并还原到slave2(3308)中。

备份:
mysqldump  -uzjy -p123456 -h127.0.0.1 -P3307 --default-character-set=utf8 --set-gtid-purged=ON -B mmm > mmm1.sql

在还原到slave2的时候需要在slave2上执行:reset master; 不然会报错:

ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

还原:

root@zjy:~# mysql -uzjy -p123456 -h127.0.0.1 -P3308 --default-character-set=utf8 < mmm.sql 

开启同步:

mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.03 sec)

这时候你会发现误删除的数据已经被还原,并且复制也正常。因为根据GTID的原理,通过slave1的备份直接可以和Master进行同步。

这里备份注意的一点是:在备份开启GTID的实例里,需要指定 --set-gtid-purged参数,否则会报warning:

Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events

备份文件里面会出现:

SET @@GLOBAL.GTID_PURGED='4e659069-3cd8-11e5-9a49-001c4270714e:1-483';

还原的时候会要求先在实例上reset master,不然会报错:

Warning: Using a password on the command line interface can be insecure.
ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

指定–set-gtid-purged=ON参数,出现GTID_PURGED,直接还原的时候执行,从库不需要其他操作就可以直接change到主。关于GTID更多的信息可以到官方文档里查看。

4、总结:

GTID就是全局事务ID(global transaction identifier ),最初由google实现,官方MySQL在5.6才加入该功能。要是主从结构只有一台Master和一台Slave对于GTID来说就没有优势了,而对于2台主以上的结构优势异常明显,可以在数据不丢失的情况下切换新主。
使用GTID需要注意的是:在构建主从复制之前,在一台将成为主的实例上进行一些操作(如数据清理等),通过GTID复制,这些在主从成立之前的操作也会被复制到从服务器上,引起复制失败。即:通过GTID复制都是从最先开始的事务日志开始,即使这些操作在复制之前执行。比如在server1上执行一些drop、delete的清理操作,接着在server2上执行change的操作,会使得server2也进行server1的清理操作。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值