InnoDB 事务/锁/多版本分析?你了解多少?

目录

• InnoDB事务

– 事务结构/功能

– XA事务/Group Commit

– mini-transaction• InnoDB锁 – 锁结构/类型/功能

– 锁等待/死锁检测

– 自增序列锁(autoinc lock)

– 半一致读(semi-consistent read)

– 隐式锁(implicit lock)

• InnoDB多版本

– ReadView

– 聚簇索引/二级索引

– 快照读 – Index Only Scan

– RC vs RR

– Purge

• InnoDB事务/锁/多版本总结


 InnoDB事务

– 事务结构/功能

– XA事务/Group Commit

– mini-transaction

InnoDB事务-结构

InnoDB事务-结构(cont.)

• trx_sys(全局唯一)

– mutex: critical section,控制事务的分配/提交/回滚

– max_trx_id: 当前系统最大的事务号 分配256次,写一次文件,持久化

– trx_list: 系统当前所有活跃事务链表

– view_list: 系统当前所有ReadView链表
• trx_struct(事务对象)

– id/no: 事务号,标识事务起始/提交顺序 • id用户可见,no用户不可见;共用trx_sys的max_trx_id进行分配 – xid: XA事务标识 – (global)read_view: 事务所属的ReadView

– trx_locks: 事务持有的所有lock(表锁/记录锁/Autoinc锁)

– wait_lock: 事务当前正在等待的lock

InnoDB事务-功能

 快照读

– 创建ReadView,实现RC/RR隔离级别(MVCC时分析)
• 当前读

– 对表/记录加锁

– 同一事务,所有的锁,链成链表
• I/U/D

– 加锁

– 记录undo日志/redo日志
• 数据持久化

– 事务commit • 需要哪些操作?
• 数据回滚

– 事务rollback • 需要哪些操作?

InnoDB事务-XA事务

Why XA? – 为了保证InnoDB redo log与MySQL binlog的一致性 – backup

XA Commit流程

– InnoDBprepare -> Binlog commit -> InnoDB commit

– Binlog作为事务协调器 – Transaction Coordinator

– 参数 – MySQL:sync_binlog – InnoDB:innodb_flush_log_at_trx_commit

Group Commit – MariaDB/Percona 5.5.19-rel24/MySQL 5.6

InnoDB事务-mini-transaction

mini-transaction(微事务) – 定义 • mini-transaction不属于事务;InnoDB内部使用
• 对于InnoDB内所有page的访问(I/U/D/S),都需要mini-transaction支持
– 功能 • 访问page,对page加latch ( 只读访问: S latch ;写访问: X latch)
• 修改page,写redo日志 (mtr 本地缓存 )
• page操作结束,提交mini-transaction ( 非事务提交 ) – 将redo日志写入log buffer – 将脏页加入Flush List链表 – 释放页面上的 S/X latch
– 总结 • mini-transaction,保证单page操作的原子性(读/写单一page) • mini-transaction,保证多pages操作的原子性(索引SMO/记录链出,多pages访问的原子性)

 InnoDB锁

– 锁结构/类型/功能

– 锁等待/死锁检测

– 自增序列锁(autoinc lock)

– 半一致读(semi-consistent read)

– 隐式锁(implicit lock)

InnoDB锁-定义

 数据库中常用锁类型(Lock/Latch/Mutex)

– 相同 • 都是用来锁住一个资源
– 不同 • Lock (事务锁)

– 实现复杂;功能多样;可大量/长时间持有

– 支持死锁检测 – 用途:锁用户记录/表
• Latch (页面锁)

– 实现相对简单;功能相对简单;少量/短时间持有

– 不支持死锁检测

– 用途:Latch page,防止访问时页面被修改/替换(pin)
• Mutex (临界区锁)

– 最为简单(CAS, TAS); 功能简单;极短持有时间

– 无死锁检测 – 用途:保护critical section(临界区)

InnoDB锁-结构

 

 lock_sys(Rec lock hash)

– InnoDB的行锁,通过hash表管理

– hash值,通过[space, page_no]计算:同一页面在同一hash bucket中

– 思考:表锁呢?
• lock_struct – trx_locks: 属于同一事务的锁链表

– type_mode: 加锁模式 • 一个锁对象,一个加锁模式 – hash: 记录锁在hash表中的指针

– index: 锁对应的索引 – rec_lock/tab_lock: 以上属于表锁/行锁共用结构,此处为不同结构

InnoDB锁-结构(cont.)

 lock_rec_struct

