概述
目录
Mysql 架构体系拆解、设计剖析
页的数据结构
页内记录维护
顺序保证
插入策略
页内查询
Mysql 存储引擎(最常用InnoDB为例) 原理拆解、设计剖析
InnoDB内存管理宗旨
LRU内存淘汰算法
Mysql 事务实现 原理拆解、设计剖析
Mysql事务基本概念
事务特性ACID
并发问题
隔离级别
Mysql事务实现机制
Mysql InnoDB 事务管理机制 ------- MVCC
undo log 事务回滚
redo log 事务固化
Mysql 锁实现 原理拆解、设计剖析
InnoDB锁种类
InnoDB加锁过程
Mysql 架构体系拆解、设计剖析
Mysql数据都是 以页(page)为单位 去做内外层交换或者刷新取数的,所以页是怎么划分,怎么管理的呢?
页的数据结构
页头:主要记录页的左右兄弟页面指针,还记录页面空间使用情况。(页面的控制信息,共占56个字节)。页头是双向指针。
虚记录:最小虚记录比页内最小主键还小;最大虚记录比业内最大主键还大。谈到mysql主键,就是聚簇索引,聚簇索引又是什么呢,数据结构和数存在一起
记录堆:行记录存储区,包括有效记录和已删除记录两种
自由空间链表:把被删除的记录链接起来的链表,为了方便找到被删除的记录,清理,节约空间
未分配空间:页面未使用的空间
页尾:占8个字节,存储页面的校验信息
页内记录维护
Mysql InnoDB用 聚簇索引做主键索引。主键索引为B+ Tree。聚簇索引是Data和索引存在一起,根据索引的key得到一行记录,Data是按照索引的结构有序存储的。
-
顺序保证
Mysql的顺序保证 选用的是 逻辑有序。逻辑有序就是 每次一条新数据都给个指针去指向相邻的数据,这样的话插入就很快,但是读取数据时因为是乱序,无法用二分法查找,得遍历查找,所以涉及到后面的页内查询的方法。所以逻辑有序就是页内通过一条单向链表把数据链接起来。 物理有序,就是每次插入时,已有数据都要按需求移动位置,但是查询的时候因为是按顺序放的,所以二分查询的话就会比较快。 所以,逻辑有序就是写的快,读的慢,物理有序就是 写的慢,读的快。
所以,Mysql的顺序保证就是1.页内通过一条单向链表来把数据连接起来 2.页与页之间通过 页头双向指针 联系起来。
-
插入策略
插入的空间有两个选择,自由空间链表和未使用空间。Mysql优先使用自由空间链表,充分利用空间来存储有效数据,MongoDB偷懒,拿到一块用一块,不管不顾。Mysql同样也需要定期清理空间,因为删除记录会残留碎片。
-
页内查询
页内查询,逻辑有序用遍历,物理有序用二分查找。但是二分查找的话,因为每条记录是不一样的大小,所以不能根据size去二分查找。所以不论是逻辑有序还是物理有序都不可以用二分查找。
所以有了 SLOT 槽。根据页内设置槽的数量和大小,每个slot指向一个记录。Slot是一堆连续的内存,把整个链表根据slot数量拆分为多个sub-list。每个slot指向一个记录即每个sub-list的头 。Slot同来帮助我们实现一个近似的二分查找。
Mysql的页内查询就是 用Slot来存放分链表,二分查找Slot,锁定部分数据,再对该部分数据进行遍历查找。
Mysql 存储引擎(最常用InnoDB为例) 原理拆解、设计剖析
InnoDB内存管理宗旨
1.预分配内存管理空间,即设置缓存-------------------------------------------------> 内存池
2.已页为单位加载:如果以记录为单位,粒度太细,IO消耗太大-------------> 内存页面管理:页面映射,页面数据管理
3.内外层空间交换:优先将磁盘里和内存中数据不符的页替换掉,释放内存空间,加载新数据
------------------------------------------------------------------------------------------------->数据淘汰:内存页都被使用;需要加载新数据
LRU算法:在淘汰时,把最长时间没有访问的数据淘汰。每次访问了哪条数据就把那个数据页放在链表头,这样每次链表末尾就是最长时间没有使用的。如果只有一个LRU链表的话,在访问数据量大的表时可能会把整个LRU链表占满,导致之前的热数据全被淘汰。Redis采用的是 访问时间+访问频率 的方式来避免热数据被淘汰。Mysql采用 两层LRU(LRU_new:LRU_old 5:3) 的方式。访问大表时即使把二级LRU占满也没关系,真正的热数据都在一级LRU(LRU_new)。
当访问一条数据要将该数据所在数据页写入内存时,找到free list 找个free page位置放进去,把数据页在磁盘的位置和在内存页的位置记录在 page hash,然后在free list里把该free page干掉,把该已经变成clean page的页插入到LRU list 的 LRU_old的头部,这一步就是页面装载。如果free list显示内存池中没有空闲页了,那么就去找到存放数据页和脏页的 LRU list 开始进行数据淘汰(有疑惑,是什么显示没有空闲页,为什么从LRU list淘汰,LRU list是筛选热数据的放在内存中的,所以LRU list能对应内存池中所有数据吗,不然怎么能判断进入LRU_old的就是冷数据呢),优先对 dirty page进行淘汰,LRU 内存淘汰算法。
LRU内存淘汰算法
LRU 尾部淘汰、LRU Flush淘汰
如果LRU_old里数据都在被使用(dirty page会不会被使用中,这样不会有锁吗),就去Flush Page,选择dirty page进行LRU Flush淘汰。LRU Flush淘汰就是把dirty page从LRU list直接放到Free list去。
OLD---NEW
innodb_old_blocks_time old区存货时间大于此值,old区该page才有可能进入new区
new -----old
移动 midpoint 到 LRU old的新Header,保持在5/8位置
为了避免移动次数过多,造成锁,影响并发效率,故只有当 freed_page_clock - 上次移动到Header时free_page_clock > LRU_new 长度1/4时,即代表发生较多改变了的时候,才移动midpoint。
Mysql 事务实现 原理拆解、设计剖析
Mysql事务基本概念
事务特性ACID
- A (Atomicity)原子性:全部成功或者全部失败
- I (Isolation) 隔离性:并行事务之间互不干扰
- D (Durability) 持久性:事务提交后,永久生效
- C (Consistency) 一致性:通过AID保证
并发问题
- 脏读:读取到未提交数据
- 不可重复读:两次读取结果不同
- 幻读:select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。待理解
隔离级别
- Read Uncommitted(读取未提交内容) --- 脏读
- Read Committed(读取提交内容) --- 不可重复读
- Repeatable Read (可重复读) ---幻读。 每次读取相同的结果集,不管其他事务是否提交
- Serializable(串行化) ---事务排队,隔离级别最高,性能最差
Mysql事务实现机制
Mysql InnoDB 事务管理机制 ------- MVCC
多版本并发控制
解决 读-写 冲突
隐藏列 transaction_id事务ID 指针ID 全局唯一,事务ID递增,越大代表数据越新
Mysql的读 ------ 当前读和快照读
当前读就是读当前存储引擎里的数据,快照读可读创建快照那一刻的历史数据。那么快照读是如何判断当时数据是什么样的呢。
创建快照的那一刻,保存下当下 活跃事务 的事务ID 到一个列表中,此为 活跃事务ID列表,排序
当开始快照读时,去存储引擎里去寻找数据,找到一条数据,查看其隐藏列中的 tarnsaction id ,如果该条数据 TRX_ID < 活跃事务ID列表中最小TRX_ID,那就直接可见,查看;如果大于活跃事务ID列表中最小TRX_ID,那就去和 活跃事务ID列表中最大TRX_ID 比较 判断,如果大于其,则根据回滚指针指向上一版本数据,如果小于其,判断是否在 活跃事务ID列表 中,如果在,继续根据回退指针指向上一版本数据,如果不在,则 视为可见,查看。
undo log 事务回滚
redo log 事务固化
Mysql 锁实现 原理拆解、设计剖析
InnoDB锁种类
锁粒度:行级锁、间隙锁、表级锁
类型:共享锁(S)、排他锁(X)
所有 当前读 加 排他锁 。
select for update
update
delete
凡是要更新的操作,都是 当前读。
- 行级锁
作用在索引上;聚簇索引 & 二级索引。
聚簇索引------树结构和数据都存在一起。
二级索引:除聚簇索引外都是二级索引,二级索引的data节点存的是主键值
- 间隙锁
间隙锁,解决 可重复读(RR) 隔离级别下的幻读问题,保证两次当前读操作返回一直的记录。间隙锁,锁的是两条记录之间的GAP。
- 表级锁
谈到锁是怎么锁的,有四种情况: 唯一索引/非唯一索引 * RC/RR隔离级别
唯一索引都基本先锁定行,再根据行里涉及到的其他表的索引去锁定其他表的特定行,行级锁。。
非唯一索引,RC隔离级别 加锁:只涉及行级锁,在两次当前读的情况下,可能出现幻读 现象
非唯一索引,RR隔离级别 加锁:涉及 行级锁 和 间隙锁(GAP锁),所以即使有两次当前读操作也不会改变。
三个间隙锁,锁住那几个范围的值,132,133,135,136,都插不进去的。
间隙锁---------两次当前读之间,其他的事务不会插入新的满足条件的记录。
根据条件查询,无索引可走时:
当没有索引可走时,会 全表扫描 ------------> 表锁
在 RC 已提交读 模式下,会加 表锁 ,然后全部给 Mysql Server,MysqlServer会进行筛选,不符合条件的就释放其锁。
在 RR 可重复读 模式下,会加 表锁+间隙锁,可怕。
避免全表扫描!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
InnoDB加锁过程
锁,是一条一条加的。
死锁的形成:
最后
以上就是甜美裙子为你收集整理的Mysql架构体系深入剖析学习 Mysql 架构体系拆解、设计剖析 Mysql 存储引擎(最常用InnoDB为例) 原理拆解、设计剖析Mysql 事务实现 原理拆解、设计剖析Mysql 锁实现 原理拆解、设计剖析的全部内容,希望文章能够帮你解决Mysql架构体系深入剖析学习 Mysql 架构体系拆解、设计剖析 Mysql 存储引擎(最常用InnoDB为例) 原理拆解、设计剖析Mysql 事务实现 原理拆解、设计剖析Mysql 锁实现 原理拆解、设计剖析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复