数据+LOG

数据库的数据由两部分组成,一部分是数据,一部分是LOG。Innodb的数据包括内存(Innodb buffer pool)中和硬盘中的数据。数据的更改首先会作用到内存中的缓存数据,然后Innodb会根据flush策略将最新的数据flush到硬盘中。因此数据并不是实时落盘的,此时如果进程或者系统崩溃的话,没flush到硬盘的数据会丢失。Innodb采用了WAL技术,通过Redo日志与Undo日志保证了数据的持久性与原子性。

WAL技术

在计算机科学中,预写式日志(Write-ahead logging,缩写 WAL)是关系数据库系统中用于提供原子性和持久性(ACID属性中的两个)的一系列技术。在使用WAL的系统中,所有的修改在提交之前都要先写入log文件中。

Redo与Undo

为啥使用Redo与Undo。

» MySQL数据库InnoDB存储引擎Log漫游(1)

IO性能

Undo + Redo的设计主要考虑的是提升IO性能。虽说通过缓存数据,减少了写数据的IO.

但是却引入了新的IO,即写Redo Log的IO。如果Redo Log的IO性能不好,就不能起到提高性能的目的。

为了保证Redo Log能够有比较好的IO性能,InnoDB 的 Redo Log的设计有以下几个特点:

A. 尽量保持Redo Log存储在一段连续的空间上。因此在系统第一次启动时就会将日志文件的空间完全分配。

以顺序追加的方式记录Redo Log,通过顺序IO来改善性能。

B. 批量写入日志。日志并不是直接写入文件,而是先写入redo log buffer.当需要将日志刷新到磁盘时

(如事务提交),将许多日志一起写入磁盘.

C. 并发的事务共享Redo Log的存储空间,它们的Redo Log按语句的执行顺序,依次交替的记录在一起,

以减少日志占用的空间。例如,Redo Log中的记录内容可能是这样的:

记录1:

记录2:

记录3:

记录4:

记录5:

D. 因为C的原因,当一个事务将Redo Log写入磁盘时,也会将其他未提交的事务的日志写入磁盘。

E. Redo Log上只进行顺序追加的操作,当一个事务需要回滚时,它的Redo Log记录也不会从

Redo Log中删除掉。

Redo为啥采用物理page+逻辑

https://zhuanlan.zhihu.com/p/109417488

» MySQL数据库InnoDB存储引擎Log漫游(2)

这也是为啥需要double write buffer

保证日志的刷盘

上文提到Innodb通过Redo日志与Undo日志保证了数据的持久性与原子性。所以日志的刷盘策略很关键,只有日志及时刷盘,持久性和原子性才得以实现。

这里面就涉及到几个参数,包括innodb_flush_method、innodb_flush_log_at_commit等。

innodb_flush_method

Defines the method used to flush data to InnoDB data files and log files, which can affect I/O throughput.

innodb_flush_method与open文件的模式不是一一对应,因为innodb_flush_method同时指定了data files和log files的刷盘方式,这两者的刷盘方式可能不一致。

举个例子,innodb_flush_method为O_DIRECT,以O_DIRECT模式open data files,数据绕过缓存直接写入硬盘,log files仍然需要过操作系统缓冲。

image.png

注意:

innodb_flush_method为O_DIRECT时

用O_DIRECT打开数据文件,那为什么还要fsync,因为需要刷新为了把directory cache和inode cache元数据也刷新到存储设备上。

日志文件还是要过文件系统缓存,所以也需要fsync。

innodb_flush_log_at_commit

控制着redo日志在commit时的刷盘行为,参考上文,因为日志仍然需要过操作系统缓冲,所以数据安全性要求高的需要设置为1,每次事务commit都把redo日志fsync到硬盘上。

图。

innodb_flush_log_at_commit的可选值为0,1,2。

当值为0时,LOG buffer中的数据每1s写入os缓存并fsync,当值为2时,每次事务commit都把redo日志写入到os缓存,每1s再fsync到磁盘。

image.png

数据完整性

上文说Redo日志与Undo日志保证了数据的持久性和原子性,这个是Innodb层面的。因为MySQL是Server-engine架构,server层面需要使用binlog。

https://www.infoq.cn/article/M6g1yjZqK6HiTIl_9bex