– InnoDB行锁特殊结构
– InnoDB行锁实例,对应于一个索引页面中的所有记录 n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN; n_bytes = 1 + n_bits / 8; lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes);
– 行锁实例的最后,是n_bytes的bitmap • bitmap的下标对应于page中的heap_no(记录唯一) • bitmap=1,heap_no记录加锁

InnoDB锁-行锁

行锁 – 行锁实例 • 对应 Index Page (聚簇 & 非聚簇)
– 行锁标识 • 记录在page中的heap_no
– heap_no • 记录插入page,分配 • 删除记录重用,heap_no可重用 • heap_no与slot_no不同 • heap_no不可用来查找记录
– 行锁实例(右图) • 根据查询条件,行锁实例bitmap 的1,3,6 bits设置为1,对应于 heap_no 1,3,6号记录

InnoDB锁-行锁开销

 锁开销接近Oracle? InnoDB 宣称自己的行锁代价接近于 Oracle ,一条记录用 1 bit 即可,实 际情况呢? InnoDB 的行锁对象,管理一个 Page ,行锁上的 1 bit ,对应 Page 中的一条记录。一个 400 条记录的 Page ,一个行锁对象大小约为 102 bytes 。
锁一行 :
代价 为 102 bytes/ 行 ;
锁 400 行 :
代价 为 102 bytes/400 = 2 bits/ 行。
• 实际情况 – 锁一行代价巨大(如何优化,后续揭晓) – 锁一页代价较小

InnoDB锁-锁模式

 数据锁模式

– 数据锁:仅仅锁住数据

LOCK_IS, LOCK_S, LOCK_IX, LOCK_X
– 意向锁:LOCK_IS, LOCK_IX • 表级锁;加记录锁前必须先加意向锁; • 功能: 杜绝行锁与表锁相互等待

 非数据锁模式

– 不锁数据,标识数据前GAP的加锁情况;非数据锁与数据锁之间不冲突
– LOCK_ORDINARY • next key锁,同时锁住记录(数据),并且锁住记录前面的Gap
– LOCK_GAP • Gap锁,不锁记录,仅仅记录前面的Gap
– LOCK_NOT_GAP • 非Gap锁,锁数据,不锁Gap
– LOCK_INSERT_INTENSION • Insert操作,若Insert的位置的下一项上已经有Gap锁, 则获取insert_intension锁,等待Gap锁释放
– LOCK_WAIT • 当前锁不能立即获取,需要等待

– 非数据锁兼容模式

InnoDB锁-实例分析

 

InnoDB锁-加锁总结

InnoDB锁-等待

InnoDB锁-死锁检测

死锁检测 – 加锁需要等待,则触发死锁检测
– 死锁检测由用户线程处理
– 构造Wait-For-Graph (WFG)
– 深度优先遍历 (递归) • 后续改为非递归实现(栈)
– 死锁检测过程中,持有kernel_mutex • 后续MySQL版本中,新增lock_sys->mutex
– 根据事务权重,选择牺牲者 • 事务权重:undo日志量 + 锁数量

InnoDB锁-分裂/合并/迁移

 锁分裂 – 索引页面分裂 -> 锁分裂
• 锁合并 – 索引页面合并 -> 锁合并
• 锁迁移 – 插入记录 • Gap锁从插入后项迁移到新插入项
– 删除记录 • Gap锁从删除项迁移到删除后项

InnoDB锁-Autoinc锁

自增序列锁(Autoinc Lock) – 功能 • 复杂insert语句+statement binlog下,保证master-slave一致性
– 自增序列并发控制 • mutex: 简单Insert/replace语句 • Autoinc_lock: insert into select * from 语句
– 参数设置 • innodb_autoinc_lock_mode – 0,1,2

InnoDB锁-半一致读

Semi-Consistent Read(半一致读) – 目标 • 提高系统并发性能,减少锁等待
– 方案 • 当前读,可读取记录历史版本 • 不满足查询条件的记录,可提前放锁
– 前提 • Read Committed隔离级别 • innodb_locks_unsafe_for_binlog

InnoDB锁-隐式锁

Implict Lock(隐式锁)

– 目标 • 减少Insert时加锁开销,减少锁内存消耗 • 降低锁一行记录的情况( 锁一行代价巨大 )
– 方案 • Insert时,不加锁(Implict lock) • 后续scan(当前读),如果碰到Implicit lock,则转换为Explicit lock • 延迟加锁
– Implicit Lock判断 • 聚簇索引 – 根据记录上的trx_id判断(trx_id 是否为活跃事务? ) • 二级索引 – 根据索引页面上的max_trx_id + 回聚簇索引判断 (max_trx_id 是否小于最小活跃事务? )

