MySQL如何保证数据不丢

Binlog写入机制

  事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。系统给binlog cache分配了一片内存,每个线程一个,参数 binlog_cache_size用于控制单个线程内binlog cache所占内存的大小。如果超过了这个参数规定的大小,就要暂存到磁盘。
  Binlog的写入有两个阶段:
  1. write,指的是指把日志写入到文件系统的page cache,并没有把数据持久化到磁盘,所以速度比较快。
  2. fsync,是将数据持久化到磁盘的操作。一般情况下,fsync占用磁盘的IOPS。
  write 和fsync的时机,是由参数sync_binlog控制的:
  1. sync_binlog=0的时候,表示每次提交事务都只write,不fsync;
  2. sync_binlog=1的时候,表示每次提交事务都会执行fsync;
  3. sync_binlog=N(N>1)的时候,表示每次提交事务都write,但累积N个事务后才fsync。
  在实际的业务中,一般将这个参数设置为100-1000,注意这时如果主机异常重启,会有丢失日志的风险。

Redo log写入机制

  与binlog类似,为了控制redo log的写入策略,InnoDB提供了innodb_flush_log_at_trx_commit参数,它有三种可能取值:
  1. 设置为0的时候,表示每次事务提交时都只是把redo log留在redo log buffer中;
  2. 设置为1的时候,表示每次事务提交时都将redo log直接持久化到磁盘;
  3. 设置为2的时候,表示每次事务提交时都只是把redo log写到page cache。
  InnoDB通过后台线程的方式,每隔1秒,就把redo log buffer中的日志,调用write写到文件系统的page cache,然后调用fsync持久化到磁盘。

组提交技术

  为了减少刷盘占用的IOPS,MySQL提供了一种组提交技术,拖延write与fsync之间的时间,每次fsync的时候都将一组写到磁盘上~(不仅仅是当前事务),两阶段提交的实质性图如下所示:
在这里插入图片描述
  一般MySQL的备库会设置成read-only,以避免发生数据不一致等情况,注意这个read-only对于超级用户无效(binlog可以正常执行),事务日志同步的过程如下
  1. 在备库B上通过change master命令,设置主库A的IP、端口、用户名、密码,以及要从哪个位置开始请求binlog,这个位置包含文件名和日志偏移量。
  2. 在备库B上执行start slave命令,这时候备库会启动两个线程,分别为io_thread和sql_thread。其中io_thread负责与主库建立连接。
  3. 主库A校验完用户名、密码后,开始按照备库B传过来的位置,从本地读取binlog,发给B。
  4. 备库B拿到binlog后,写到本地文件,称为中转日志(relay log)。
  5. sql_thread读取中转日志,解析出日志里的命令,并执行。

Binlog的格式

  一共有三种格式
  Statement:
  这种格式直接记录操作语句,如果使用limit时,可能会发生在主库和从库上选择不同索引而造成的查询结果不一致的问题
  Row:
  记录具体操作的rowID,不会出现主从不一致的问题。对于插入会记录具体插入内容和插入的行,对于删除也会记录全部删除内容,所以可以用于恢复数据,但是占用空间较大。
  Mixed:
  这种格式是上面两种进行混合,由MySQL去判断是不是会发生主从不一致,进而选择合适的binlog格式
在生产中,大部分会使用双master,这时要小心binlog的循环复制问题,可以通过日志中记录的server id来解决。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章