一、AB主从复制
1、介绍:
简称AB复制,在A主机上做create、update、insert、drop、delete等数据库、表、记录的增、删、改操作,B主机上会自动做数据库、表、记录的同步更新。
2、AB复制的工作原理(即工作过程):
a. 在主库上把数据更改记录到二进制日志(Binary Log)中。
b. 备库将主库上的日志复制到自己的中继日志(Relay Log)中。
c. 备库读取中继日志中的事件,将其重放到备库数据库之上。
3、AB复制的一主一从模式工作过程:
A主机: create database db1 ----> 会将此命令自动写入本机的二进制日志文件中
B主机:
I/O线程: 监测并读A主机上的二进制日志文件新增的内容,且将新内容写入到B主机自己的中继日志文件中
SQL线程 : 读取B主机上中继日志文件中心的SQL语句,并且自动执行这些SQL语句。最终在B主机上创建了db1这个库。
网络拓扑:(1主1从)
mysql主服务器(master主人):192.168.11.11
mysql从服务器(slave随从、奴隶):192.168.11.12
4、项目准备:(在master、slave主机上分别做如下操作)
0.[选做]。安装mariadb-server服务器端软件、mariadb客户端软件,启动mariadb服务,查mariadb服务端口号3306。
yum install -y mariadb-server mariadb
systemctl restart mariadb
netstat -atunlp | grep :3306
①停止master、slave主机上的mariadb服务,并且清空/var/lib/mysql的所有数据。
systemctl stop mariadb
rm -rfv /var/lib/mysql/*
②重启master、slave主机上的mariadb服务。并且查库、test库中是否有表(无表就OK)。
systemctl restart mariadb
mysql -uroot -e 'show databases;use test;show tables;'
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
5、AB复制的配置思路:
①在A主机(master)上的/etc/my.cnf主配置文件中开启binlog二进制日志文件功能,并且给主机设置server-id唯一标识编号。重启mariadb服务。
②在A主机上创建用于AB主从复制的用户账号,并查看master状态中的binlog日志文件的position位置数值。
③在B主机上的/etc/my.cnf主配置文件中设置server-id唯一标识编号。。重启mariadb服务。
④在B主机上用help change master查命令帮助,并用change master命令告诉B主机他的master主人的正确信息。
⑤在B主机上用start slave启动mariadb的随从服务,并用show slave status查看AB主从复制的数据同步状态,要确认两个线程的yes状态。
6、AB复制的配置实施:
①在A主机(master)上的/etc/my.cnf主配置文件中开启binlog二进制日志文件功能,并且给主机设置server-id唯一标识编号。重启mariadb服务。
vim /etc/my.cnf 做如下修改
[mysqld]
#找到此行,添加如下蓝色字的3行功能选项
server-id=11
#指定server-id为11,通常用本机IP的最后一组数
log-bin=master-bin
#添加此行,指定二进制日志文件名为master-bin
skip_name_resolv=1
#跳过域名解析功能
重启mariadb服务:
systemctl restart mariadb
②在A主机上创建用于AB主从复制的用户账号,并查看master状态中的binlog日志文件的position位置数值。
[root@localhost ~]# mysql -uroot -e “grant replication slave on . to ‘rep’@‘192.168.11.%’ identified by ‘rep’;”
[root@localhost ~]# mysql -uroot -e ‘select user,host,password from mysql.user;’
+------+-----------------------+-------------------------------------------+
| user | host | password |
+------+-----------------------+-------------------------------------------+
| root | localhost | |
| root | localhost.localdomain | |
| root | 127.0.0.1 | |
| root | ::1 | |
| | localhost | |
| | localhost.localdomain | |
| rep | 192.168.11.% | *9FF2C222F44C7BBA5CC7E3BE8573AA4E1776278C |
+------+-----------------------+-------------------------------------------+
[root@localhost ~]# mysql -uroot -e 'reset master;show master status;'
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000001 | 245 | | |
+-------------------+----------+--------------+------------------+
③在B主机上的/etc/my.cnf主配置文件中设置server-id唯一标识编号。重启mariadb服务。
vim /etc/my.cnf 做如下修改
[mysqld]
#找到此行,添加如下蓝色字的3行功能选项
server-id=12
#指定server-id为12,通常用本机IP的最后一组数
#log-bin=slave-bin
#添加此行,指定二进制日志文件名为slave-bin,需要变成master时再开启
skip_name_resolv=1
#跳过域名解析功能
重启mariadb服务:
[root@node12 ~]# systemctl restart mariadb
[root@node12 ~]# mysql -urep -prep -h192.168.11.11 -e 'status;'
--------------
mysql Ver 15.1 Distrib 5.5.60-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 5
Current database:
Current user: rep@192.168.11.12
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 5.5.60-MariaDB MariaDB Server
Protocol version: 10
Connection: 192.168.11.11 via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
Uptime: 5 min 27 sec
Threads: 1 Questions: 15 Slow queries: 0 Opens: 0 Flush tables: 2 Open tables: 26 Queries per second avg: 0.045
--------------
测试rep用户是否能远程访问master主机的数据库服务
④在B主机上用help change master查命令帮助,并用change master命令告诉B主机他的master主人的正确信息。
mysql
help change master to;
//默认配置如下:
CHANGE MASTER TO
MASTER_HOST='192.168.11.11',
MASTER_USER='rep',
MASTER_PASSWORD='rep',
MASTER_PORT=3306,
MASTER_LOG_FILE='master-bin.000001',
MASTER_LOG_POS=542,
MASTER_CONNECT_RETRY=10; //是指从和主连不上是重试连接的时间为10秒
//修改配置
MariaDB [(none)]> CHANGE MASTER TO
-> MASTER_HOST='192.168.11.11',
-> MASTER_USER='rep',
-> MASTER_PASSWORD='rep',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='master-bin.000001',
-> MASTER_LOG_POS=245,
-> MASTER_CONNECT_RETRY=10;
Query OK, 0 rows affected (0.00 sec)
⑤在B主机上用start slave启动mariadb的随从服务,并用show slave status查看AB主从复制的数据同步状态,要确认IO和SQL两个线程的yes状态。
mysql -uroot -p
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.01 sec)
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.11.11
Master_User: rep
Master_Port: 3306
Connect_Retry: 10
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 245
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 530
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
//注: \G 是分组(group)显示信息。需要IQ和SQL均为YES,Pos为245(和master一致)
注:change master to设置的信息默认保存在/var/lib/mysql/master.info文件中,relay中继日志的设置信息默认保存在/var/lib/mysql/relay-log.info文件中。
ls /var/lib/mysql/
cat /var/lib/mysql/master.info
cat /var/lib/mysql/relay-log.info
cat /var/lib/mysql/mysql.sock
//此套接字设备文件无法查看,是正常现象
⑥测试主从复制的数据同步。
a.首先,在A主机(192.168.11.11)上创建一个名称为db1的库,并查库。
mysql
create database db1;
show databases;
SHOW PROCESSLIST;
//查mysql的内部进程(即线程)清单
b.然后,在B主机上查库,看到了db1库,说明AB主机的数据自动同步成功。
mysql -uroot -e 'show databases;'
二、MySQL主从数据状态
1、MySQL 主从 show slave status 各个参数详解
①基于二进制日志复制的显示格式
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Queueing master event to the relay log
Master_Host: 172.18.16.22
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.010362
Read_Master_Log_Pos: 555176471
Relay_Log_File: mysqld-relay-bin.004136
Relay_Log_Pos: 502564
Relay_Master_Log_File: mysql-bin.010327
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: blog
Replicate_Ignore_DB:
Replicate_Do_Table: blog.archives
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 555176471
Relay_Log_Space: 3642164873
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: 1042
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: 1622
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
参数具体含义解释:
Slave_IO_State
这个是指Slave连接到Master的状态,就是当前IO线程的状态,MySQL主从复制线程状态转变。
这里显示了当前slave I/O线程的状态。状态信息和使用show processlist显示的内容一样。
slave I/O线程的状态,有以下几种:
1) waiting for master update
这是connecting to master状态之前的状态
2) connecting to master
I/O线程正尝试连接到master
3) checking master version
在与master建立连接后,会出现该状态。该状态出现的时间非常短暂。
4) registering slave on master
在与master建立连接后,会出现该状态。该状态出现的时间非常短暂。
5) requesting binlog dump
在与master建立连接后,会出现该状态。该状态出现的时间非常短暂。在这个状态下,I/O线程向master发送请求,请求binlog,位置从指定的binglog 名字和binglog的position位置开始。
6) waiting to reconnect after a failed binlog dump request
如果因为连接断开,导致binglog的请求失败,I/O线程会进入睡眠状态。然后定期尝试重连。尝试重连的时间间隔,可以使用命令"change master to master_connect_trt=X;“改变。
7) reconnecting after a failed binglog dump request
I/O进程正在尝试连接master
8) waiting for master to send event
说明,已经成功连接到master,正等待二进制日志时间的到达。如果master 空闲,这个状态会持续很长时间。如果等待的时间超过了slave_net_timeout(单位是秒)的值,会出现连接超时。在这种状态下,I/O线程会人为连接失败,并开始尝试重连
9) queueing master event to the relay log
此时,I/O线程已经读取了一个event,并复制到了relay log 中。这样SQL 线程可以执行此event
10) waiting to reconnect after a failed master event read
读取时出现的错误(因为连接断开)。在尝试重连之前,I/O线程进入sleep状态,sleep的时间是master_connect_try的值(默认是60秒)
11) reconnecting after a failed master event read
I/O线程正尝试重连master。如果连接建立,状态会变成"waiting for master to send event”
12) waiting for the slave sql thread to free enough relay log space
这是因为设置了relay_log_space_limit,并且relay log的大小已经整张到了最大值。I/O线程正在等待SQL线程通过删除一些relay log,来释放relay log的空间。
13) waiting for slave mutex on exit
I/O线程停止时会出现的状态,出现的时间非常短。
Master_User
这个是Master上面的一个用户,用来负责主从复制的用户 ,创建主从复制的时候建立的(具有reolication slave权限)。
Master_Port
Master服务器的端口,一般是3306。
Connect_Retry
连接尝试次数,使用change master时可以使用master-connect-retry选项指定当前值。
Master_Log_File
显示当前I/O线程当前正在读取的主服务器二进制日志文件的名称,上面显示是mysql-bin.010362。
Read_Master_Log_Pos
显示当前同步到主服务器上二进制日志的偏移量,I/O线程已经读取的位置,单位是字节,上述的示例显示当前同步到mysql-bin.010362的555176471偏移量位置,即已经同步了mysql-bin.010362这个二进制日志中529MB(555176471/1024/1024)的内容。
Relay_Log_File
显示Slave的SQL线程当前正在读取和执行的中继日志文件的名称。
Relay_Log_Pos
显示在当前的中继日志中,Slave的SQL线程已读取和执行的中继日志的偏移量。
Relay_Master_Log_File
显示Slave中继日志同步到Master的二进制日志文件,本示例中为mysql-bin.010327。
Slave_IO_Running
显示I/O线程是否被启动并成功地连接到主服务器上,成功为Yes,否则为No。
Slave_SQL_Running
显示SQL线程是否被启动,启动为Yes,否则为No。
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
Replicate_Ignore_Table
Replicate_Wild_Do_Table
Replicate_Wild_Ignore_Table
这些参数都是为了用来指明哪些库或者表在复制的时候不要同步到备库,但是这些参数用的时候要小心,因为当跨库使用的时候可能会出现问题。另外当仅忽略或仅允许多个库或表时,要多次使用忽略语句才可以。
Last_Errno,Last_Error
显示Slave的SQL线程读取日志参数的的错误数量和错误消息,错误数量为0并且消息为空字符串表示没有错误;如果Last_Error值不是空值,它也会在从属服务器的错误日志中作为消息显示。
Skip_Counter
显示最近被使用的用于SQL_SLAVE_SKIP_COUNTER的值,就是用于跳过Slave错误的。
Exec_Master_Log_Pos
表示SQL线程执行的Relay log相对于主库二进制日志偏移量的位置,Read_Master_Log_Pos减去Exec_Master_Log_Pos可以表示当前SQL线程运行的延时,单位是字节。上述例子显示完全同步。注意还要看Relay_Master_Log_File的值是否跟Master_Log_File相同,如果小于Master_Log_File二进制,则说明延迟更大。
Relay_Log_Space
表示所有原有的中继日志结合起来的总大小,在START SLAVE语句的UNTIL子句中指定的值,Until_Condition具有以下值:Until_Condition、Until_Log_File、Until_Log_Pos。
Until_Condition
如果没有指定UNTIL子句,则没有值。如果从属服务器正在读取,直到达到主服务器的二进制日志的给定位置为止,则值为Master,如果从属服务器正在读取,直到达到其中继日志的给定位置为止,则值为Relay。
Until_Log_File
Until_Log_Pos
Until_Log_File和Until_Log_Pos用于指示日志文件名和位置值,日志文件名和位置值定义了SQL线程在哪个点中止执行。
Master_SSL_Allowed
显示了从服务器是否使用SSL连接到主服务器。如果允许对主服务器进行SSL连接,则值为Yes;如果不允许对主服务器进行SSL连接,则值为No;如果允许SSL连接,但是从服务器没有让SSL支持被启用,则值为Ignored。
Master_SSL_CA_File
Master_SSL_CA_Path
Master_SSL_Cert
Master_SSL_Cipher
Master_SSL_Key
如果Slave使用SSL连接Master服务器,这里就会显示对应的证书和私钥信息。使用CHANGE MASTER与SSL相关的选项有:–master-ca,–master-capath,–master-cert,–master-cipher和–master-key等。
Seconds_Behind_Master
表示主从之间延迟的时间,单位是秒。如果为null表示未知数,一般主从复制出问题了会出现null的情况。
Master_SSL_Verify_Server_Cert
显示是否认证Master证书。
Master_Server_Id
显示主服务器的Server_id。
Using_Gtid
表示是否开启了基于Gtid的复制,开启为Yes,否则为No。
Gtid_IO_Pos
如果开启了基于Gtid的复制,这里会显示当前执行到的事物ID。
②基于GTIDs复制的显示格式
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.30.65
Master_User: mysql_slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 790
Relay_Log_File: relay-log.000008
Relay_Log_Pos: 1003
Relay_Master_Log_File: mysql-bin.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: 790
Relay_Log_Space: 2591
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: 5f0b7791-a499-11e6-901c-44a84227448b
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 more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: 5f0b7791-a499-11e6-901c-44a84227448b:2-11
Executed_Gtid_Set: 3ec6f284-a4a8-11e6-a3fe-44a84220797c:1-4,5f0b7791-a499-11e6-901c-44a84227448b:1-11
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_UUID
记录Master的UUID。
Master_Info_File
记录Master info信息的存储位置。
SQL_Delay
记录Slave设置延迟复制的时间,0表示无延迟。
SQL_Remaining_Delay
Slave_SQL_Running_State
记录SQL线程的状态。
Last_IO_Error_Timestamp
记录最近IO线程错误的时间戳。
Last_SQL_Error_Timestamp
记录最近SQL线程错误的时间戳。
Retrieved_Gtid_Set
接收的二进制日志集合,对应IO线程。
execute_Gtid_Set
执行的二进制日志集合,对应SQL线程。
Auto_Position
记录在GTID模式下是否开启了自动事务校验。
Channel_Name
在多源复制下(5.7支持),复制通道的名称,可以有多个。
2、主从复制跳过错误异常
[root@master ~]# pt-table-checksum --nocheck-replication-filters --replicate=mydb1.checksums --databases=mydb1 h=127.0.0.1,u=monitor,p=111111
Replica slave has binlog_format ROW which could cause pt-table-checksum to break replication. Please read "Replicas using row-based replication" in the LIMITATIONS section of the tool's documentation. If you understand the risks, specify --no-check-binlog-format to disable this check.
mysql主从复制,经常会遇到错误而导致slave端复制中断,这个时候一般就需要人工干预,跳过错误才能继续。
跳过错误有两种方式:
①跳过指定数量的事务
mysql>slave stop;
mysql>SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1 #跳过一个事务
mysql>slave start
②修改mysql的配置文件
通过slave_skip_errors参数来跳所有错误或指定类型的错误
vi /etc/my.cnf
[mysqld]
slave-skip-errors=1062,1053,1146 #跳过指定error no类型的错误
slave-skip-errors=all #跳过所有错误
3、mysql主从一致性校验
pt-table-checksum是查看主从一致性的工具, 网上很多人说 pt-table-checksum 要在主库上执行,其实不是的,我的mysql实例比较多,只需在某一台服务器上安装percona-toolkit,这台服务能够同时访问主库和从库就行了。
工具安装:
①软件下载:
wget https://www.percona.com/downloads/percona-toolkit/3.0.3/binary/redhat/6/x86_64/percona-toolkit-3.0.3-1.el6.x86_64.rpm
②安装该工具依赖的软件包:
yum install perl-IO-Socket-SSL perl-DBD-MySQL perl-Time-HiRes -y
③软件安装
rpm -ivh percona-toolkit-3.0.3-1.el6.x86_64.rpm
如果提示需要依赖,那么使用下列方式安装
yum localinstall percona-toolkit-3.0.3-1.el6.x86_64.rpm
④查看是否安装成功
rpm -qa | grep percona-toolkit
在master和slave创建账号:
mysql>GRANT SELECT,PROCESS,SUPER,REPLICATION SLAVE,CREATE,DELETE,INSERT,UPDATE ON *.* TO 'jiaoyan'@'192.168.11.*' identified by '123';
mysql>flush privileges;
说明:HOST指安装percona-toolkit的服务器IP。
在安装了percona-toolkit的服务器上执行:
pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=cnt.checksums --databases=cnt --tables=ldb_alipay_order h=Master_HOST,u=rep,p=rep,P=3306
–no-check-replication-filters 表示不需要检查 Master 配置里是否指定了 Filter。 默认会检查,如果配置了 Filter,如 replicate_do_db,replicate-wild-ignore-table,binlog_ignore_db 等,在从库checksum就与遇到表不存在而报错退出,所以官方默认是yes(–check-replication-filters)但我们实际在检测中时指定–databases=,所以就不存在这个问题,干脆不检测。
–no-check-binlog-format 不对binlog的格式进行检查
–replicate-check-only 只显示主从不一致部分,此参数不会生成新的checksums数据,只会根据checksums表已经有的数据来显示
**–databases=,-d:**要检查的数据库,逗号分隔。 --databases-regex 正则匹配要检测的数据库,–ignore-databases[-regex]忽略检查的库。Filter选项。
**–tables=,-t:**要检查的表,逗号分隔。如果要检查的表分布在不同的db中,可以用–tables=dbname1.table1,dbnamd2.table2的形式。
同理有–tables-regex,–ignore-tables,–ignore-tables-regex。–replicate指定的checksum表始终会被过滤。
pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=cnt.checksums --databases=cent h=127.0.0.1,u=user,p=123456,P=3306
• TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
06-15T10:24:20 0 0 910 1 0 0.267 cent.ldb_alipay_order
06-15T10:24:21 0 0 1557 1 0 0.283 cent.ldb_charge_history
06-15T10:24:21 0 0 2555 1 0 0.262 cent.ldb_charge_history_detail
06-15T10:24:21 0 0 1488 1 0 0.268 cent.ldb_device
06-15T10:24:21 0 0 7 1 0 0.007 cent.ldb_device_charge
06-15T10:24:21 0 0 34 1 0 0.007 cent.ldb_device_failure
06-15T10:24:21 0 0 0 1 0 0.007 cent.ldb_device_pwd
06-15T10:24:21 0 0 4 1 0 0.007 cent.ldb_failure_info
**TS :**完成检查的时间
**ERRORS :**检查时候发生错误和警告的数量
DIFFS : 0表示一致,1表示不一致。当指定–no-replicate-check时,会一直为0,当指定–replicate-check-only会显示不同的信息
ROWS : 表的行数
**CHUNKS :**被划分到表中的块的数目
**SKIPPED :**由于错误或警告或过大,则跳过块的数目
**TIME :**执行的时间
**TABLE :**被检查的表名
提示错误:
问题一:
Waiting for the --replicate table to replicate to localhost.localdomain...
问题出在percona.checksums 表在从库不存在,根本原因是没有从主库同步过来,所以看一下从库是否延迟严重。
问题二:
Diffs cannot be detected because no slaves were found. Please read the --recursion-method documentation for information.
上面的提示信息很清楚,因为找不到从,所以执行失败。用参数–recursion-method 可以指定模式解决。
4、mysql主从数据一致性校验及纠错工具
①概述
假如你是一位运维人员,假如你生产环境上部署了mysql系统,再假如你线上的mysql是基于主从复制的架构,那恭喜你,它将可能会带给你主从数据不一致的"恶运"。
由于mysql复制架构原生特性,主从服务器上的数据不可能做”同步“复制,所以延时是必然会有的,即使是不那么繁忙的服务器上,在业务不繁忙的时间里,从库能追上主库的进度,也可能会因为从服务器崩溃、非法关机、程序bug等因素导致在主库上写入的数据与从库上写入的数据不一致的问题。而当这种情况发生时,mysql内部是没有相应的机制来检测主从数据一致性的,对用户而言,你是不知道主从数据已经不一致了。
所以需要一种工具来解决这样的问题,而percona-toolkit工具集中的pt-table-checksum工具就是能在几乎不影响mysql性能的前提下高效的,能检测主从数据不一致的工具。当数据不一致真正产生后,percona-tools工具集中也提供了pt-table-sync工具来修复不一致的数据,这样可免去重新部署从服务器的麻烦。
然而在真正的生产环境上,这两个工具还是有一定的局限性,准确的说应该是mysql这种异步复制的架构导致了工具在使用上的局限性,因为从库会慢于主库,所以在校验主库上的表与校验从库上的表时往往数据是不一致的,这个不致是由于从库的延迟而导致的,所以这两个工具最好运用在以下场景:
a)、从服务器提升为主服务器时,在新的主服务器上线时需要与旧的主服务器进行数据一致性检查
b)、数据迁移后,应该进行数据一致性检查
c)、从库被误操作导致数据更新后,应该进行一致性检查
d)、计划内的数据一致性检查
②percona-toolkit工具的安装
先安装所依赖的包及percona-toolkit:
[root@master ~] yum -y install perl perl-devel libaio libaio-devel perl-Time-HiRes perl-DBD-MySQL perl-IO-Socket-SSL
[root@master ~] rpm -ivh percona-toolkit-2.2.13-1.noarch.rpm
③新建用户
创建一个非root权限的用户来专门进行数据一致检测等工作,pt-table-checksum与pt-table-sync需要连接到从库中进行相应的数据查看、数据修改等操作,所以在主库上创建一个这样的用户:
mysql> GRANT select,insert,update,delete,create,process,super,replication slave ON *.* TO monitor@'192.168.0.%' IDENTIFIED BY '111111';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT select,insert,update,delete,create,process,super,replication slave ON *.* TO monitor@'127.0.0.1' IDENTIFIED BY '111111';
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
用户新建好后请测试是否能正常接入主库和备库(因为这个用户也需要连接主库,所以创建了上边两个用户)。这个用户所需要的权限真不少,没办法,这是由于percona-toolkit中那两个工具的工作原理所需要的权限,如果为了省事,也可直接给予ALL的权限。
④pt-table-checksum使用
在mydb1库中的tb1表作为测试,在主库上查看tb1的内容:
mysql> SELECT * FROM mydb1.tb1;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 1 | tom | 12 |
| 2 | jem | 23 |
| 3 | jason | 29 |
| 4 | aaa | 30 |
| 5 | b | 69 |
+----+-------+------+
5 rows in set (0.01 sec)
在从库上查看mydb1.tb1的内容:
mysql> select * from mydb1.tb1;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 1 | tom | 12 |
| 2 | jem | 23 |
| 3 | jason | 29 |
| 4 | aaa | 30 |
| 5 | b | 69 |
+----+-------+------+
5 rows in set (0.00 sec)
此时主从的数据都是一致的,用pt-table-checksum工具测试一下看输出的是什么结果:
#报错了,因为我的mysql环境的二进制日志是基于行的,即‘binlog_format=ROW’,如果是基于行的复制环境,percona官方是不建议使用pt-table-checksum工具来进行数据的一致性检查的,但它又提供了一个选项来跳过此检查。
各常用选项意义:
**–nocheck-replication-filters:**不检查复制过虑,我们用–databases来指定需要检查的数据库
**–replicate:**把校验的信息写入指定的表中
**–no-check-binlog-format:**不检查二进制日志文件格式
**–replicate-check-only:**只显示有不一致数据的信息
**–databases:**指定校验的数据库,多个用逗号隔开
**–tables:**指定校验的表,多个用逗号隔开
h:主机,指主服务器IP
u:帐号
p:密码
加上“–no-check-binlog-format”选项后再来测试一次:
[root@master ~]# pt-table-checksum --nocheck-replication-filters --replicate=mydb1.checksums --no-check-binlog-format --databases=mydb1 --h=127.0.0.1,u=monitor,p=111111
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
04-21T18:00:59 0 0 5 1 0 0.280 mydb1.tb1
04-21T18:00:59 0 0 2 1 0 0.331 mydb1.tb2
#注意观察“DIFFS”那一列,如果数据有不一致的这里不是“0”值。
运行上边的命令后可能会报“no slaves were found”类似的错误,这里因为无法连接从服务器所导致。当运行上边的指令后,pt-table-checksum连接支主mysql后会采取递归的方法去自动查找主的从服务器有哪些,先是运行“show processlist;”,然后是运行“show slave hosts”来查找,如果遇到不能连接从服务器的错误时,可以在从服务器的my.cnf加入“report_host=从服务器IP”来主动告诉主服务器它就主的从,并在运行的pt-table-checksum命令中加上“–recursion-method=hosts”选项,这样在主服务器可以用“show slave hosts”指令就可查看到从服务器IP地址。
现在我们人为的使主从数据不一致,在从服务器上把tb1表中id号为5的age那一列改为20:
mysql> update mydb1.tb1 set age=20 where id=5;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from mydb1.tb1;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 1 | tom | 12 |
| 2 | jem | 23 |
| 3 | jason | 29 |
| 4 | aaa | 30 |
| 5 | b | 20 |
+----+-------+------+
5 rows in set (0.00 sec)
这样主从数据就不一致了,我们再主服务器上运行pt-table-checksum工具来测试一下:
[root@master ~]# pt-table-checksum --nocheck-replication-filters --replicate=mydb1.checksums --no-check-binlog-format --recursion-method=hosts --databases=mydb1 h=127.0.0.1,u=monitor,p=111111
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
04-21T18:27:00 0 1 5 1 0 0.307 mydb1.tb1
04-21T18:27:01 0 0 2 1 0 0.048 mydb1.tb2
#tb1这个表的"DIFFS"的值变为了“1”。
接下来该pt-table-sync工具上场了。
⑤pt-table-sync使用
可以用“–print”选项来看一下主从上到底是哪里不一致了:
[root@master ~]# pt-table-sync --replicate=mydb1.checksums h=127.0.0.1,u=monitor,p=111111 h=192.168.0.202,u=monitor,p=111111 --charset=utf8 --print
REPLACE INTO mydb1
.tb1
(id
, name
, age
) VALUES (‘5’, ‘b’, ‘69’) /percona-toolkit src_db:mydb1 src_tbl:tb1 src_dsn:A=utf8,h=127.0.0.1,p=…,u=monitor dst_db:mydb1 dst_tbl:tb1 dst_dsn:A=utf8,h=192.168.0.202,p=…,u=monitor lock:1 transaction:1 changing_src:mydb1.checksums replicate:mydb1.checksums bidirectional:0 pid:3205 user:root host:master/;
#上边的输出信息表示从库上id=5那行的age的值应该是69。
#命令中有两组“h= ,u= ,p= ”,第一组指定的是主服务器,第二组指向从服务器。
各个常用选项的意义:
**–replicate= :**表示基于pt-table-checksum工具生成的checksums表来修复有问题的数据
**–databases=:**表示执行同步的数据库,多个用逗号隔开
–tables=: 表示执行同步的数据表,多个用逗号隔开
**h= :**服务器主机名
**u= :**帐号
**p= :**密码
**–print:**只打印,但不执行命令
**–execute:**执行命令
确认数据真不一致后那就把“–print”选项换成“–execute”来执行替换语句:
[root@master ~]# pt-table-sync --replicate=mydb1.checksums h=127.0.0.1,u=monitor,p=111111 h=192.168.0.202,u=monitor,p=111111 --charset=utf8 --execute
从库上的数据手动纠正后再运行pt-table-checksum工具来看一下这两个表的数据是否已经一致了:
[root@master ~]# pt-table-checksum --replicate=mydb1.checksums --nocheck-replication-filters --no-check-binlog-format --databases=mydb1 h=127.0.0.1,u=monitor,p=111111
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
04-21T21:42:31 0 0 5 1 0 0.309 mydb1.tb1
04-21T21:42:32 0 0 2 1 0 0.304 mydb1.tb2
这样数据就被成功纠正。
5、总结
这两个工具一般都是结合起来使用,弥补了mysql没有数据一致性校验的机制,让运维人员在主从复制架构中更能维护得更好。基于percona官方的说明在pt-table-checksum工具中最好让复制是基于语句的复制,而基于语句和基于行的复制各有各的优缺点,如果考虑到在后期的维护中会常用到pt-table-checksum工具,个人认为还是该把binlog_format设置为statement,或者mixed。
最后要说的是,如果在生产环境上真的产生了主备数据不一致,而不是延迟导致的,那在利用这些工具对数据操作时切记记得对源数据要进行备份,不管源数据是完好的,还是有些数据已被损坏,你在做数据修复工作前一定要把源数据做一个备份,在数据恢复这样一个高压的环境,谁能保证你做的操作都是规范且正确的?如果操作失误,你起码还有回滚的机会。