MySQL系统架构设计

news2024/11/27 0:44:39

MySQL

  • 一、MySQL整体架构
    • 1.1 SQL接口
    • 1.2 解析器 Parser
    • 1.3 查询优化器 Optimizer
      • 1.3.1 逻辑优化
      • 1.3.2 物理优化
      • 1.3.3 explain
    • 1.4 缓存 Cache
    • 1.5 存储引擎 Stroage Management
    • 1.6 一条查询SQL的执行流程
  • 二、缓存池(Buffer Pool)
    • 2.1 Buffer Pool 预读机制
    • 2.2 Buffer Pool free链
    • 2.3 Buffer Pool 空间管理
    • 2.4 Buffer Pool 脏页(Flush链)
  • 三、Redo Log
    • 3.1 Redo Log Buffer
    • 3.2 Redo Log Buffer 刷盘机制
  • 四、Undo Log
    • 4.1 Undo Tablespace
    • 4.2 相关参数
  • 五、Change Buffer
    • 5.1 Change Buffer缓存操作类型
    • 5.2 Change Buffer被 Merge 情况
  • 六、Doublewrite Buffer
    • 6.1 相关参数
  • 七、InnoDB 整体架构图

【MySQL系统架构设计】
【MySQL索引设计与选择】
【MySQL事务底层原理】

一、MySQL整体架构

在 MySQL 整体架构中,主要包括两个部分:

  1. MySQL Client:用于连接 MySQL 服务端,场景的有MySQL Shell、JDBC、.NET、Python等;
  2. MySQL Server:MySQL 服务端,主要分为几个核心模块;
    2.1 基础模块:授权认证、线程模型(处理客户端连接)、连接池、缓存等;
    2.2 SQL接口;
    2.3 SQL解析器;
    2.4 查询优化器;
    2.5 缓存;
    2.6 存储引擎:插件式设计,支持多种存储方式选择;
    2.7 系统文件:存储 MySQL 数据、索引、日志文件等;
    在这里插入图片描述

1.1 SQL接口

SQL接口主要用于接收客户端的DML、DDL、存储过程、视图、触发器等语句。

1.2 解析器 Parser

一个语法正确SQL语句,通过Parser解析器进行处理后,会被解析为一颗SQL语法树,如下:
在这里插入图片描述

1.3 查询优化器 Optimizer

一条SQL的执行方式(执行计划)有很多种方式,最终的执行计划是由 Optimizer 决定的,可以通过 explain 关键字来获取 SQL 语句的最终执行计划。

工作原理:根据 Parser 生成的解析树,产生多条执行计划(Execution Plan),最终选择一种最优的执行计划,进行 SQL 语句执行。在 MySQL Optimizer 中,默认采用的是基于开销的优化器,最优的执行计划,也就是开销最小的执行计划。

MySQL 的优化包括两种:逻辑优化、物理优化,运行流程如下:
在这里插入图片描述
不管是逻辑优化还是物理优化,都是对 Parser 生成的语法树进行修改,最终生成最优的执行计划。

1.3.1 逻辑优化

主要是通过关系代数对 SQL 语句进行一些等价替换,使得 SQL 执行效率更优。

  • 子查询优化:子查询合并
  • 等价谓词重写:如将in转化为or规则,status IN(1, 2) -----> status = 1 OR status = 2,LIKE优化,name LIKE 'mic%' ----> name >= 'mic' AND name < 'mid'
  • 条件简化:WHERE、HAVING、ON条件可能是由很多的表达式组成的,而这些表达式 在某些情况下存在一定的联系, 数据库可以利用等式和不等式的性质,把 WHERE、HAVING、ON条件简化。如:
    • 把HAVING条件并入到WHERE条件, 方便统一、集中化解子条件,节 约多次化解的时间。
    • 去除表达式中的冗余括号,减少语法分析时产生的AND和OR 树的层 次,比如 ((a AND b) AND (c AND d)) 简化为 a AND b AND c AND d
    • 常量传递,比如 col_1 = col_2 AND col_2 = 3 可以简化成 col_1 = 3 AND col_2 = 3
    • 表达式计算, 对可以求解的表达式进行计算,比如 WHERE col_1=1+2 转化为 WHERE col_1=3 。

1.3.2 物理优化

在生成逻辑查询计划后,查询优化器会进一步对查询树进行物理查询优化, 物理优化主要解决几个问题:

  1. 在单表扫描方式中,选择什么样的单表扫描方式是最优的
  2. 对于存在两个表连接时,那种连接方式最优
  3. 对于多个表连接,连接顺序有多种组合,那种连接顺序是最优的

物理查询优化一般分为两种

  • 基于规则的优化(RBO,Rule-Based Optimizer),这种方式主要是基于 一些预置的规则对查询进行优化。
  • 基于代价的优化(CBO,Cost-Based Optimizer,默认方式),这种方式会根据模型计算出各个可能的执行计划的代价,然后选择代价最少的那个。它会利用数据库里面的统计信息来做判断,因此是动态的。基于代价估算是基于CPU代价和IO代价这两个纬度来实现的。

总代价 = IO代价 + CPU代价

1.3.3 explain

在 MySQL 中,可以通过 explain 关键字查看 SQL 的执行计划,如下:
在这里插入图片描述

