Mysql复制架构及主从复制中数据不一致的解决方案

2018-11-03  本文已影响5人  任总

一、MySQL 复制架构

1、主从架构的优点:

1、解决了冗余问题和异地灾备;
2、配合高可用工具程序MHA,提高可靠性;
3、解决负载均衡问题,转移一部分“读”请求;
4、支援安全的备份操作;
5、测试,主从复制提供实验环境;
...

2、主/从架构类型:

3、主从复制要考虑问题

二、主从复制示例

1、主服务器:

时间同步;

[root@mysql-19 ~]# ntpdate time1.aliyun.com

配置文件my.cnf

[root@mysql-19 ~]# vim /etc/my.cnf.d/server.cnf 
[mysqld]
innodb_file_per_table=ON
skip_name_resolve=ON

server_id=1
log_bin=log-bin

启动服务:

systemctl start mariadb.service

授权从服务器复制账号

MariaDB [(none)]> GRANT REPLICATION CLIENT,REPLICATION SLAVE ON *.* TO 'repluser'@'192.168.1.20' IDENTIFIED BY 'replpass';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
#查看二进制日志信息
MariaDB [(none)]> SHOW MASTER STATUS;
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-log.000001 |      245 |              |                  |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

2、从服务器:

时间同步;

[root@mysql-19 ~]# ntpdate time1.aliyun.com

配置文件my.cnf

[root@mysql-20 ~]# vim /etc/my.cnf.d/server.cnf 
[mysqld]
innodb_file_per_table=ON
skip_name_resolve=ON

server_id=12
relay_log=relay-log
read_only=ON

启动服务:

systemctl start mariadb.service

设置从服务器复制

[root@mysql-20 ~]# mysql

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.1.19',MASTER_USER='repluser',MASTER_PASSWORD='replpass',MASTER_PORT=3306,MASTER_LOG_FILE='master-log.000001',MASTER_LOG_POS=245;
Query OK, 0 rows affected (0.05 sec)
#启动线程进行复制
MariaDB [(none)]> START SLAVE;
Query OK, 0 rows affected (0.00 sec)
#查看
MariaDB [(none)]> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.19
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-log.000001
          Read_Master_Log_Pos: 498
               Relay_Log_File: relay-log.000002
                Relay_Log_Pos: 783
        Relay_Master_Log_File: master-log.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: 498
              Relay_Log_Space: 1071
              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
1 row in set (0.01 sec)

3、测试:

#主数据库操作
MariaDB [(none)]> create database mydb;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> use mydb;
Database changed

MariaDB [mydb]> CREATE TABLE tbl1(id INT,name CHAR(30),age INT);
Query OK, 0 rows affected (0.33 sec)

#从数据库查询是否同步
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb               |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.01 sec)

MariaDB [(none)]> use mydb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mydb]> show tables;
+----------------+
| Tables_in_mydb |
+----------------+
| tbl1           |
+----------------+
1 row in set (0.00 sec)

MariaDB [mydb]> desc tbl1;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  |     | NULL    |       |
| name  | char(30) | YES  |     | NULL    |       |
| age   | int(11)  | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
3 rows in set (0.00 sec)

三、主主复制:

定义一个节点使用奇数id

auto_increment_offset=1 #起始偏移值
auto_increment_increment=2 #步进值

另一个节点使用偶数id

auto_increment_offset=2 #起始偏移值
auto_increment_increment=2 #步进值

1、节点一服务器配置:

[root@mysql-19 ~]# vim /etc/my.cnf.d/server.cnf 
[mysqld]
innodb_file_per_table=ON
skip_name_resolve=ON

server_id=1
log-bin=master-log
relay_log=relay-log

auto_increment_offset=1 #起始偏移值
auto_increment_increment=2  #步进值
[root@mysql-19 ~]# systemctl start mariadb
[root@mysql-19 ~]# mysql
#复制授权
MariaDB [(none)]> GRANT REPLICATION CLIENT,REPLICATION SLAVE ON *.* TO 'repluser'@'192.168.1.20' IDENTIFIED BY 'replpass';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
#查看二进制日志位置
MariaDB [(none)]> SHOW MASTER STATUS;
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-log.000003 |      770 |              |                  |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

