mysql 单机 数据_MySQL数据一致性-单机
数据+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数据一致性-单机相关推荐
- mysql ibata文件_重装系统后,怎么调用之前mysql的数据_mysql
重装系统后,如何调用之前mysql的数据 前提是:必须保留之前的数据库数据 在介绍此方法之前,提醒各位最好的转移数据的方法为: 在原来MYSQL服务器导出SQL文件,然后再在新的MYSQL服务器导入数 ...
- mysql 复制数据_MySQL快速复制数据库数据表的方法
某些时候,例如为了搭建一个测试环境,或者克隆一个网站,需要复制一个已存在的mysql数据库.使用以下方法,可以非常简单地实现. 假设已经存在的数据库名字叫db1,想要复制一份,命名为newdb.步骤如 ...
- elastic如何和mysql同步数据_MySQL数据库之mysql 同步数据到 ElasticSearch 的方案
本文主要向大家介绍了MySQL数据库之mysql 同步数据到 ElasticSearch 的方案 ,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助. MySQL Binlog 要通过 ...
- mysql丢失数据_MySQL数据丢失问题
这两天遇到mysql宕机的问题,导致数据出现不一致的现象,结果发现有个特别重要的参数innodb_flush_log_at_trx_commit特别需要关注,默认情况下这个参数是1,即严格保证数据库的 ...
- mysql文本数据_mysql操作文本数据
有时为了更快速地插入大批量数据或交换数据,需要从文本中导入数据或导出数据到文本. 一. 建立测试表,准备数据 首先建立一个用于测试的表示学生信息的表,字段有id.姓名.年龄.城市.薪水.Id和姓名不 ...
- go mysql 查询数据_MySQL常用语句之查询数据-Go语言中文社区
简单查询: select [distinct] *| {字段名1,字段名2,字段名3, ...} from 表名 [where 条件表达式1] [group by 字段名 [having 条件表达式2 ...
- php验证mysql内数据_MySQL中数据类型的验证_MySQL
CHAR char (M) M字符,长度是M*字符编码长度,M最大255. 验证如下: mysql> create table t1(name char(256)) default charse ...
- mysql 镜像数据_mysql官方镜像数据存储问题
mysql官方镜像的Dockerfile中,有这么一条设置,即用了VOLUME这个关键字,同时后面设置了一个路径,/var/lib/mysql,这个路径是用来存储数据库的各种表的数据的. 这一条设置会 ...
- mysql 处理数据_MySQL数据库,如何处理重复的数据?
前言 这是一个基本问题,这篇文章是我很早之前遇到的一种情况,后来在学习视频的时候又遇到了一次,因此给出一个总结.其实解决能否插入重复数据的问题,一般情况下是有两个思路,就像治水一样,第一个就是从源头, ...
最新文章
- 一个 零差评的 Python 内置库
- debounce实现 js_javascript防抖函数debounce详解
- *[topcoder]TheTree
- 每日一皮:当你开始研究一个新项目时是这样的吗?
- import _ssl # if we can‘t import it, let the error propagate
- 【Flink】Flink 从 1.9.1 版本 升级到 1.12.4 版本的 注意事项 以及 过程
- 不懂性能测试,被面试官挂了...
- 一次接口超时排查,花费了我两个星期。。
- php字符串里含有全角符号,php半角转全角字符函数
- 数学建模比赛需要那些c语言的知识,数学建模需要掌握哪些编程语言和技术
- Spring如何保证线程安全
- 如何把pdf文件变小一点?
- 2010年北京大学软件与微电子学院毕业生就业去向(官方不完全统计)
- 虚拟服务器实现方式,服务器实现虚拟主机的三种主要方式
- azkaban 报Error Chunking during uploading files to db
- VS Code 快捷键(中英文对照版)
- 智能车图像处理11-斜入十字补线
- java-数组常用api
- Anaconda,tensorflow,keras安装过程以及遇到的问题和解决方案
- BurpSuit在不同浏览器中配置代理
热门文章
- 创客匠人6月功能更新:服务商管理、直播、学员版APP全新上线
- 普通人如何创业,怎么迈出第一步?看完你就明白了丨国仁网络资讯
- Java学习_getProperty()方法初探
- 梦想照亮前程--新东方执行总裁陈向东的故事
- Huawei QOS
- 小明和小强都是张老师的学生,张老师的生日是M月N日
- 你的“差不多”,其实差很多
- 编写一个程序,绘制一个小球模拟平抛运动。
- 唐伯虎点秋香剧本精选------小强和旺财的诞生!
- deepin 服务器_深度Linux终于看到曙光,国内巨头华为使用的服务器就是使用深度系统 ......