可以获取信息如上,每列意思为:

  • id:表的读取顺序。每一行记录代表一个表的执行计划,执行顺序如下:id不同,按照id方式递减方式执行;id相同,按照从上往下执行。
  • select_type:查询类型。可选值如下:
    • SIMPLE:建档的 SELECT 查询,不使用 union 及子查询;
    • PARMARY:最外层的 SELECT 查询;
    • UNION:UNION 中的第二个或随后的 SELECT 查询,不依赖于外部查询的结果集;
    • DEPENDENT UNION:UNION 中的第二个或随后的 SELECT 查询,依赖于外部查询的结果集;
    • SUBQUERY:子查询中的第一个 SELECT 查询,不依赖于外部查询的结果集;
  • table:表名,如果 SQL 语句中定义了别名,则展示表的别名。
  • partitions:分区。表示当前查询匹配记录的分区,对于未分区的表,返回 NULL。
  • type:表示当前 SELECT 查询数据表中的方式,以及查找数据行记录的大概范围。该列的取值优化程度如下:

最优 -> 最差
null -> system -> const -> eq_ref -> ref -> range -> index -> ALL

一般来说,需要保证查询语句type类型达到 range 基本,最好是 ref。

type说明优化建议
NULLMySQL优化器在优化阶段分解查询语句,在优化过程中就已经可以得到结果,那么在执行阶段就不用再访问表或索引。
systemsystem是const的特例,表中数据只有一条匹配时为system。
constconst出现在用 primary key(主键) 或 unique key(唯一键) 的所有列与常数比较时,优化器对查询进行优化并将其部分查询转化成一个常量。最多有一个匹配行,读取1次,速度非常快。
eq_refprimary key(主键)或 unique key(唯一键) 索引的所有构成部分被join使用 ,只会返回一条符合条件的数据行。
ref与eq_ref相比,ref类型不是使用primary key(主键) 或 unique key(唯一键)等唯一索引,而是使用普通索引或者联合唯一性索引的部分前缀,索引和某个值相比较,可能会找到符合条件的多个数据行。
range使用一个索引来查询给定范围的行,如通过in()、between、>、>=、< 等操作符进行查询。建议优化
index扫描全表索引。index是从索引中读取,所有字段都有索引。需优化
ALL全表扫描。需从磁盘中读取数据。需优化
  • possible_keys:表示当前 SELECT 可能使用到那些索引。但有些时候也会出现出现 possible_keys 列有结果,而 key=NULL ,这是因为此时表中数据不多,优化器认为查询索引对查询帮助不大,所以没有走索引查询而是进行了全表扫描。
  • key:表名当前 SELECT 实际采用那个索引。返回 NULL 表示未使用索引。
  • key_len:表示在索引里使用的字节数。通过 key_len 值,可以估算出具体使用了联合索引中的几列。
  • ref:表示在 key 列记录的索引中,SELECT 查询所用到的列或常量。可选值:const-常量、字段名,如user.name。
  • rows:表示当前 SELECT 大概需要读取并检测的数据行数。
  • filtered
  • Extra:顾名思义,这一列表明的是额外信息。这一列的取值对 SQL 优化非常有参考意义。可选值有:
    • NULL:被查询的列没有被索引覆盖,但 WHERE 条件是索引的前导列,需要通过 “回表” 动作来获取所有列数据;
    • Using index:被查询的列都是索引列(称为覆盖索引);
    • Using where:被查询的列没有被索引覆盖,WHERE 条件也并非索引的前导列;
    • Using where; Using index:被查询的列被索引覆盖,并且 WHERE 条件是索引列之一,但不是所有的前导列,也就是没有办法直接通过索引来查询到符合条件的数据;
    • Using index condition:被查询的列不完全被索引覆盖,WHERE 条件中是一个前导列的范围。
    • User temporary:表明需要通过创建临时表来处理查询结果。出现这种情况一般需要优化,创建临时表情况有distinct、group by、order by、子查询等;
    • Using filesort:使用 order by 时,MySQL 会对结果使用一个外部索引排序,而不是按索引次序从表中读取行。此时mysql会根据连接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下要考虑使用索引来优化的。

1.4 缓存 Cache

查询缓存,在 MySQL 8.0 已经移除该模块。

1.5 存储引擎 Stroage Management

表示数据如何存储、如何提取、如何更新等具体的实现,不同存储引擎的底层实现方式不同,因此会呈现不同存储引擎独特的功能和特点。

在 MySQL 中支持多种存储引擎,最常用的引擎是 MyISAM、InnoDB、Memory,可以根据实际的业务场景来选择使用不同的存储引擎。

  • MyISAM:写多读少,不支持事务,数据和索引分开存储,索引会存储一份数据。
  • InnoDB:支持事务,数据和索引存储在一个文件,聚簇索引(主键索引,如果没有主键索引,MySQL会默认生成一个 _rowid 为主键索引,如果存在, _rowid = id)会存储数据,非聚簇索引(除主键索引外,其他索引),不存储数据,通过主键索引进行 “回表” 获取数据。
  • Memory:基于内存存储。

MySQL 5.5 版本前默认存储引擎是 MyISAM,在5.5 版本后默认的存储引擎是 InnoDB,因为它在大多数情况下都提供更好的性能和可靠性。根据不同业务场景,我们可以选择不同存储引擎。

MyISAM

  • 读多写少:MyISAM 在读取性能上有一定的优势,适用于大多数读多写少的应用,比如博客、新闻网站等;
  • 全文搜索:MyISAM 支持全文搜索功能,适合需要进行全文搜索的应用,如搜索引擎;
  • 空间数据存储:MyISAM 提供了空间索引的支持,可以存储地理信息数据或空间数据;