#设置访问节点二用户名密码
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.1.20',MASTER_USER='repluser',MASTER_PASSWORD='replpass',MASTER_PORT=3306,MASTER_LOG_FILE='master-log.000003',MASTER_LOG_POS=770;
Query OK, 0 rows affected (0.01 sec)
#启动复制
MariaDB [(none)]> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

2、节点二配置:

[mysqld]
innodb_file_per_table=ON
skip_name_resolve=ON

server_id=12
log_bin=master-log
relay-log=relay-log
read_only=ON

auto_increment_offset=2
auto_increment_increment=2

#从服务器访问授权
MariaDB [(none)]> GRANT REPLICATION CLIENT,REPLICATION SLAVE ON *.* TO 'repluser'@'192.168.1.19' IDENTIFIED BY 'replpass';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
#设置访问节点一用户名密码
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.1.19',MASTER_USER='repluser',MASTER_PASSWORD='replpass',MASTER_PORT=3306,MASTER_LOG_FILE='master-log.000003',MASTER_LOG_POS=770;
Query OK, 0 rows affected (0.06 sec)
#查看二进制日志位置
MariaDB [(none)]> show master status;
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-log.000003 |      770 |              |                  |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
#启用复制
MariaDB [(none)]> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

3、测试:

#节点一操作:创建mydb数据库,待节点二创建完表后,再次查询
MariaDB [(none)]> create database mydb;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb               |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec)

MariaDB [(none)]> use mydb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mydb]> show tables;
+----------------+
| Tables_in_mydb |
+----------------+
| tbl1           |
+----------------+
1 row in set (0.00 sec)

MariaDB [mydb]> desc tbl1;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  |     | NULL    |       |
| name  | char(30) | YES  |     | NULL    |       |
| age   | int(11)  | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
3 rows in set (0.00 sec)
#节点二操作:在mydb库中创建表
MariaDB [(none)]> use mydb;
Database changed
MariaDB [mydb]> CREATE TABLE tbl1(id INT,name CHAR(30),age INT);
Query OK, 0 rows affected (0.06 sec)

4、配置注意:

5、服务启动后执行如下两步:

6、复制时应该注意的问题:

四、半同步复制

mysql> INSTALL PLUGIN plugin_name SONAME 'shared_library_name';

1、主节点:

#安装主节点半同步插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
#查询主节点半同步插件状态
MariaDB [mydb]> SHOW GLOBAL 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    |
+------------------------------------+-------+
#启用主节点半同步插件
MariaDB [mydb]> SET @@global.rpl_semi_sync_master_enabled=ON;

2、从节点:

#安装从节点半同步插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
#查看从节点半同步插件当前状态
MariaDB [mydb]> SHOW GLOBAL VARIABLES LIKE 'rpl_semi%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | OFF   |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
#启用从节点半同步插件
MariaDB [mydb]> SET @@global.rpl_semi_sync_slave_enabled=ON;
#查看从节点半同步插件当前状态
MariaDB [mydb]> SHOW GLOBAL VARIABLES LIKE 'rpl_semi%';
#重启线程
MariaDB [mydb]> STOP SLAVE IO_THREAD;
MariaDB [mydb]> START SLAVE IO_THREAD;

3、测试:

主节点:

MariaDB [(none)]> SHOW GLOBAL STATUS LIKE 'rpl%';
+--------------------------------------------+-------------+
| 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           |
| Rpl_status                                 | AUTH_MASTER |
+--------------------------------------------+-------------+
15 rows in set (0.00 sec)

五、复制过滤器:

有两种实现思路:

1、主服务器端过滤

注意:过滤设置不能同时使用。

binlog_do_db= 仅对某个库有写权限(白名单)
binlog_ignore_db= 除此库之外的所有有写权限(黑名单)

2、从服务器端过滤

