MySQL怎么保证数据一致性

发布时间 2023-06-14 15:44:49作者: 上好佳28

一、MySQL数据库层怎么保证不丢数据

InnoDB支持事务,事务提交需要写redo、undo。采用日志先行的策略,将数据的变更在内存中完成,并且将事务记录成redo,顺序的写入redo日志中,即表示该事务已经完成,就可以返回给客户已提交的信息。但是实际上被更改的数据还在内存中,并没有刷新到磁盘,当达到一定的条件,会触发checkpoint,才会将内存中的数据(page)合并写入到磁盘

为了控制redo log的写入策略,InnoDB提供了innodb_flush_log_at_trx_commit参数,它有三种可能取值:

innodb_flush_log_at_trx_commit

= 0 :每秒 write cache & flush disk

= 1 :每次commit都 write cache & flush disk

= 2 :每次commit都 write cache,然后根据innodb_flush_log_at_timeout(默认为1s)时间 flush disk

二、主从复制怎么保证一致性

 

主库将变更写入 binlog 日志,然后从库连接到主库之后,从库有一个 IO 线程,将主库的binlog 日志拷贝到自己本地,写入一个 relay 中继日志中,接着从库中有一个 SQL 线程会从中继日志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍 SQL。

XA事务(保证redo与binlog的一致性)

MySQL的存储引擎与MySQL服务层之间,或者存储引擎与存储引擎之间的分布式事务,称之为内部XA事务。最为常见的内部XA事务存在与binlog与InnoDB存储引擎之间。

在事务提交时,先写二进制日志,再写InnoDB存储引擎的redo日志。对于这个操作要求必须是原子的,即需要保证两者同时写入,内部XA事务机制就是保证两者的同时写入。

XA事务的大致流程:

事务提交后,InnoDB存储引擎会先做一个PREPARE操作,将事务的XID写入到redo日志中

再写binlog日志

再将该事务的commit信息写到redo log中

如果在步骤1和步骤2失败的情况下,整个事务会回滚,如果在步骤3失败的情况下,MySQL数据库在重启后会先检查准备的UXID事务是否已经提交,若没有,则在存储引擎层再进行一次提交操作。这样就保证了redo与binlog的一致性,防止丢数据。

binlog刷新机制

master写binlog与innodb引擎写redo类似,也有参数控制:sync_binlog

= 0 :表示MySQL不控制binlog的刷新,由文件系统自己控制它的缓存的刷新
> 0 :表示每sync_binlog次事务提交,MySQL调用文件系统的刷新操作将缓存刷下去

其中最安全的就是=1,表示每次事务提交,MySQL都会把binlog缓存刷下去,这样在掉电等情况下,系统才有可能丢失1个事务的数据。当sync_binlog设置为1,对系统的IO消耗也是非常大的。

但是上面的XA事务流程,但是这个流程并不是天衣无缝的,redo的ib_logfile与binlog日志如果被设置非实时flush,就有可能存在丢数据的情况。

1.redo的trx_prepare未写入,但binlog写入,造成从库数据量比主库多。 2.redo的trx_prepare与commit都写入了,但是binlog未写入,造成从库数据量比主库少。

从目前来看,只能牺牲性能去换取数据的安全性,必须要设置redo和binlog为实时刷盘。

三、如何保证slave库写redo、binlog不实时丢数据

slave读取master的binlog日志后,需要落地3个文件:relay log、relay log info、master info:

    relay log:即读取过来的master的binlog,内容与格式与master的binlog一致

  relay log info:记录SQL Thread应用的relay log的位置、文件号等信息

  master info:记录IO Thread读取master的binlog的位置、文件号、延迟等信息

也可以控制刷盘参数

四、master宕机后无法及时恢复造成的数据丢失

如果master不切换,则整个数据库只能只读,影响应用的运行。

1.确保binlog全部传到从库

(1)异步复制(Asynchronous replication)

MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从库上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。

(2)全同步复制(Fully synchronous replication)

指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。

(3)半同步复制(Semisynchronous replication)

主库只需要等待至少一个从库节点收到并且 Flush Binlog 到 Relay Log 文件即可,主库不需要等待所有从库给主库反馈。同时,这里只是一个收到的反馈,确保事务提交后binlog至少传输到一个从库,不保证从库应用完成这个事务的binlog,如此,节省了很多时间。

2.保证数据最小化丢失

上面的方案设计及架构比较复杂,如果能容忍数据的丢失,可以考虑使用淘宝的TMHA复制管理工具。

当master宕机后,TMHA会选择一个binlog接收最大的slave作为master。当原master宕机恢复后,通过binlog的逆向应用,把原master上多执行的事务回退掉