– 存在bug

InnoDB多版本

– ReadView

– 聚簇索引/二级索引

– 快照读

– Index Only Scan

– RC vs RR

– Purge

InnoDB多版本定义

一 条语句,能够 看到 ( 快照读 ) 本 语句开始时 (RC)/ 本 事务开始时 (RR) 已 经提交的 其他事务所做的修改
– 快照读 • 读记录历史版本,而非当前更新未提交版本 • 无需加锁,lock free • 语句级(RC):语句开始时的快照 – 语句级ReadView • 事务级(RR):事务开始时的快照 – 事务级ReadView
– 看到? • 已提交的Insert/Update后项,可见并返回 • 已提交的Delete/Update前项,可见并略过

• ReadView
所谓 ReadView ,是一个事务的集合,这些事务在 ReadView 创建时是 活跃的 ( 未提交 / 回滚 )

 read_view_struct – low_limit_no • 提交时间早于此值(trx->no < low_limit_no)的事务,可以被purge线程回收 • low_limit_no= trx_sys->max_trx_id
– low_limit_id • >= 此值(trx->id >= low_limit_id)的事务,当前ReadView均不可见 • low_limit_id= trx_sys->max_trx_id
– up_limit_id • < 此值(trx->id < up_limit_id)的事务,当前ReadView一定可见 • up_limit_id= ReadView创建时系统中最小活跃事务ID
– trx_ids[] • 系统中所有活跃事务id组成的数组
• 创建ReadView

– 获取kernel_mutex • 遍历trx_sys的trx_list链表,获取所有活跃事务,创建ReadView

– Read Committed • 语句开始,创建ReadView

– Repeatable Read • 事务开始,创建ReadView

 ReadView创建

RC VS RR

InnoDB多版本-记录组织

聚簇索引记录 – DB_TRX_ID • 生成此记录的事务ID

– DB_ROLL_PTR • 此记录历史版本的指针

– Delete_Bit(未给出)
• 二级索引记录

– Delete_Bit – 索引页面,有DB_MAX_ID • 标识修改索引页面的最大事务ID

InnoDB多版本-更新

 目的

– 测试各种更新场景下,聚簇索引记录/二级索引记录的变化
• 准备 create table test (id int primary key, comment char(50)) engine=innodb; create index test_idx on test(comment);
insert into test values (1, ‘aaa’); insert into test values (2, ‘bbb’);

更新主键

update test set id = 9 where id = 1;

– 旧记录标识为删除

– 插入一条新纪录

– 新旧记录前项均进入回滚段

更新非主键

update test set comment = ‘ccc’ where id = 9;

 InnoDB更新总结
– 更新主键,聚簇索引/二级索引均无法进行in place update,均会产生 两个版本
– 更新非主键,聚簇索引可以in place update;二级索引产生两个版本
– 聚簇索引记录undo,二级索引不记录undo
– 更新聚簇索引,记录旧版本会进入Rollback Segment Undo Page
– 更新二级索引,同时需要判断是否修改索引页面的MAX_TRX_ID
– 属于同一事务的undo记录,在undo page中保存逆向指针

InnoDB多版本-可见性

InnoDB多版本-Cluster Index Scan

聚簇索引扫描

– 当前读 • 加锁;读取记录最新版本 • 通过记录的DB_TRX_ID判断 是否存在Implicit lock
– 快照读 • 不加锁; • 根据ReadView读取可见版本
– Index Only Scan • 一定为Index Only Scan

 二级索引扫描

– 当前读 • 加锁(二级索引/聚簇索引) • 读取记录最新版本 • 通过page上的MAX_TRX_ID判断 是否可能存在Implicit lock
– 快照读 • 不加锁 • 读取记录唯一可见版本 – 如何过滤同一记录的不同版本?
– Index Only Scan • cont.

 Index Only Scan

– 当前读 • 不能进行Index Only Scan – 当前读需要对聚簇索引记录加锁 – 当前读需要访问聚簇索引,读取记录所有列
– 快照读 • 访问索引不存在的列

– 不能进Index Only Scan
• 仅仅访问索引列

– 二级索引page的MAX_TRX_ID不可见-> 不能进行Index Only Scan » 此概率较小

– MAX_TRX_ID可见 -> 可进行Index Only Scan » 此概率极大

InnoDB多版本-实例讲解