在同时考虑Redo日志与binlog日志时就需要保证三个方面:

数据内容一致性

数据顺序一致性

效率

数据内容一致性

为什么?

如何做的?

自动为每个事务分配一个唯一的ID(XID)。

COMMIT会被自动的分成Prepare和Commit两个阶段。

Binlog会被当做事务协调者(Transaction Coordinator),Binlog Event会被当做协调者日志。

当实例从崩溃中恢复时,需要将活跃的事务从undo中提取出来,对于ACTIVE状态的事务直接回滚,对于Prepare状态的事务,如果该事务对应的binlog已经记录,则提交,否则回滚事务。

具体实现

image.png

以上的图片中可以看到,事务的提交主要分为两个主要步骤:

准备阶段(Storage Engine(InnoDB) Transaction Prepare Phase)

此时SQL已经成功执行,并生成xid信息及redo和undo的内存日志。然后调用prepare方法完成第一阶段,papare方法实际上什么也没做,将事务状态设为TRX_PREPARED,并将redo log刷磁盘。

提交阶段(Storage Engine(InnoDB)Commit Phase)

2.1 记录协调者日志,即Binlog日志。

如果事务涉及的所有存储引擎的prepare都执行成功,则调用TC_LOG_BINLOG::log_xid方法将SQL语句写到binlog(write()将binary log内存日志数据写入文件系统缓存,fsync()将binary log文件系统缓存日志数据永久写入磁盘)。此时,事务已经铁定要提交了。否则,调用ha_rollback_trans方法回滚事务,而SQL语句实际上也不会写到binlog。

2.2 告诉引擎做commit。

最后,调用引擎的commit完成事务的提交。会清除undo信息,刷redo日志,将事务设为TRX_NOT_STARTED状态。

PS:记录Binlog是在InnoDB引擎Prepare(即Redo Log写入磁盘)之后,这点至关重要。

由上面的二阶段提交流程可以看出,一旦步骤2.1中的操作完成,就确保了事务的提交,即使在执行步骤2.2时数据库发送了宕机。此外需要注意的是,每个步骤都需要进行一次fsync操作才能保证上下两层数据的一致性。步骤2的fsync参数由sync_binlog=1控制,步骤3的fsync由参数innodb_flush_log_at_trx_commit=1控制,俗称“双1”,是保证CrashSafe的根本。

数据顺序一致性

为什么?

因为mysql是多线程的,如果没有机制保证的话,在多个事务并发执行的情况下先写binlog不一定代表先在innodb中commit。

以下图Binlog与Innodb commit顺序不一致为例。

image.png

如上图,事务按照T1、T2、T3顺序开始执行,将二进制日志(按照T1、T2、T3顺序)写入日志文件系统缓冲,调用fsync()进行一次group commit将日志文件永久写入磁盘,但是存储引擎提交的顺序为T2、T3、T1。当T2、T3提交事务之后,若通过在线物理备份进行数据库备份(xtrabackup只备份Redo,不备份binlog),所以虽然在线物理备份记录的Binlog点位是T1、T2、T3都已经提交的点位,但是在恢复时因为T1在Innodb层未进行Commit,所以最终会丢失T1的数据。

如何做的

旧版本(性能差)

prepare_commit_mutex

在每次进行xa事务时,在prepare阶段事务先拿到一个全局的prepare_commit_mutex, 然后执行前面说的持久化(fsync)redo log与binlog,然后等fsync完了之后再释放prepare_commit_mutex,这样相当于串行化的效果虽然保证了binlog与redo log之间顺序一致性,但是却导致每个事务都需要一个fsync操作。

组提交

Binary Log Group Commit

组提交的目的是减少fsync的次数。

Binlog组提交的基本思想是,引入队列机制保证Innodb commit顺序与binlog落盘顺序一致。

前提

RedoLog本身就是组提交的。

2PC中的prepare阶段,会对redo进行一次刷盘操作(innodb_flush_log_at_trx_commit=1),这时候redo group commit的过程如下:

获取 log_mutex

若flushed_to_disk_lsn>=lsn,表示日志已经被刷盘,跳转5

若 current_flush_lsn>=lsn,表示日志正在刷盘中,跳转5后进入等待状态