Replicate_Do_DB= 库级别白名单
Replicate_Ignore_DB= 库级别黑名单
Replicate_Do_Table= 表级别黑名单
Replicate_Ignore_Table= 表级别黑名单
Replicate_Wild_Do_Table= 使用通配符匹配白名单
Replicate_Wild_Ignore_Table= 使用通配符匹配黑名单

从服务器:

#查询从节点相关设置信息
MariaDB [(none)]> SHOW SLAVE STATUS \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.19
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-log.000004
          Read_Master_Log_Pos: 245
               Relay_Log_File: relay-log.000005
                Relay_Log_Pos: 530
        Relay_Master_Log_File: master-log.000004
             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: 
.......
#查询库级别白名单配置
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%do_db%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| replicate_do_db |       |
+-----------------+-------+
1 row in set (0.00 sec)
#停止从节点复制线程
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.01 sec)
#设置库白名单启用
MariaDB [(none)]> SET @@global.replicate_do_db=mydb;
Query OK, 0 rows affected (0.00 sec)
#启用从节点复制线程
MariaDB [(none)]> START SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
#查询从节点设置信息
MariaDB [(none)]> SHOW SLAVE STATUS \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.19
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-log.000004
          Read_Master_Log_Pos: 245
               Relay_Log_File: relay-log.000005
                Relay_Log_Pos: 530
        Relay_Master_Log_File: master-log.000004
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: mydb   #设置成mydb库
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
           .................

六、复制的监控和维护:

1、清理日志:PURGE

格式:PURGE { BINARY | MASTER } LOGS { TO 'log_name' | BEFORE datetime_expr };

#备份二进制日志文件
[root@mysql-19 ~]# mkdir /data/backup/binlogs -pv
mkdir: created directory ‘/data/backup/binlogs’
[root@mysql-19 ~]# cp /var/lib/mysql/master-log.* /data/backup/binlogs/


MariaDB [(none)]> show master logs;
+-------------------+-----------+
| Log_name          | File_size |
+-------------------+-----------+
| master-log.000001 |     30340 |
| master-log.000002 |   1038814 |
| master-log.000003 |       498 |
| master-log.000004 |       245 |
+-------------------+-----------+
4 rows in set (0.00 sec)
#删除00004之前的日志
MariaDB [(none)]> PURGE MASTER LOGS TO 'master-log.000004';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> show master logs;
+-------------------+-----------+
| Log_name          | File_size |
+-------------------+-----------+
| master-log.000004 |       245 |
+-------------------+-----------+
1 row in set (0.00 sec)
#自动更新index文件
[root@mysql-19 ~]# cat /var/lib/mysql/master-log.index 
./master-log.000004

2、 复制监控语句
SHOW MASTER STATUS \G;
SHOW BINLOG EVENTS; #查询二进制文件数据记录位置
SHOW BINARY LOGS; #查询二进制文件
SHOW SLAVE STATUS \G;
Seconds_Behind_Master: 0
3、 如何确定主从节点数据是否一致

通过表的CHECKSUM检查;
使用percona-toolkit中pt-table-checksum命令;

注意:
1、根据测试,需要一个技能登录主库,也能登录从库,而且还能同步数据库的账号;
2、只能指定一个host,必须为主库的IP;
3、在检查时会向表加S锁;
4、运行之前需要从库的同步IO和SQL进程是YES状态。
#下载
[root@mysql-20 ~]# wget https://www.percona.com/downloads/percona-toolkit/3.0.12/binary/redhat/7/x86_64/percona-toolkit-3.0.12-1.el7.x86_64.rpm
#安装
[root@mysql-20 ~]# yum install percona-toolkit-3.0.12-1.el7.x86_64.rpm -y
#校验
[root@mysql-20 ~]# pt-table-checksum h=192.168.1.19,u=myadmin,p=mypass,P=3306 --databases=mysql --tables=tbl3 --nocheck-replication-filters 
#结果
.............
# A software update is available:
            TS ERRORS  DIFFS     ROWS  DIFF_ROWS  CHUNKS SKIPPED    TIME TABLE
11-03T18:51:23      0      0        3          0       1       0   0.035 mysql.tbl3
............