MySQL Bugs 65745 UPDATE on InnoDB table enters recursion, eats all disk space

原因分析

– 更新主键字段,二级索引同样会产生Halloween问题

 Purge

– 功能 • 回收索引页面中被删除 且不会被其他事务看到的项
– 实现流程 • 拷贝trx_sys ReadView链表中最老 的read_view,作为purge_read_view
• 遍历InnoDB系统中所有的Rollback Segment, 取出最老的提交事务
• 若purge_read_view.low_limit_no > old_trx.no; 说明对应的事务可以被purge
• 反向遍历事务的undo日志, 构造索引记录,查询并删除
– 参数/优化 • innodb_max_purge_lag() • innodb_purge_threads (since MySQL 5.6.2)

• InnoDB事务/锁/多版本总结

 RR vs RC

– Read Committed • 优势

– 高并发,低锁开销:semi-consistent read – no gap lock;early unlock • 劣势

– 不支持statement binlog – 语句级快照读:每条语句,新建ReadView
– Repeatable Read • 优势 – 支持gap lock;statement binlog – 事务级快照读:一个事务,对应一个ReadView • 劣势 – 并发冲突高,加锁冲突更为剧烈 – 不支持semi-consistent read;不支持early unlock

事务Commit流程 – prepare • 将redo日志从log buffer写入log file,并flush – innodb_flush_log_at_trx_commit
– commit • 处理事务产生的undo pages – insert undo pages直接回收 – 获取事务的trx->no (标识提交顺序) – update undo pages链入history list,等待purge
• 释放事务持有的锁 – 唤醒必要的等待者
• 关闭事务的read_view
• 将redo日志写出,并flush – innodb_flush_log_at_trx_commit

事务Rollback流程 – 反向遍历undo日志并应用 • undo操作需要记录redo (undo的补偿日志)
– 以下流程,与commit一致 • 处理事务产生的undo pages
• 释放事务锁
• 关闭read_view
• 将redo日志写出,并flush

 

 

 

 

 

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

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

相关文章

[剑指offer]面试题第[42]题[Leedcode][JAVA][第53题][最大子序和][动态规划][贪心][分治]

【问题描述】[第53题][最大子序和][中等] 给定一个整数数组 nums &#xff0c;找到一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。示例:输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大…

[Leedcode][JAVA][第983题][最低票价][动态规划]

【问题描述】[第983题][最低票价][中等] 在一个火车旅行很受欢迎的国度&#xff0c;你提前一年计划了一些火车旅行。在接下来的一年里&#xff0c;你要旅行的日子将以一个名为 days 的数组给出。每一项是一个从 1 到 365 的整数。火车票有三种不同的销售方式&#xff1a;一张为…

[Leedcode][JAVA][第572题][另一个树的子树]

【问题描述】 给定两个非空二叉树 s 和 t&#xff0c;检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。示例 1: 给定的树 s:3/ \4 5/ \1 2 给定的树 t&#xff1a;4 / \1 2 返回…

LVS在淘宝环境中的应用

目录 1. LVS-简介 2. LVS-问题 3. LVS-fullnat 4. LVS-synproxy 5. LVS-cluster 6. LVS-performance 7. LVS-todo list 疑问引入:用户访问淘宝&#xff0c;访问哪台apache服务器 传统做法&#xff1a;DNS服务 四个问题 Q1&#xff1a;apache2 down&#xff0c;remove生…

android 开发艾特功能,Android Binder

Binder 是一种进程间通信机制&#xff0c;基于开源的 OpenBinder 实现&#xff1b;OpenBinder 起初由 Be Inc. 开发&#xff0c;后由 Plam Inc. 接手。从字面上来解释 Binder 有胶水、粘合剂的意思&#xff0c;顾名思义就是粘和不同的进程&#xff0c;使之实现通信。为什么 Act…

C# Json转对象

第一步&#xff0c;项目添加negut的搜索Newtonsoft.Json&#xff0c;安装第一个&#xff1a;如图所示&#xff1a; 安装以后&#xff0c;自动引用。 private ObservableCollection<Traffic> m_listcls; var json JsonConvert.DeserializeObject<List<Traffic>&…

Dubbo开源

什么是Dubbo? 分布式服务框架 – 远程服务调用 • Ne/y/Mina/Grizzly • RMI/Hessian/WebService – 服务动态发现 • Zookeeper/Redis – 集群软负载均衡 • Random/RoundRobin – 集群失败容错 • Failove…

[Leedcode][JAVA][第470题][Ran7()实现Rand10()]