InnoDB

  • 事务支持:InnoDB 支持事务ACID特性。事务是数据库保持数据完整性和一致性的关键;
  • 高并发写入:InnoDB 支持行级锁,对于高并发写入的应用,InnoDB 的性能更好;
  • 数据完整性:InnoDB 支持外键约束、主键约束等数据完整性控制功能,对于要求数据一致性和完整性的应用更合适;
  • 崩溃恢复:InnoDB 支持崩溃恢复功能(redo log、undo log、doublewrite log files),可以在数据库崩溃后进行恢复,确保数据不丢失;

1.6 一条查询SQL的执行流程

在这里插入图片描述

二、缓存池(Buffer Pool)

MySQL 除了使用 Memory 存储引擎以外,其他存储引擎最终都需要将数据存储到磁盘上。先假如我们需要对某个数据进行操作,步骤如下:

  1. 需先找到当前数据在磁盘中存储的位置;
  2. 将磁盘中的数据加载到内存中;
  3. 对数据进行修改;
  4. 将修改后的数据写入磁盘;

将数据写入磁盘的效率是非常低的,如果每次数据操作都重复上面的步骤,MySQL 性能是会存在非常大的性能瓶颈,那 MySQL 是怎么解决这个问题的呢?

Buffer Pool 概念由此产生。
在这里插入图片描述
用户操作数据,不直接和磁盘交互,而是和内存中的一块区域进行交互,该区域就叫做 Buffer Pool。具体操作步骤如下:

  1. 读取数据时,先判断数据是否存在 Buffer Pool,如果存在直接获取并返回,否则将磁盘数据读取到 Buffer Pool,然后返回;
  2. 修改数据时,先将数据读取到 Buffer Pool 中,然后修改 Buffer Pool 中对应的数据,并放入一块特定区域中,由 MySQl 后台线程将这特定区域的数据写入磁盘,这一块特定的区域叫 脏链

不管是查询、修改数据,都需要先将数据从磁盘读取到 Buffer Pool 中,那对于数据的一次读取操作,会将磁盘中的多少数据加载到 Buffer Pool 中呢?加入当前数据只占了15个字节,那一次读取操作,只会加载这15个字节数据吗?

很显然不是,磁盘I/O相对内存来说是非常慢的,特别是磁盘的随机读操作,产生的I/O次数更多。
所以这里也用到了 预读取 的概念,也就是说,当磁盘上的某块数据被读取时,根据局部性原理,很有可能它附近位置的数据马上也会被用到。所以,MySQL 在进行一次性读取时,会尽量多读取一些数据保存到 Buffer Pool 中,通过空间换时间的设计思想, 提升数据的IO效率。

InnoDB 为 MySQL 最常使用的存储引擎,后续都是围绕 InnoDB Stroage Management 进行分析。

2.1 Buffer Pool 预读机制

MySQL 设定了一个存储引擎从磁盘读取数据到内存的最小单位叫 页缓存(Page Cache)。InnoDB 中,Page Cache 默认大小为 16kb,既一次数据读取操作,会从磁盘加载 16kb 大小的数据到 Buffer Pool 中,可通过参数 innodb_page_size 将页的大小设置为4K、8K、16K进行调整。
每个Page Cache 会对应一个描述数据,这个描述数据本身也是一块数据,它包含 Page 所属的表空间、数据页编号、数据页在Buffer Pool中的地址等信息。在 Buffer Pool 中,每个 Page Cache 的描述数据放在最前面,Page Cache放在后面。结构如下:
在这里插入图片描述

操作系统也存在 页缓存 的概念,默认大小为 4kb

在 MySQL InnoDB 中,通过将数据存储分为不同级别,如下:

  • 行(Row):数据行。
  • 页(Page):为 InnoDB 存储引擎磁盘管理的最小单元,每页大小默认为 16kb。
  • 区(Extent):64个相邻的 Page 称为一个 Extent。默认情况下 Extent 大小为 16kb * 64 = 1024kb = 1MB
  • 段(Segment):Segment 由一个或多个 Extent 组成,在 Segment 中不要求区与区之间是相邻的。段是数据库中的分配单位,不同类型的数据库对象以不同的段形式存在。当创建数据表、索引的时候,就会相应创建对应的段,比如创建一张表时会创建一个表段,创建一个索引时会创建一个索引段。
  • 表空间(Tablespace):Tablespace 是一个逻辑容器,存储的对象是 Segment,在一个 Tablespace 中可以有一个或多个 Segment,但是一个 Segment 只能属于一个 Tablespace。数据库由一个或多个 Tablespace 组成,表空间从管理上可以划分为系统表空间、用户表空间、撤销表空间、临时表空间等。在 InnoDB 中存在两种表空间的类型:共享表空间独立表空间。如果是共享表空间就意味着多张表共用一个表空间。如果是独立表空间,就意味着每张表有一个独立的表空间,也就是数据和索引信息都会保存在自己的表空间中。独立的表空间可以在不同的数据库之间进行迁移。可通过命令 show variables like 'innodb_file_per_table'; 查看当前系统启用的表空间类型。目前最新版本已经默认启用独立表空间。InnoDB把数据保存在表空间内,表空间可以看作是InnoDB存储引擎逻辑结构的最高层。本质上是一个由一个或多个磁盘文件组成的虚拟文件系统。InnoDB用表空间并不只是存储表和索引,还保存了回滚段、双写缓冲区等。

