前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL如何保证数据不丢失

MySQL如何保证数据不丢失

作者头像
shysh95
发布2022-04-07 19:28:38
9740
发布2022-04-07 19:28:38
举报
文章被收录于专栏:shysh95

如何保证数据不丢失?

保证redo log和binlog可以持久化到磁盘,就可以确保MySQL在异常重启后进行数据恢复。

binlog的写入机制

binlog的写入机制逻辑:

  • 事务执行过程中,先把日志写到binlog cache(内存)
  • 事务提交的时候(MySQL客户端执行commit指令),再把binlog cache中写到binlog文件中,并清空binlog cache

操作系统会给每个线程分配binlog cache,binlog cache的大小由binlog_cache_size参数控制,该参数控制的是单个线程内binlog cache的大小,如果超过了该参数的大小,就需要保存到磁盘

代码语言:javascript
复制
show global variables like 'binlog_cache_size';

binlog cache如何写入binlog文件?

  • 每个线程都有自己的一个binlog cache,但是共同使用同一份binlog
  • 上图中的write指的是把binlog cache写入到文件系统的page cache,不会真正将数据持久化到磁盘,因此速度较快
  • fsync才是将数据持久化到磁盘(此时会占用磁盘的IOPS)

binlog cache何时write和fsync?

write和fsync是由参数sync_binlog进行控制:

代码语言:javascript
复制
show global variables like 'sync_binlog';
  • 该参数为0,表示每次提交事务只write,不fsync
  • 该参数为1,表示每次提交事务都会fsync
  • 该参数大于1时,假设为N,表示每次事务都会write,但是会累计N个事务进行一次fsync

redo log写入机制

  • 事务在执行过程中,生成的redo log首先会写到redo log buffer
  • redo log会在一些特定条件下写入日志文件

binlog cache是每一个线程一个,但是redo log buffer是所有线程共用一个

redo log会在哪些地方存在?

redo log会在以下三个地方存在:

  • 绿色部分,MySQL的进程之中,也就是redo log buffer
  • 黄色部分,write到磁盘(存储在Page Cache中),此时没有实际调用fsync写入磁盘
  • 红色部分,持久化到磁盘,调用了fsync

redo log的写入策略如何控制?

redo log写入策略由innodb_flush_log_at_trx_commit参数控制:

代码语言:javascript
复制
show global variables like 'innodb_flush_log_at_trx_commit';
  • 该参数如果为0:表示每次事务提交时只把redo log留在redo log buffer中
  • 该参数如果为1:表示每次事务提交时都将redo log直接持久化到磁盘
  • 该参数如果为2:表示每次事务提交时将redo log写入page cache

InnoDB有一个后台线程,每隔1s,会把redo log buffer中的日志调用write写到page cache,然后调用fsync持久化到磁盘。

事务执行过程中redo log也是直接写入到redo log buffer中能够,这写redo log会因为后台线程会被一起持久化到磁盘(没有提交的事务也会被持久化到磁盘)。

除了后台线程每秒1次的轮询之外,还会有以下两种情况下会将redo log写入磁盘:

  • redo log buffer占用的空间即将达到innodb_log_buffer_size一半的时候,后台线程会主动写盘。(这里的写盘动作只是写到Page Cache,不会真正调用fsync)
  • 并行的事务在提交时,顺带会将该事务的redo log buffer持久化到磁盘。

MySQL 双1配置是?

MySQL 双1配置指的就是sync_binlog和innodb_flush_log_at_trx_commit都设置成1,也就是说一个事务完整提交前,需要等待两次刷盘,一次是redo log(prepare阶段),一次是binlog。

什么是日志逻辑序列号(LSN)?

LSN是用来对应redo log的一个个写入点,是单调递增的,每次写入长度为length的redo log,LSN的值就会加上length。

LSN也会写到InnoDB的数据页中,来确保数据页不会被多次执行重复的redo log

什么是组提交(Group Commit)?

  1. trx1是第一个到达的,会被选为leader
  2. 等trx1要开始写盘的时候,该组里有三个事务,此时LSN会变成160
  3. trx写盘的时候,带的LSN=160,因此当trx1返回时,所有LSN小于等160的redo log都已经被持久化到磁盘
  4. trx2和trx3此时就可以直接返回

一次组提交中,组员越多,越能节约磁盘IOPS。在多事务并发更新场景下,第一个事务写完redo log buffer以后,fsync越晚调用,组员就可能越多,节约IOPS效果越好

binlog的组提交

上面的组提交是redo log组提交,MySQL为了充分提高性能,binlog也会进行组提交。

上图最后三个步骤是redo log和binlog的两阶段提交(该步骤的触发是事务提交的一个阶段,也就是说我们的客户端执行了MySQL的commit命令),在写binlog的时候实际需要两步操作:

  1. 先把binlog从binlog cache中写到磁盘上的binlog文件
  2. 调用fsync持久化

上图是两阶段提交的细化,可以看出在执行第4步binlog fsync时,如果有多个事务的binlog已经写完,那么是可以一起持久化的,可以降低IOPS的消耗。

由于步骤3的执行较快,binlog write和fsync间隔时间段,所以binlog的组提交效果较差

binlog组提交效果提升

如果需要提升binlog组提交的效果,可以通过设置binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count参数来实现:

代码语言:javascript
复制
show global variables like 'binlog_group_commit_sync_delay';
show global variables like 'binlog_group_commit_sync_no_delay_count';
  • binlog_group_commit_sync_delay:表示延迟多少微秒以后调用fsync
  • binlog_group_commit_sync_no_delay_count:表示累计多少次以后调用fsync

上述两个条件是或关系,只要满足一个就会触发fsync。

redo log的commit阶段

根据两阶段提交的细化流程图,我们可以发现redo log的commit只写了page cache,并没有进行fsync,这是因为借助每秒1次的后台轮询刷盘,再加上崩溃恢复逻辑,InnoDB认为在redo log commit的时候就不需要fsync,只需要写到page cache即可。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档