【问题描述】[Leedcode][JAVA][第470题][Ran7()实现Rand10()] 已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数&#xff0c;试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。不要使用系统的 Math.random() 方法。示例 1:输入: 1 输出: [7] 示例 2:输入: 2 输出: …

推荐系统?淘宝?

目录 • 推荐系统概念 • 淘宝的数据 • 淘宝推荐系统应用场景 • 淘宝推荐系统核心算法 • 淘宝推荐系统的设计 • 推荐系统概念 • 淘宝的数据 • 淘宝推荐系统应用场景 • 淘宝推荐系统核心算法 • 淘宝推荐系统的设计 推荐系统定义 维基百科&#xff1a; form…

android studio 无法输入中文,Android Studio 升级到3.0后输入法中文状态下无法选词的终极解决方案...

AndroidStudio终于出3.0正式版了&#xff0c;内置了kotlin(虽然我安了插件一直能用)。一直忍着没敢下rc版的好奇猫&#xff0c;总算装了正式版。当然&#xff0c;伴随每次大版本更新&#xff0c;总有一些恼人的后遗症&#xff0c;其中以gradle问题最多。AS3.0要求gradle版本在3…

java学习(174):constructor类反射编程

//class反射编程 //定义一个学生类 public class test124 {public String name;protected int age;double height;private double money;public void setName(String name) {this.name name;}public String getName() {return name;}public int getAge() {return age;}public …

[国密算法]一文了解国密算法

国密算法概述1 SM1对称密码2 SM2椭圆曲线公钥密码算法3 SM3杂凑算法4 SM4对称算法5 SM7对称密码6 SM9标识密码算法7 ZUC祖冲之算法总结算法名称算法类别应用领域特点SM1对称密码算法芯片分组长度、密钥长度均为 128 比特SM2公钥密码算法加密ECC椭圆曲线密码机制256位 相比RSA&a…

java学习(175):method类反射机制

//class反射编程 //定义一个学生类 public class test124 {public String name;protected int age;double height;private double money;public void setName(String name) {this.name name;}public String getName() {return name;}public int getAge() {return age;}public …

java-web的mybatis的学习

idea开发必须是把Mapper文件与配置文件放到Resources标记的classpath目录下&#xff0c;eclips好像放到哪都行指定好路径就可以了&#xff0c; maven里面做好配置resources的路径&#xff0c;不然更新依赖 工程结构标记又没了 <build> <resources> <resour…

[Leedcode][JAVA][第85题][第221题][最大正方形][动态规划]

【问题描述】[第221题][最大正方形][中等] 在一个由 0 和 1 组成的二维矩阵内&#xff0c;找到只包含 1 的最大/长方形正方形&#xff0c;并返回其面积。示例:输入: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 长方形 输出: 6 正方形 输出: 4【解答思路】 1. 长方形 暴力 时间…

次时代各制作插件使用方案以及技巧 包括UV 烘焙 减面等

次世代游戏的到来&#xff0c;使游戏行业向前迈进了一大步。次世代本来代表的是拥有更高cpu硬件设施的电视游戏&#xff0c;即戴着头盔能感到wii拳击的震动、拿着拳套能感应阴森恐怖的氛围。绝对让玩家融入气氛的Xbox360的《生化危机5》还带有场景破坏&#xff0c;能打下一片墙…

java学习(177):获取应用程序的路径

import javax.tools.Tool; import java.net.URLDecoder;//获取类路径 public final class test132 {public static String getClassPath(){String pathtest132.class.getClassLoader().getResource( "" ).getPath().toString();try {return URLDecoder.decode( path…

[Leedcode][JAVA][第69题][x的平方根][二分查找][数学]

【问题描述】 实现 int sqrt(int x) 函数。计算并返回 x 的平方根&#xff0c;其中 x 是非负整数。由于返回类型是整数&#xff0c;结果只保留整数的部分&#xff0c;小数部分将被舍去。输入: 8 输出: 2 说明: 8 的平方根是 2.82842..., 由于返回类型是整数&#xff0c;小数部…

高可用的 MFS 文件分布式系统(Drdb+heartbeat+MFS )

理论拓扑 环境准备&#xff1a; N 台 Linux 测试服务器 操作系统版本 CentOS 6.5 32bit ***系统分区要求&#xff1a;需要为格式化的空分区*** IP 地址&#xff1a; mfsmaster&#xff1a;10.3.0.81 心跳 ip 192.168.1.11 mfsbackup&#xff1a;10.3.0.82 …