由此可见,InnoDB 中的存储结构如下:
在这里插入图片描述
InnoDB 使用两种预读算法来减少磁盘I/O,提高系统性能,默认采用线性预读

  • 线性预读 linear read-ahead:以 Extent 为单位,将下一个 Extent 提前读取到 Buffer Pool 中。
  • 随机预读 random read-ahead:随机预读以 Page 为单位,将当前 Extent 中剩下的 Page 提前读取到 Buffer Pool 中。不建议使用随机预读,会降低 MySQL 效率。

2.2 Buffer Pool free链

上面说到,每个 Page Cache 存放在 Buffer Pool 中都会对应一个描述数据。在 MySQL 中,将所有 空闲的缓存页的描述数据块 所组成的双向链表定义为 free链。由此可知,free 链具有如下特征:

  1. 双向链表;
  2. 每个节点为空闲的缓存页对应的描述数据块;
  3. 当缓存页存在数据时,将从 Free 链中移除;

在缓存页的描述数据区中存在两个指针:free_prefree_next ,分别指向自己的上一个 free链节点,以及下一个 free链节点。当需要操作的数据在 Buffer Pool 中不存在时,会先将其存在的 Page 缓存到 Buffer Pool 中,然后再对齐进行操作,那整个过程是怎样的呢?

  1. 判断当前操作数据是否存在 Buffer Pool 中(通过 表空间号+数据页号 判断);
  2. 存在,直接进行操作;
  3. 不存在,从 free链 中获取一个描述数据块;
  4. 将 Page 写入当前描述数据块对应的 Page Cache 中;
  5. 将 Page 相关的一些描述数据写入当前描述数据块中;
  6. 最后将当前描述数据块从 free 中移除,并把当前缓存页写入一个哈希表中;

上面提及到的哈希表结构如下:

  • key -> 表空间号 + 数据页号;
  • value -> 缓存页地址;

2.3 Buffer Pool 空间管理

Buffer Pool 为系统内存,默认大小为 128M,可通过参数 innodb_buffer_pool_size 调整 Buffer Pool 大小,官方建议实际生产中,Buffer Pool 大小可以配置为机器内存的 50% ~ 75% 左右。

Buffer Pool 的大小设置合理,对整个 MySQL 性能也是具体非常大的优化的,涉及到相关参数如下:

# 缓存区域的大小,建议配置为机器内存的 50% ~ 75% 左右
innodb_buffer_pool_size=1024M
# 在mysql 5.7.5之前,buffer pool的大小只能在mysql启动之前通过innodb_buffer_pool_size设置,在mysql运行过程中是不允许进行修改的。
# 在mysql5.7.5及之后的版本中支持运行过程中修改innodb_buffer_pool_size的值,每次修改都需要重新向服务器申请连续的内存空间,把旧的
# buffer pool数据放到新的buffer pool中,这样的操作是特别费时的。innodb使用chunk为单位来申请连续的内存空间,一个buffer pool由多个
# chunk组成,每个chunk里面存放控制块和缓存页对,一个chunk的默认大小是128M。这样在运行过程中修改buffer pool的大小,只用增加或者删
# 除chunk的数量,使chunk的累计大小等于新的buffer pool值即可达到修改的效果。
# 
# 配置chunk值需要注意的点:
#     innodb_buffer_pool_size的值必须是innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances的整数倍,为了保证每个buffer pool
#     的chunk数量相同;当innodb_buffer_pool_size不是他们两乘积的整数倍时,会自动把innodb_buffer_pool_size的值设置为他们乘积的整数倍。
innodb_buffer_pool_chunk_size=128M
# 当buffer pool比较大的时候(超过1G),innodb会把buffer pool划分成几个instances,这样可以提高读写操作的并发,减少竞争。读写page都使用hash函数分配给一个instances。把需要缓冲的数据hash到不同的缓冲池中,这样可以并行的内存读写。innodb_buffer_pool_instances 参数显著的影响测试结果,特别是非常高的 I/O 负载时。
innodb_buffer_pool_instances=8

既然 Buffer Pool 是一块内存区域,那内存是空间大小总是有上限的,数据不可能一直存储在 Buffer Pool 中,所以,可以想象到,存储在 Buffer Pool 中的数据肯定会存在一个淘汰机制,常见的数据淘汰算法有LRU(最久未使用)、LFU(最少使用),辣么 Buffer Pool 采用什么方式进行数据淘汰呢?

Buffer Pool 内存结构整体采用 LRU 算法进行数据淘汰,但相比 LRU 算法做了一些升级优化,将 Buffer Pool 的 LUR 链表拆分为两部分:冷数据链(Old Sublist)、热数据链(Old Sublist),通过分割线 Midpoint 对 Buffer Pool 的冷热数据进行分离。整体结构如下:
在这里插入图片描述

如上图,默认情况下,冷热数据空间占比为 New Sublist : Old Sublist = 5 : 3 ,可通过参数 innodb_old_blocks_pct=37 进行调整。

注意:参数 innodb_old_blocks_pct 代表 Old Sublist 所占用比率,值区间为 5-95 之间。
值越小,冷数据区没有被访问的数据淘汰速度越快。
一般生产的机器,内存比较大。我们会把innodb_old_blocks_pct 值调低,防止热数据被刷出内存。

