主从复制环境搭建好后,对我们来说并不是没有下文或没有后顾之忧了。再好的程序都可能出错,只是概率的问题,换句话说,这个世上没有亘古不变的事,只有变幻莫测的人心,哈哈哈。突然想到了一个牛逼的定律----墨菲定律:如果一件事有出错的可能性,那么这件事一定会出错。突然感觉自己也挺有内涵的,瞬间提升了自己的档次。好了回到我们的主题上来,看看主从复制的IO线程故障和解决办法。
查看主从状态
通过show slave status\G 查看从服务器运行状态,主要状态信息如下:
show slave status\G
Slave_IO_Running: Yes #IO线程状态
Slave_SQL_Running: Yes #SQL线程状态
Last_IO_Errno: 0 #IO线程最后一次错误代码
Last_IO_Error: #IO线程错误说明
Last_SQL_Errno: 0 #SQL线程最后一次错误代码
Last_SQL_Error: #SQL线程错误说明
IO线程故障:IO线程向主库请求二进制日志,并且接受二进制日志。
- 主库连接不上
原因:
(1)user、password、port、ip 错误
解决:重新配置信息,然后执行以下命令
stop slave;
reset slave all;
change master to ...;
start slave;
(2)防火墙
(3)网络不通
(4)skip-name-resolve
解决:配置skip-name-resolve,然后执行:
stop slave;
start slave; - 主库二进制日志丢失或损坏
解决:
stop slave;
reset slave all;
重新备份恢复;
change master to ...;
start slave;
SQL线程故障:从relaylog中获取最新的未执行的日志来执行(从库做写入操作,都可能会导致以下问题出现)
- 删除、修改对象的操作时,没有这个对象
- 创建对象时,对象已存在
- 主键冲突
模拟故障:
(1)从库3308中创建数据库db01;
[root@db01 data]# mysql -S /data/3308/mysql.sock
mysql> create database db01;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db01 |
| fxw |
| mysql |
| performance_schema |
| test |
+--------------------+
6 rows in set (0.01 sec)
(2)主库3307中创建数据库db01;
[root@db01 ~]# mysql -S /data/3307/mysql.sock
mysql> create database db01;
Query OK, 1 row affected (0.01 sec)
# 看似一切安好
(3)从库3308中查看状态;
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Wild_Ignore_Table:
Last_Errno: 1007
Last_Error: Error 'Can't create database 'db01'; database exists' on query. Default database: 'db01'. Query: 'create database db01'
.
.
.
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'db01'; database exists' on query. Default database: 'db01'. Query: 'create database db01'
.
.
#这是我们可以看见Slave_SQL_Running: No,以及Last_Error,Last_SQL_Error等,也就是我们在3308中已经创建过db01,当3308通过二进制日志在此创建想通的数据库db01时发生冲突。
解决方法(1)
直接在3308中执行:
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
mysql> set global sql_slave_skip_counter = 1;
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: 10.0.0.20
Master_User: repl
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.
.
省略部分
.
.
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
ERROR:
No query specified
# 此时错误已经消失
# global sql_slave_skip_counter = 1 ,表示跳过错误,命令详情请参看https://www.iteye.com/blog/dinglin-1236330
解决方法(2)
在从库3308的配置文件中加入以下代码:
vim /data/3308/my.cnf
[mysqld]
slave-skip-errors = 1032,1062,1007
#slave-skip-errors 表示从库忽略错误代码为1032,1062,1007的错误
1007:数据库已存在,创建数据库失败
1008:数据库不存在,删除数据库失败
1050:数据表已存在,创建数据表失败
1050:数据表不存在,删除数据表失败
1054:字段不存在,或程序文件跟数据库有冲突
1060:字段重复,导致无法插入
1061:重复键名
1068:定义了多个主键
1094:位置线程ID
1146:数据表缺失,请恢复数据库
解决方法(3)
直接在从库命令行执行:set global read_only=1; 设置从库为只读
mysql> set global read_only=1;
Query OK, 0 rows affected (0.00 sec)
或者在配置文件中:
vim /data/3308/my.cnf
[mysqld]
read_only=1 ###只能控制普通用户,管理用户无效
主从延时过长:主从数据库之间并非同步,但是如果延时过长也是问题
Seconds_Behind_Master 即为主从时间间隔时间
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
.
.
.
Seconds_Behind_Master: 0
.
.
.
1 row in set (0.00 sec)
ERROR:
No query specified
# 目前时间间隔为0秒,但是如果网络波动或其他原因会导致时间过长,我们会希望Seconds_Behind_Master值越小越好。
# 默认主从复制机制是异步过程
- 主库原因:
(1)主库做修改操作之后,才会记录二进制日志。
sync_binlog=0/1,默认0,
0 表示操作系统缓存机制控制,
1 表示立即写入二进制日志,每次commit后刷新到binlog,是最安全的机制,所以主从复制下,设置为1
(2)主库的压力特别大(大事务,多事务)
(3)从库数量较多,导致dump线程繁忙
- 从库原因:
(1)relay-log写入慢
(2)SQL线程慢(主从硬件差异较大)
- 尽可能避免主从延时
(1)sync_binlog=1
(2)大事务拆成小事务,多事务进行分离
(3)使用多级主从,分库分表架构
(4)将binlog放到ssd或者flash上,高性能存储
(5)将relay放到ssd或者flash上
(6)尽量选择和主库一致硬件和配置