参数说明:

TS            :完成检查的时间。
ERRORS        :检查时候发生错误和警告的数量。
DIFFS         :0表示一致,1表示不一致。当指定--no-replicate-check时,会一直为0,当指定--replicate-check-only会显示不同的信息。
ROWS          :表的行数。
CHUNKS        :被划分到表中的块的数目。
SKIPPED       :由于错误或警告或过大,则跳过块的数目。
TIME          :执行的时间。
TABLE         :被检查的表名。

参数意义:
--nocheck-replication-filters :不检查复制过滤器,建议启用。后面可以用--databases来指定需要检查的数据库。
--no-check-binlog-format      : 不检查复制的binlog模式,要是binlog模式是ROW,则会报错。
--replicate-check-only :只显示不同步的信息。
--replicate=   :把checksum的信息写入到指定表中,建议直接写到被检查的数据库当中。
--databases=   :指定需要被检查的数据库,多个则用逗号隔开。
--tables=      :指定需要被检查的表,多个用逗号隔开
h=127.0.0.1    :Master的地址
u=root         :用户名
p=123456       :密码
P=3306         :端口

参数解释:
# --h -u -p -P -S -d 连接信息
# --nocheck-replication-filters 检测中忽略mysql 配置参数binlog_ignore_db等
# --nocheck-binlog-format 不检测日志格式
# --replicate 指定checksum 存储的db和表, 如:pt.checksum
# --databases 指定数据库,如:nobserver_new
# --chunk-size, --chunk-size-limit 用于指定检测块的大小,可控性更强
# --ignore-databases/tables/column 跳出指定元素的过滤
# --lock-wait-timeout innodb 锁的超时设定, 默认为1
# --max-load 设置最大并发连接数
# --replicate-check-only 只输出数据不一致的信息

#更多的参数请见官网,上面指出来的是常用的,对该场景够用的参数。
#通过DIFFS是1可以看出主从的表数据不一致,通过查看从库上的test.checksum表可以看到主从库的检验信息。
#当DIFFS列全部为0时表示Master、Slave无差异。
4、 主从数据不一致时的修复方法
方法一:

重新复制数据库,结合二进制文件恢复。

方法二:
#同步主从数据
[root@mysql-20 ~]# pt-table-sync --print --replicate=test.checksum h=192.168.1.21,u=myadmin,p=mypass,P=3306 h=192.168.1.19,u=myadmin,p=mypass,P=3306 #第一个ip是主节点,第二个ip是从节点
#或者
#用一个从节点ip执行同步库里的指定表
[root@mysql-20 bin]# pt-table-sync --print --sync-to-master h=192.168.1.19,u=myadmin,p=mypass,P=3306 --databases mysql --tables tbl3

参数的意义:
--replicate=  :指定通过pt-table-checksum得到的表,这2个工具差不多都会一直用。
--databases=  : 指定执行同步的数据库,多个用逗号隔开。
--tables=     :指定执行同步的表,多个用逗号隔开。
--sync-to-master :指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。
h=127.0.0.1   :服务器地址,命令里有2个ip,第一次出现的是M的地址,第2次是Slave的地址。
u=root        :帐号。
p=123456      :密码。
--print       :打印,但不执行命令。
--execute     :执行命令。

更多的参数请见官网,上面指出来的是常用的,对该场景够用的参数

注意:要是表中没有唯一索引或则主键则会报错:
Can't make changes on the master because no unique index exists at /usr/local/bin/pt-table-sync line 10591.

七、读锁FTWRL在备份中的使用

读锁的作用

flush tables with read lock的作用是关闭所有打开的表,同时对于所有数据库中的表都加一个读锁,直到显示地执行unlock tables,该操作常常用于数据备份的时候也就是将所有的脏页都要刷新到磁盘,然后对所有的表加上了读锁,于是这时候直接拷贝数据文件也就是安全的。

工作流程

读锁缺点:

改进

LOCK TABLES FOR BACKUP
LOCK BINLOG FOR BACKUP

上一篇下一篇

猜你喜欢

热点阅读