Buffer Pool 的 LRU 算法整体原理如下:

  • 所有新数据页加入 Buffer Pool 时,一律先放入 Old 区的 Head;
  • 默认在 1s(可通过参数innodb_old_blocks_time=1000进行调整,毫秒) 后,如果该缓存页再次被访问,则会移动到 New 区的 Head位置;

在这里插入图片描述

2.4 Buffer Pool 脏页(Flush链)

当我们在执行增删改的时候,会先访问 Buffer Pool 中是否存在当前数据,如果不存在,那么必然会基于 free链表找到一个空闲的缓
存页,然后读取到缓存页中,如果存在,则直接对其进行操作。在 MySQL 中,为了提供效率,数据的任何操作都是基于 Buffer Pool 的,当我们更新了 Page Cache 中的数据后,就会导致缓存页数据与磁盘存储数据不一致,我们将被修改过的缓存页称为脏页

为了根据便捷将脏页的数据刷到磁盘中,MySQL 将所有脏页组成一个 Flush链,Flush链的也是由描述数据块中的两个指针(flush_preflush_next)组成的双向链表,那什么时候触发将 Flush链中的脏页数据刷新到磁盘中?

  1. 后台线程定时执行刷新;
  2. Buffer Pool 内存不足时(冷热数据区不足都会触发刷新);
  3. 数据库正常关闭;
  4. Redo Log写满;

三、Redo Log

在进行 MySQL 数据修改时,都是先修改 Buffer Pool 中数据,然后将存在修改的 Page Cache 加入脏页,最后由后台线程进行刷盘,整体流程如下:
在这里插入图片描述
我们都知道,MySQL 是支持ACID特性的,那在整个过程中,数据都是由后台线程刷新到磁盘,假如在进行刷盘之前数据库宕机,那内存中修改的持久化数据是不是就丢失了???

为了处理上面这种异常情况,MySQL 引入了 Redo Log 日志机制。MySQL 在修改 Buffer Pool 中数据记录是,会同步向 Redo Log 中写入一条记录,如果数据库宕机后,存在未同步到磁盘的数据,在后续数据库重启时,会从 Redo Log 中读取之前已经进行过的操作,然后将这些操作重新再内存中执行一遍,最后由后台线程进行刷盘,完成数据崩溃恢复。这也是事务ACID特性中 D(Durability,持久性)的保障机制

3.1 Redo Log Buffer

基于以上流程,MySQL 在修改 Buffer Pool 中数据记录是,会同步向 Redo Log 写一条记录,如果每一次修改,都需要和磁盘进行一次 IO 那将非常影响 MySQL 效率,于是,MySQL 在这基础上引入了一个 Redo Log Buffer 机制,整体流程如下:
在这里插入图片描述

Redo Log Buffer 也是存在大小的,默认为 16MB,可通过参数 innodb_log_buffer_size=16MB 变量来调整。

Redo Log Buffer空间越大,可以容纳更大的事务操作,而无需将数据直接写入到 Redo 磁盘日志中,减少了与磁盘的交互。所以,如果事务中如果有大量的DML操作,可 以考虑增大 Log Buffer 的值,减少磁盘 IO 从而提升效率。

3.2 Redo Log Buffer 刷盘机制

在将任何内存中的数据刷新到磁盘,都需要经历如下节点:内存 -> 操作系统页缓存 -> 磁盘,所以,MySQL 提供了三种 Redo Log Buffer 刷盘机制,来满足不同业务场景,可通过参数 innodb_flush_log_at_trx_commit 进行设置,具体如下:

  1. innodb_flush_log_at_trx_commit=0:将每秒一次地将 Redo Log Buffer 中的数据写入 Redo Log File 中,并且 Redo Log File 的 flush 操作同时进行。该模式下,在事务提交的时候,不会主动触发写入磁盘的操作。这个策略的性能是最佳的,但是会存在 1s 的数据丢失。
  2. innodb_flush_log_at_trx_commit=1:每次事务提交时 MySQL 都会把 Redo Log Buffer 的数据写入 Redo Log File,并且调用 flush 操作刷新到磁盘中去。这个策略能保证强一致性,也是InnoDB默认的配置,为的是保证事务的ACID特性。
  3. innodb_flush_log_at_trx_commit=2:每次事务提交时 MySQL 都会把 Redo Log Buffer 的数据写入 Redo Log File。但是 flush 操作并不会同时进行,由后台线程每秒执行一次 flush 操作,交由操作系统保证数据刷新到磁盘。这种策略,如果操作系统出现崩溃,也可能会存在 1s 的数据丢失,当相比 0 这种策略,数据丢失概率更小。
    在这里插入图片描述

四、Undo Log

MySQL InnoDB是支持事务回滚(ACID中的Atomiciy,原子性),一个事务要么全部执行,要么全部失败。那当失败时,MySQL 通过什么来进行回归呢??

在 MySQL InnoDB中,任何数据的修改前,都需先记录修改前数据,用于后续事务回滚操作,我们将记录修改前数据定义为 Undo Log。引入 Undo Log 后数据修改流程如下:
在这里插入图片描述

MySQL Undo Log存储的信息主要有:

  1. 修改前的数据值:用于数据回滚;
  2. 修改后的数据值:如果事务执行了更新、插入或删除等操作,Undo Log 也会记录新值,以便在回滚时撤销这些更改;
  3. 事务元数据:每个 Undo Log 记录都会包括与事务相关的信息,如事务ID、事务的状态(开始、提交、回滚等)以及其他元数据。