将小于LSN的日志刷盘(flush and sync)

退出log_mutex

这个过程是根据LSN的顺序进行合并的,也就是说一次redo group commit的过程可能会讲别的未提交事务中的lsn也一并刷盘

https://segmentfault.com/a/1190000014810628

Binary Log组提交的实现

组提交整体过程

binlog prepare

InnoDB prepare

binlog commit(ordered commit)

--3.1 Stage #1: flushing transactions to binary log

--3.2 Stage #2: Syncing binary log file to disk

--3.3 Stage #3: Commit all transactions in order.

InnoDB commit

5.6

为了提高并发性能,肯定要细化锁粒度。MySQL 5.6 引入了 binlog 的组提交(group commit)功能,prepare 阶段不变,只针对 commit 阶段,将 commit 阶段拆分为三个过程:

flush stage:多个线程按进入的顺序将 binlog 从 cache 写入文件(不刷盘);

sync stage:对 binlog 文件做 fsync 操作(多个线程的 binlog 合并一次刷盘);

commit stage:各个线程按顺序做 InnoDB commit 操作。

其中,每个阶段有 lock 进行保护,因此保证了事务写入的顺序。

实现方法是,在每个 stage 设置一个队列,第一个进入该队列的线程会成为 leader,后续进入的线程会阻塞直至完成提交。leader 线程会领导队列中的所有线程执行该 stage 的任务,并带领所有 follower 进入到下一个 stage 去执行,当遇到下一个 stage 为非空队列时,leader 会变成 follower 注册到此队列中。

这种组提交的优势在于锁的粒度减小,三个阶段可以并发执行,从而提升效率。

5.7优化

延迟写 redo 到 group commit 阶段

MySQL 5.6 的组提交逻辑中,每个事务各自做 prepare 并写 redo log,只有到了 commit 阶段才进入组提交,因此每个事务的 redolog sync 操作成为性能瓶颈。

在 5.7 版本中,修改了组提交的 flush 阶段,在 prepare 阶段不再让线程各自执行 flush redolog 操作,而是推迟到组提交的 flush 阶段,flush stage 修改成如下逻辑:

收集组提交队列,得到 leader 线程,其余 follower 线程进入阻塞;

leader 调用 ha_flush_logs 做一次 redo write/sync,即,一次将所有线程的 redolog 刷盘;

将队列中 thd 的所有 binlog cache 写到 binlog 文件中。

这个优化是将 redolog 的刷盘延迟到了 binlog group commit 的 flush stage 之中,sync binlog 之前。通过延迟写 redolog 的方式,为 redolog 做了一次组写入,这样 binlog 和 redolog 都进行了优化。

Innobackupex为啥不需要备份Binlog?

首先看看什么时候需要binlog=>当实例从崩溃中恢复时,需要将活跃的事务从undo中提取出来,对于ACTIVE状态的事务直接回滚,对于Prepare状态的事务,如果该事务对应的binlog已经完整记录,则提交,否则回滚事务。

因此,XA Recover只对Prepare状态事务有影响。

如何做的

FLUSH TABLE WITH READ LOCK

Innobackupex中有一步是FLUSH TABLE WITH READ LOCK。

FTWRL主要包括3个步骤:

1.上全局读锁(lock_global_read_lock)

2.清理表缓存(close_cached_tables)

3.上全局COMMIT锁(make_global_read_lock_block_commit)。

FTWRL在备份中的作用=>阻塞新事务开启以及活跃事务提交,为获取一致性位点做准备。这个时候Redo日志与Binlog日志已经是一致的了。

FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS

把Log buffer中的Redo刷到硬盘上,然后Innobackupex拷走。

