MySQL——9、主从数据一致性问题
1.1 主从数据一致性问题:半同步复制
使用半同步复制
1.1.1 半同步复制的作用:
1.为了解决主从延迟导致数据丢失的问题
Mysql5.5之前的复制是异步的,主库和从库的数据有一定的延迟,这样就存在一个问题
当主库上写入一个事务并提交成功,而从库尚未收到主库推送的binlog日志,如果此时主库宕机,造成主库上的事务binlog丢失,此时,从库就可能损失这个事务,从而造成主从不一致。
为了解决这个问题,Mysql5.5引入了半同步复制机制。
1.1.2 什么是半同步复制:
需要主库和从库均打开半同步复制
Mysql主库发送binlog日志后,会执行等待,直到收到从库返回的确认响应后,才会返回给客户端
从库发回确认响应之前,是将binlog日志中的事件,写入了relay log的,并已经刷到磁盘中去了
理解:
半同步复制是从Mysql5.5版本开始,以插件的形式支持的,默认情况下是关闭的,使用时,需在配置中打开。
Mysql默认的复制是异步的,主库在将事件写入binlog后,即成功返回客户端,但并不知道从库是否以及何时会获取和处理日志。
而至于半同步复制,主库在提交后,执行事务提交的线程将一直等待,直到至少有一个半同步从库确认已接收到所有事件,从库仅在将事件写入其中继日志(relay log)并刷新到磁盘后,才对接收到事务的事件进行确认。
此时,主库收到确认后才会对客户端进行响应。
半同步复制保证了事务成功提交后,至少有两份日志记录,一份在主库的binlog上,另一份在至少一个从库的中继日志relay log上,这样就进一步保证了数据的完整性。
图中步骤①②③中任何一个步骤中主库宕机,则事务并未提交成功,从库也没有收到事务对应的binlog日志,所以主从数据是一致的。
需要注意的是:
(1)主库和从库都要启用半同步复制,才会进行半同步复制功能,否则主库会还原为默认的异步复制。
(2)当主库等待超时时,也会还原为默认的异步复制。当至少有一个从库赶上时,主库会恢复到半同步复制。
1.1.3 一个方法执行a数据库操作,在执行b数据库操作,怎么保证一致性
1.2 什么情况会导致主从数据不一致
(1)人为原因导致从库与主库数据不一致(从库写入)。
(2)主从复制过程中,主库异常宕机。
(3)设置了ignore/do/rewrite等replication等规则。
(4)binlog不是row格式 。
(5)异步复制本身不保证,半同步存在提交读的问题,增强半同步起来比较完美。 但对于异常重启或从库写数据(GTID)的防范,还需要策略来保证。
(6)从库中断很久,binlog应用不连续,监控并及时修复主从。
(7)从库启用了诸如存储过程,从库禁用存储过程等。
(8)数据库大小版本/分支版本导致数据不一致,主从版本统一。
(9)备份的时候没有指定参数 例如mysqldump --master-data=2 等。
(10)主从sql_mode 不一致。
(11)一主二从环境,二从的server id一致。
(12)MySQL自增列,主从不一致。
(13)主从信息保存在文件里面,文件本身的刷新是非事务的,导致从库重启后开始执行点。
1.3 Mysql数据备份问题
1.3.1 线上数据库备份场景:
每周日执行一次全量备份,然后每天下午1点执行MySQLdump增量备份.
1.3.2 为什么需要备份数据?
避免生产环境,数据丢失
在生产环境中我们数据库可能会遭遇各种各样的不测从而导致数据丢失, 大概分为以下几种.
a) 硬件故障
b) 软件故障
c) 自然灾害
d) 黑客攻击
e) 误操作 (占比最大)
所以, 为了在数据丢失之后能够恢复数据, 我们就需要定期的备份数据, 备份数据的策略要根据不同的应用场景进行定制, 大致有几个参考数值, 我们可以根据这些数值从而定制符合特定环境中的数据备份策略
a) 能够容忍丢失多少数据
b) 恢复数据需要多长时间
c) 需要恢复哪一些数据
1.3.3 数据的备份类型
数据的备份类型根据其自身的特性主要分为以下几组
完全备份:备份整个数据集( 即整个数据库 )
部分备份:备份部分数据集(例如: 只备份一个表)
而部分备份又分为以下两种
增量备份:备份自上一次备份以来(增量或完全)以来变化的数据。特点: 节约空间、还原麻烦
差异备份:备份自上一次完全备份以来变化的数据。 特点: 浪费空间、还原比增量备份简单
1.3.4 MySQL备份数据的方式
在MySQl中我们备份数据一般有几种方式
热备份:当数据库进行备份时, 数据库的读写操作均不是受影响
温备份:当数据库进行备份时, 数据库的读操作可以执行, 但是不能执行写操作
冷备份:当数据库进行备份时, 数据库不能进行读写操作, 即数据库要下线
MySQL中进行不同方式的备份,还要考虑存储引擎是否支持
MyISAM
热备 ×
温备 √
冷备 √
InnoDB
热备 √
温备 √
冷备 √
我们在考虑完数据在备份时, 数据库的运行状态之后,还需要考虑对于MySQL数据库中数据的备份方式
物理备份:一般就是通过tar,cp等命令,直接打包复制数据库的数据文件,达到备份的效果
逻辑备份:一般就是通过特定工具,从数据库中导出数据,并另存备份(逻辑备份会丢失数据精度)
1.3.5 一般备份什么?
一般情况下, 我们需要备份的数据分为以下几种
a) 数据
b) 二进制日志, InnoDB事务日志
c) 代码(存储过程、存储函数、触发器、事件调度器)
d) 服务器配置文件
1.3.6 备份工具
这里我们列举出常用的几种备份工具
\1) mysqldump : 逻辑备份工具, 适用于所有的存储引擎, 支持温备、完全备份、部分备份、对于InnoDB存储引擎支持热备
\2) cp, tar 等归档复制工具: 物理备份工具, 适用于所有的存储引擎, 冷备、完全备份、部分备份
\3) lvm2 snapshot: 几乎热备, 借助文件系统管理工具进行备份
\4) mysqlhotcopy: 名不副实的的一个工具, 几乎冷备, 仅支持MyISAM存储引擎
\5) xtrabackup: 一款非常强大的InnoDB/XtraDB热备工具, 支持完全备份、增量备份, 由percona提供
1.3.7 设计合适的备份策略
针对不同的场景下, 我们应该制定不同的备份策略对数据库进行备份, 一般情况下, 备份策略一般为以下三种
\1) 直接cp,tar复制数据库文件:
如果数据量较小, 可以使用第一种方式, 直接复制数据库文件
\2) mysqldump+复制BIN LOGS:
如果数据量还行, 可以使用第二种方式,
先使用mysqldump对数据库进行完全备份, 然后定期备份BINARY LOG达到增量备份的效果
\3) lvm2快照+复制BIN LOGS:
如果数据量一般, 而又不过分影响业务运行, 可以使用第三种方式,
使用lvm2的快照对数据文件进行备份, 而后定期备份BINARY LOG达到增量备份的效果
\4) xtrabackup:
如果数据量很大, 而又不过分影响业务运行, 可以使用第四种方式,
使用xtrabackup进行完全备份后, 定期使用xtrabackup进行增量备份或差异备份
1.3.8 使用mysqldump+复制BINARY LOG备份(理解)
备份前需要加锁
我们通过mysqldump进行一次完全备份, 再修改表中的数据, 然后再通过binary log进行恢复, 二进制日志需要在mysql配置文件中添加 log_bin=on 开启
使用mysqldump备份数据库:
[root@node1 ~]# mysql -uroot -p -e 'SHOW MASTER STATUS' #查看当前二进制文件的状态, 并记录下position的数字
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 106 | | |
+------------------+----------+--------------+------------------+
[root@node1 ~]# mysqldump --all-databases --lock-all-tables > backup.sql #备份数据库到backup.sql文件中
mysql> CREATE DATABASE TEST1; #创建一个数据库
Query OK, 1 row affected (0.00 sec)
mysql> SHOW MASTER STATUS; #记下现在的position
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 191 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
[root@node1 ~]# cp /var/lib/mysql/mysql-bin.000003 /root #备份二进制文件
[root@node1 ~]# service mysqld stop #停止MySQL
[root@node1 ~]# rm -rf /var/lib/mysql/* #删除所有的数据文件
[root@node1 ~]# service mysqld start #启动MySQL, 如果是编译安装的应该不能启动(需重新初始化), 如果rpm安装则会重新初始化数据库
mysql> SHOW DATABASES; #查看数据库, 数据丢失!
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| test |
+--------------------+
3 rows in set (0.00 sec)
mysql> SET sql_log_bin=OFF; #暂时先将二进制日志关闭
Query OK, 0 rows affected (0.00 sec)
mysql> source backup.sql #恢复数据,所需时间根据数据库时间大小而定
mysql> SET sql_log_bin=ON; 开启二进制日志
mysql> SHOW DATABASES; #数据库恢复, 但是缺少TEST1
+--------------------+
| Database |
+--------------------+
| information_schema |
| employees |
| mysql |
| test |
+--------------------+
4 rows in set (0.00 sec)
[root@node1 ~]# mysqlbinlog --start-position=106 --stop-position=191 mysql-bin.000003 | mysql employees #通过二进制日志增量恢复数据
mysql> SHOW DATABASES; #现在TEST1出现了!
+--------------------+
| Database |
+--------------------+
| information_schema |
| TEST1 |
| employees |
| mysql |
| test |
+--------------------+
5 rows in set (0.00 sec)