在 MySQL 官网描述中,Undo Log 主要作用除了用于支持事务 rollback,保证原子性,还用于支持事务的 MVCC (多版本并发控制)机制。MVCC 允许多个事务同时访问相同的数据表,每个事务都能看到自己的数据版本,而不会互相干扰。如果事务需要回滚,Undo Log 中的旧值信息将被用来还原数据到事务开始之前的状态。

需要注意的是,Undo Log是存储在磁盘上的,但在事务执行期间,它的一部分可能会暂时存储在内存中的Undo Log Buffer中,以提高性能。在事务提交之后,Undo Log中的数据将被清理或重用。

4.1 Undo Tablespace

在 MySQL 中,将 Undo Log 存储的内容也包括一部分数据,所以在整体架构设计时,定义了一个组件,用于 Undo Log 日志的管理、存储、清理等,这个组件为 Undo Tablespace。

Undo Tablespace在MySQL数据库中扮演着重要的角色,主要用于以下几个方面:

  • 用于回滚:当一个事务需要回滚到之前的状态时,使用 Undo Tablespace 中的数据来还原数据到事务开始之前的状态。
  • 多版本并发控制 (MVCC):MySQL通过 Undo Tablespace 中的数据来支持 MVCC,允许多个事务同时访问相同的数据表,每个事务都能看到自己的数据版本,从而提高了并发性能。
  • 垃圾收集:当事务提交或回滚后,Undo Tablespace中的数据可能会变得无效。MySQL会定期进行垃圾收集,回收不再需要的 Undo 数据,以释放空间。
  • 长事务处理:长时间运行的事务可能导致 Undo Tablespace 中的数据积累,因此它需要足够的空间来存储这些数据。管理Undo Tablespace的大小对于处理长事务至关重要。

4.2 相关参数

参数说明默认值
innodb_undo_tablespaces指定InnoDB Undo Tablespace的个数,不支持后续修改。默认值为0,表示不独立设置 undo 的 tablespace,默认记录到 ibdata 中;否则,则在undo目录下创建这么多个undo文件(每个文件的默认大小为10M)。最多可以设置到126。例如假定设置该值为4,那么就会在mysql的data目录下创建命名为 undo001~undo004 的 undo tablespace 文件0
innodb_undo_logs指定InnoDB引擎中Undo Log的数量,每个Undo Log用于存储不同的事务数据128
innodb_max_undo_log_size控制每个Undo Log文件的最大大小,当Undo Log文件达到这个大小时,会触发回收操作1GB
innodb_undo_log_truncateundo是否加密OFF
innodb_undo_directory指定Undo Log文件的存储目录。如果未设置,Undo Log文件将存储在数据目录中。

五、Change Buffer

在之前的数据修改流程中,MySQL InnoDB 的 Buffer Pool 会缓存磁盘中的数据页,所以当我们在进行数据修改的时候,会先从 Buffer Pool 中通过表空间号+数据页号查找对应数据,如果数据存在,就直接修改,并把修改后的数据添加到 Flush 链表中,等待刷新到磁盘。如果在数据修改的时候,对应的数据页不存在,那么就会先从磁盘中加载数据到 Buffer Pool,然后进行修改,执行之前流程。

但是,这种对于写多读少的场景,会产生大量的磁盘IO,即会存在很多数据都不存在Buffer Pool中,会产生大量的磁盘IO。MySQL基于以上场景,设计了一个 Change Buffer 来优化,目的是在写多读少的情况下,降低磁盘IO交互,提高效率。

Changer Buffer 是对 非唯一性普通索引 数据不在缓冲区中,但是又要对数据进行修改操作,在不影响数据一致性的前提下,InnoDB 不会将数据加载到 Buffer Pool 中,而是将更新操作缓冲到 Change Buffer 中,最后再某一时刻进行Merge,延迟更新,从而减少和磁盘IO次数。

Change Buffer 也是属于 Buffer Pool 中的一块内存区域,可通过参数 innodb_change_buffer_max_size=25 设置,默认为 Buffer Pool 大小25%,最大可设置为 50%。

  • 当在系统中存在大量插入,更新和删除操作时,可以增大 innodb_change_buffer_max_size,以提高系统的写入性能。
  • 当在系统中有大量查询操作时,可以减小 innodb_change_buffer_max_size,以减少 Buffer Pool 中数据页的淘汰的概率,提高系统的读取性能。
  • innodb_change_buffer_max_size 设置是动态的,它允许修改设置而无需重新启动服务器

Change buffer为什么只针对【非唯一普通索引】数据修改??
因为如果是唯一性索引,InnoDB在修改的时候,必须要去校验这个数据是否违反唯一性约束条件,从而直接将数据直接加载到 Buffer Pool 中,不会走 Change Buffer 逻辑。

5.1 Change Buffer缓存操作类型

Change Buffer 在 MySQL5.5 之后可以支持新增、删除、修改的写入,对于受 I/O 限制的操作(大量DML、如批量插入)有很大的性能提升价值。但是对于一些特定的场景,可以通过修改参数 innodb_change_buffering 来变更 Change Buffer 支持的类型。

  • all :默认值,缓冲区插入,删除和清除。
  • none:不缓存任何操作;
  • inserts:插入操作;
  • deletes:删除标记操作;
  • changes:插入、删除标记操作;
  • purges:后台发生的物理删除操作;

5.2 Change Buffer被 Merge 情况