mysql 单机 数据_MySQL数据一致性-单机相关推荐

  1. mysql ibata文件_重装系统后,怎么调用之前mysql的数据_mysql

    重装系统后,如何调用之前mysql的数据 前提是:必须保留之前的数据库数据 在介绍此方法之前,提醒各位最好的转移数据的方法为: 在原来MYSQL服务器导出SQL文件,然后再在新的MYSQL服务器导入数 ...

  2. mysql 复制数据_MySQL快速复制数据库数据表的方法

    某些时候,例如为了搭建一个测试环境,或者克隆一个网站,需要复制一个已存在的mysql数据库.使用以下方法,可以非常简单地实现. 假设已经存在的数据库名字叫db1,想要复制一份,命名为newdb.步骤如 ...

  3. elastic如何和mysql同步数据_MySQL数据库之mysql 同步数据到 ElasticSearch 的方案

    本文主要向大家介绍了MySQL数据库之mysql 同步数据到 ElasticSearch 的方案 ,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助. MySQL Binlog 要通过 ...

  4. mysql丢失数据_MySQL数据丢失问题

    这两天遇到mysql宕机的问题,导致数据出现不一致的现象,结果发现有个特别重要的参数innodb_flush_log_at_trx_commit特别需要关注,默认情况下这个参数是1,即严格保证数据库的 ...

  5. mysql文本数据_mysql操作文本数据

    有时为了更快速地插入大批量数据或交换数据,需要从文本中导入数据或导出数据到文本. 一. 建立测试表,准备数据 首先建立一个用于测试的表示学生信息的表,字段有id.姓名.年龄.城市.薪水.Id和姓名不 ...

  6. go mysql 查询数据_MySQL常用语句之查询数据-Go语言中文社区

    简单查询: select [distinct] *| {字段名1,字段名2,字段名3, ...} from 表名 [where 条件表达式1] [group by 字段名 [having 条件表达式2 ...

  7. php验证mysql内数据_MySQL中数据类型的验证_MySQL

    CHAR char (M) M字符,长度是M*字符编码长度,M最大255. 验证如下: mysql> create table t1(name char(256)) default charse ...

  8. mysql 镜像数据_mysql官方镜像数据存储问题

    mysql官方镜像的Dockerfile中,有这么一条设置,即用了VOLUME这个关键字,同时后面设置了一个路径,/var/lib/mysql,这个路径是用来存储数据库的各种表的数据的. 这一条设置会 ...

  9. mysql 处理数据_MySQL数据库,如何处理重复的数据?

    前言 这是一个基本问题,这篇文章是我很早之前遇到的一种情况,后来在学习视频的时候又遇到了一次,因此给出一个总结.其实解决能否插入重复数据的问题,一般情况下是有两个思路,就像治水一样,第一个就是从源头, ...

最新文章

  1. 一个 零差评的 Python 内置库
  2. debounce实现 js_javascript防抖函数debounce详解
  3. *[topcoder]TheTree
  4. 每日一皮:当你开始研究一个新项目时是这样的吗?
  5. import _ssl # if we can‘t import it, let the error propagate
  6. 【Flink】Flink 从 1.9.1 版本 升级到 1.12.4 版本的 注意事项 以及 过程
  7. 不懂性能测试,被面试官挂了...
  8. 一次接口超时排查,花费了我两个星期。。
  9. php字符串里含有全角符号,php半角转全角字符函数
  10. 数学建模比赛需要那些c语言的知识,数学建模需要掌握哪些编程语言和技术
  11. Spring如何保证线程安全
  12. 如何把pdf文件变小一点?
  13. 2010年北京大学软件与微电子学院毕业生就业去向(官方不完全统计)
  14. 虚拟服务器实现方式,服务器实现虚拟主机的三种主要方式
  15. azkaban 报Error Chunking during uploading files to db
  16. VS Code 快捷键(中英文对照版)
  17. 智能车图像处理11-斜入十字补线
  18. java-数组常用api
  19. Anaconda,tensorflow,keras安装过程以及遇到的问题和解决方案
  20. BurpSuit在不同浏览器中配置代理

热门文章

  1. 创客匠人6月功能更新:服务商管理、直播、学员版APP全新上线
  2. 普通人如何创业,怎么迈出第一步?看完你就明白了丨国仁网络资讯
  3. Java学习_getProperty()方法初探
  4. 梦想照亮前程--新东方执行总裁陈向东的故事
  5. Huawei QOS
  6. 小明和小强都是张老师的学生,张老师的生日是M月N日
  7. 你的“差不多”,其实差很多
  8. 编写一个程序,绘制一个小球模拟平抛运动。
  9. 唐伯虎点秋香剧本精选------小强和旺财的诞生!
  10. deepin 服务器_深度Linux终于看到曙光,国内巨头华为使用的服务器就是使用深度系统 ......