上面提及到的,针对 非唯一性普调索引 的数据操作,会先将更新写入 Change Buffer 中,最后再某一时刻进行 Merge,那什么情况下会触发 Merge ???

  • 读取Change buffer中记录的数据页时,会将 Change buffer 合并到 Buffer Pool 中,然后被刷新到磁盘;
  • 当系统空闲或者 slow shutdown 时,后台master线程发起merge;
  • Change Buffer 的内存空间用完,后台master线程会发起merge;
  • Redo Log写满(也会触发Flush链刷盘);

六、Doublewrite Buffer

MySQL InnoDB 的 Page Cache 默认大小为 16k,但是正常操作系统 Page 为 4k,所以会存在 16K 只写入了一部分的极端情况,如当 InnoDB 在进行数据页的写入操作时,磁盘挂了,就可能导致 16k 只写了一部分情况,产生页断裂,导致数据部分失效,这种失效是无法回滚的,所以为了避免这种情况,引入了 Doublewrite Buffer。

Doublewrite Buffer 包括两个部分:

  1. 内存中的一块缓冲区 Doublewrite Buffer,大小为2MB;
  2. 磁盘文件 Doublewrite Buffer Files,为物理磁盘上共享表空间中连续的128个页,即2个区(extent),大小同样为2MB;

在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过 memcopy 函数将脏页先复制到内存中的 doublewrite buffer,之后通过doublewrite buffer再分两次每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用 fsync 函数,同步磁盘,避免缓冲写带来的问题。在这个过程中,因为 doublewrite 页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成 doublewrite 页的写入后,再将doublewritebuffer中的页写入各个表空间文件中,此时的写入则是离散的。所以当进行故障恢复的时候,InnoDB 会去检查 Doublewrite Buffer 的页和本来位置页的内容, 如果不一致,会从 Doublewrite Buffer 中进行恢复,如果 Doublewrite Buffer 中的页也不完整,会进行丢弃。

主要流程如下:
在这里插入图片描述

6.1 相关参数

参数说明默认值
innodb_doublewrite是否启用开关,可选值:on / offon
innodb_doublewrite_batch_size批量写入的页数。此变量用于高级性能调整。默认值应该适合大多数用户,0~2560
innodb_doublewrite_dirdoublewrite buffer files目录,如果未指定,则默认为数据目录
innodb_doublewrite_filesdoublewrite buffer files文件数量默认情况下,为每个缓冲池实例创建两个双写文件,缓冲池实例的数量由 innodb_buffer_pool_instances 控制
Innodb_dblwr_pages_written写的总的页数
innodb_dblwr_writes实际写入的次数

Innodb_dblwr_pages_written : innodb_dblwr_writes 可判断当前数据库写入压力,当值远远小于 64:1 时,表明压力并不高。

七、InnoDB 整体架构图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1042439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JVM】运行时数据区之方法区——自问自答

开局从康师傅那里借图几张 线程共享与私有 《Java虚拟机规范》中明确说明:“尽管所有的方法区在逻辑上是属于堆的一部分&#xff0c;但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。” 但对于HotSpotJVM而言&#xff0c;方法区还有一个别名叫做Non-Heap(非堆)&#…

React项目中如何实现一个简单的锚点目录定位

小册 这是我整理的学习资料&#xff0c;非常系统和完善&#xff0c;欢迎一起学习 现代JavaScript高级小册 深入浅出Dart 现代TypeScript高级小册 linwu的算法笔记&#x1f4d2; 前言 锚点目录定位功能在长页面和文档类网站中非常常见,它可以让用户快速定位到页面中的某个…

Pridwen: Universally Hardening SGX Programs via Load-Time Synthesis【ATC`22】

目录 摘要引言性能贡献 背景英特尔SGXSGX的异常SGX侧通道WebAssembly&#xff08;Wasm&#xff09;Wasm中的内存安全PRIDWEN和Wasm 概述场景威胁模型目标适应性证明性可扩展性 架构 标题&#xff1a;Pridwen: Universally Hardening SGX Programs via Load-Time Synthesis 作者…

系统学习Mysql

1.select语句 关键字执行顺序&#xff1a; 1.from 2.where 3.group by 4.select 5.having 6.order by 7.limit SQL 语句执行顺序如下&#xff1a; FROM: 指定要查询的表或子查询&#xff0c;可以包含 JOIN、WHERE 子句过滤等。 WHERE: 对 FROM 子句指定的表或子查询进行限制和…

OpenCV之直线曲线拟合

直线拟合fitLine void fitLine( InputArray points, OutputArray line, int distType,double param, double reps, double aeps ); points:二维点的数组或vector line:输出直线,Vec4f (2d)或Vec6f (3d)的vector distType:距离类型 param:距离参数 reps:径向的精度参数 a…

Tomcat Takeover

靶场介绍 蓝队靶场练习之Tomcat Takeover 场景介绍 我们的 SOC 团队在公司内部网的一台 Web 服务器上检测到可疑活动。为了更深入地了解情况&#xff0c;该团队捕获了网络流量进行分析。此pcap文件可能包含一系列恶意活动&#xff0c;这些活动已导致Apache Tomcat Web服务器…

Cairo介绍及源码构建安装(1)

一、简介 Cairo是一个支持多个输出设备的2D图形库。目前支持的输出目标包括X Window System、win32、图像缓冲区、PostScript、PDF和SVG。实验后端包括OpenGL、Quartz和XCB文件输出。Cairo旨在在所有输出媒体上产生一致的输出&#xff0c;同时利用可用的显示硬件加速&#xff…

基于 ESP32-C2 的 Wi-Fi/BLE 和 LoRa 极低成本无线组网方案

在物联网高速发展的今天&#xff0c;Wi-Fi 和 LoRa 作为近距离和超远距离通信技术&#xff0c;均有其各自的典型应用场景&#xff0c;在各自应用领域都取得了卓越的成就。Wi-Fi 和 LoRa 技术各具优势&#xff0c;在很多场景需求中&#xff0c;如果将两者结合&#xff0c;一方面…

自动化测试如何落地,一篇搞定

前言 前段时间面试了某零售电商企业的测试经理岗位&#xff0c;面试官当时提了这样一个问题&#xff1a;我们这边测试团队开展自动化测试工作将近一年了&#xff0c;但目前还未看到明显的对测试过程或者质量的改善效果。如果是你&#xff0c;你会如何做&#xff1f; 自动化测…

计算机算法分析与设计(4)---矩阵连乘问题(含C++代码)

文章目录 一、概述1.1 矩阵乘法1.2 穷举法1.3 动态规划 二、代码编写2.1 例题分析2.2 代码 一、概述 1.1 矩阵乘法 1. 矩阵相乘&#xff0c;前一个矩阵的列数需等于后一个矩阵的行数。相乘得到的新矩阵&#xff0c;其行数由前一个矩阵决定&#xff0c;其列数由后一个矩阵决定。…

可视化工具Datart踩(避)坑指南(4)——丢失的精度

作为目前国内开源版本最好用的可视化工具&#xff0c;Datart无疑是低成本高效率可供二开的可视化神兵利器。当然&#xff0c;免费的必然要付出一些踩坑的代价。本篇我们来讲一讲可视化工具Datart踩&#xff08;避&#xff09;坑指南&#xff08;4&#xff09;之丢失的精度。 版…

python -文件相关操作

文章目录 前言python -文件相关操作1. 读取文件1.1. 读取整个文件内容1.2. 读取文件的一行内容1.3. 将文件的内容按行存储到一个列表中 2. 写入文件3. 删除文件4. 追加文件5. 遍历文件5.1. 使用 os 模块 遍历文件5.2. # 使用 glob 模块 遍历文件5.3. 使用os.listdir() 函数遍历…

C语言——运算符

C用运算符表示算术运算。 C没有指数运算符&#xff0c;不过&#xff0c;C的标准数学库提供了一个pow()函数用于指数运算。 基本运算符 赋值运算符&#xff1a; 变量名变量值 从右到左 左值和变量名的区别&#xff1a; 变量名是一个标识符的名称&#xff0c;左值是一个可变…

SpringBoot+MinIO8.0开箱即用的启动器

一、代码拉取及安装 1.码云地址 https://gitee.com/qiangesoft/rdp-starter/tree/master/rdp-starter-minio 2.本地安装 代码接入 1.引入依赖 <dependency><groupId>com.qiangesoft.rdp</groupId><artifactId>rdp-starter-minio</artifactId&g…

国密国际SSL双证书解决方案,满足企事业单位国产国密SSL证书要求

近年来&#xff0c;为了摆脱对国外技术和产品的依赖&#xff0c;建设安全的网络环境&#xff0c;以及加强我国对网络信息的安全可控能力&#xff0c;我国推出了国密算法。同时&#xff0c;为保护网络通信信息安全&#xff0c;更高级别的安全加密数字证书—国密SSL证书应运而生。…

如何办一份有价值的企业内刊/报纸?向《华为人》学习就够了

前两天有一个朋友联系华研荟&#xff0c;说他是今年大学毕业加入了一个中型公司&#xff0c;他学的是企业管理&#xff0c;在公司人力资源部门工作。上周老板说公司要办一份自己的内刊&#xff0c;这个工作由人力资源部负责&#xff0c;而人力资源经理就把这个活交给她了。 她…

800G时代来临,千兆光模块万兆光模块还有用吗?

随着科技的不断进步&#xff0c;网络传输速度的需求也越来越高&#xff0c;特别是在云计算、人工智能、物联网等领域&#xff0c;对网络传输速度的要求越来越高。近年来&#xff0c;千兆光模块和万兆光模块已经成为了网络传输的主要手段&#xff0c;但随着800G时代的到来&#…

如何正确使用MySQL的索引呢?

前言: 📕作者简介:热爱编程的小七,致力于C、Java、Python等多编程语言,热爱编程和长板的运动少年! 📘相关专栏Java基础语法,JavaEE初阶,数据库,数据结构和算法系列等,大家有兴趣的可以看一看。 😇😇😇有兴趣的话关注博主一起学习,一起进步吧! 一、索引使用…

掌握这些技巧,轻松批量压缩视频大小

如果您需要批量压缩视频文件的大小&#xff0c;可以借助固乔科技官网提供的固乔剪辑助手软件。下面我们将详细介绍如何使用该软件实现这一目标。 1. 进入固乔科技官网&#xff0c;下载并安装固乔剪辑助手软件。这款软件支持Windows和Mac操作系统&#xff0c;可以方便地在官网上…

Android布局转图片Bitmap

最近再写一个PDA蓝牙连接打印机打印标签&#xff08;包含商品名、原价、现价、尺寸等等...&#xff09;这就需要自己布局一个view样式&#xff0c;转换成bitmap&#xff0c;然后用打印机打印出来。 先看图&#xff1a; 下面事layout布局转bitmap的方法。 网上很多介绍View转b…