checkpoint undo mvcc 事务 内存锁 表锁 行锁 GAP锁总结

检查点checkpoint 脏页回写

1、后台写线程在某些情况下会阻塞前台线程
    1、lru冷端没有足够干净块,前台线程会触发后台线程加快写入脏块,前台线程等待
        加大写力度
        innodb_lru_scan_depth
        innodb_io_capacity
        innodb_io_capacity_max
    2、不能被覆盖的redolog数量过大
        Log flushed up to  -    Last checkpoint at  在logfile中占得过长,logfile不能被循环覆盖,整个数据库被hang住
        增加logfile的大小和组数
    3、脏页达到阈值,监控脏页占的比例
        增加后台写线程的数量
        增加存储写能力(闪卡/bbu支持的写缓存raid卡/nv缓存raid卡)


如何通过监控和调整来避免后台写线程阻塞前台线程

undo

1主动回滚
2写不阻塞读
3MVCC来实现select可重复读
4崩溃恢复

undo基础概念
1、undo段
2、undo purge/truncate
3、undo表空间
4、undo段头块
5、undo段头块事务表
6、事务开始获取事务槽的流程
1、根据当前实例生成最新事务ID
2、寻找可用事务槽(事务槽上的事务已经提交),undo段头块可用事务槽
3、将事务ID以及事务状态写入到事务槽中
7、数据行里面的事务id和undo指针伪列
8、主动回滚流程
1、根据事务槽找到undo最后一个块
2、依次往前滚,一直滚到事务开始的第一条修改

9、写不阻塞读
    要避免脏读,正在修改的事务去undo中找上一次的信息

    流程
        事务未提交,undo数据不会被覆盖
        数据块上有未提交事务,一定可以在undo中找到未提交事务修改前的数据
        构造CR块(读一致性块),实现写不阻塞读
        写和读阻塞的核心原因是避免脏读
        数据行中有UNDO指针,这个伪列

MVCC多版本控制

1、数据行的undoi数据包含:上一次的数据数值,事务id,undo指针rollpointer
2、undo中保存着数据行多个版本
3、事务并不提交,事务访问的表所有数据对应的undo数据一直不能被覆盖
解决了在一个事务中,对一个表的所用访问从头到尾保持一致
长事务会造成undo暴增,原因如上

长事务是由mvcc造成的,mvcc就是多版本控制,mysql为了保证在一个事务中对一个表访问的一致性,只要事务不提交,事务访问的表所有数据对应的undo数据一直不能被覆盖,版本一直控制在长事务对应的版本
会造成undo版本长,undo空间暴增
解决的核心途径:加强对长事务的监控,对于超过某个时间阈值的事务,进行告警

崩溃恢复
1、数据库启动,发现检查点Log flushed up to  和   Last checkpoint at 对应的日志有差距
2、前滚日志,Last checkpoint at 滚到Log flushed up to
3、回滚可以发生在数据库打开以后,当读到对应的数据块的时候,发现这个数据库对应的未提交事务是死事务(事务未提交,但是事务对应的线程已经不存在),主动回滚


对 undo的监控,都会造成undo暴增的
    长事务
    大事务
    长查询(长sql:select和dml)



题目:系统管理员给了我一个linux让我安装mysql,如何入手开始工作??
操作系统 网络 目录  存储性能  软件 版本 参数  

##事务

什么是事务?

事务,就是把一堆事情绑在一起做,都成功了才算完成,否则就恢复之前的样子

事务的属性

1.原子性:一个事务中所有的DML语句要么都成功、要么都失败,也就是说这些DML语句不能出现部分成功、部分失败的情况:这些DML不能分割

start transaction;
DML…;
commit;
事务提交的情况
commit; 会让事务提交
ddl; ddl语句之前会先执行一个commit
某些软件正常退出
事务回滚的情况
rollback;
某些软件非正常退出
会话超时被中段
会话被强行杀掉
语句执行失败;


2.一致性:通过redo和undo来保证事务的一致性,不会因为数据库崩溃而造成数据的不一致,所有已提交事务会被前滚,未提交事务会被回滚;


3.隔离性:一个事物不会影响其他事务运行;


4.持久性:事务成功完成之后,对数据库的修改被永久保存。

innodb对用户的承诺
已提交事务一定会被保存,未提交事务一定被回滚

事务隔离级别

MySQL事务隔离级别

未提交读:

这个没有隔离性

已提交读

对于select,通过undo来实现
对于DML,通过行锁实现
对于已提交读,不能避免幻读,但是可以满足绝数据库大多数的业务场景要求

可重复读

对于select,通过undo的mvcc特性来实现
对于DML通过行锁和GAP锁来实现
能够实现在一个事务中,对于数据访问的一致性
会带来undo增加,性能负担增加。gap锁
尽量避免GAP锁,表上建立合理的主键

序列化读

保证完全执行完全序列化
会出现写阻塞读的情况
不建议采用

事务隔离级别的最佳实践
采用已提交读事务隔离级别

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
读已提交(read-committed)
可重复读(repeatable-read)
序列化/串行化(serializable)

共享内存 锁

有共享就有并发,有并发就需要锁来支持,解决并发问题
latch有读写latch r、rw
metux只有排他锁
1、内存锁(latch/metux)
1、对应innodbbufferpool来说,有很多查找页的需求(根据地址,冷热等来查找)
2、使用chain将page连接起来,不同的chain对应不同的查找需求
3、对链的访问需要对应的锁进行保护,使用latch和mutex来进行保护
特点:不排队
随机spin,占用cpu
spin超出阈值以后os waits
通过spin waits和os waits监控系统是否存在内存锁争用

内存所使用的经典场景
    糟糕sql:正在慢 show processlist 已经慢 看慢日志
        大量内存读
        大量物理读
    业务增加:
        大量数据修改DML,tps明显增加(大量事务提交)

监控里有相应的展现

(latch/metux)  作用一样   都是锁内存的链    都不排队  都会spin,征用严重会表现为cpu过载
    区别:  
        latch占用数据库内存   metux占用操作系统内存    
        一个latch管理4个链  metux 链 一对一   数量更多
        latch内存结构复杂,metux简单    
        latch有读写     很多metux无读写
        metux争用少 灵活   latch笨重  

2、表锁lock
r 共享锁,读锁 所有数据都不能被修改,只可以读
X 排他锁
IX 意向排他锁
IS 意向共享锁select * from t where id=100 for update;产生IS锁 读select 的目的是为了更新,在表级别加了is锁,想在行数据里写上自己的xid,在行级别加了x 锁(select 。。for update 在行级锁(事务锁)角度和dml 语句一样)

兼容模式
+兼容 -不兼容

- s x ix is
s + - - -
x - - - -
ix - - + +
is + - + +

什么时间产生表锁
1、lock可以产生R锁
2、DDL和lock可以产生 X 锁 DDL最经典的 ALTER DROP TRUNCATE CREATE
3、DML产生 IX 锁

表锁的毛病
    默认超时时间很长
    行锁5s
    表锁没有对应的字典查询(找不到谁把某个表锁了)
    表锁的释放:exit、kill释放  commit或者rollback不能释放表锁

    myisam没有行锁,只有表锁
    myisam只有s和x
    innodb有各种表锁行锁

    如何避免表所
    避免DDL  尽量使用online DDl
    尽量不要使用myisam引擎,使用innodb引擎


    同一时间只允许一个修改(对交易系统不可以接受)

3、事务锁lock根基是行锁
行锁 InnoDB行锁是通过给索引上的索引项加锁来实现的
行锁是innodb锁的最小粒度

    事务锁:两个事务(两个用户线程)修改相同的行
    因为innodb实现了行锁,当两个事务修改相同的数据行的时候,产生了事务锁
    事务锁会占用独立内存资源
    事务锁就是产生行锁冲突的几个事务形成的队列
    对于事务锁来说,可以查询阻塞者、被阻塞者、阻塞先后顺序、事务大小、长事务 locks  lock_waits  trx

    事务锁都是排他锁


    事务锁和表锁都有队列机制,当产生锁冲突的时候,被阻塞者会排队

    事务锁的释放机制:commit、rollback

    事务锁的超时时间可以调整

    事务锁让用户感到数据库速度很慢,dml执行时间很长,但是os层面看到的现象:cpu负载不高,IO负载不高(vmstat、top)
    判断数据库问题
        1、os
        2、会话层面 processlist
        3、zabbix 趋势图

4、死锁
死锁和锁是两回事
是锁的一种特列,一种特殊情况
死锁不会造成数据库慢
死锁会被mysql快速主动解决
死锁都是应用设计逻辑问题,不是数据库自身问题,死锁往往是因为事务需求修改相同的几个资源造成的
避免死锁发生,减少在事务中对共享资源的修改

    总结  事务来持有这个表 ,如果是修改数据行,就对表加一个iX锁,对修改的数据行加X锁

GAP锁
1、select会访问数据行的时候会涉及到undo,构造CR块 ,CR读
2、dml包含select,update,只访问当前块,绝对不会读取undo块 ,current读
3、行锁不能保证dml语句产生幻影读
幻读:在一个事务中,同一个sql语句执行多次得到的结果不一致
如何避免?
使用gap锁:范围锁

4、select如何避免的幻影读(mvcc)
    1、事务开始记录事务id       2、事务在整个生命周期以内,读取到的数据块上的数据行对应的事务id一定要小于当前事务id,如果大于,就利用行上的rollpoint读取undo,利用mvcc一直读取到小与本事务id的mvcc版本
    3、mvcc的核心就是rollpoint,事务id,修改数据行的时候xid和rollpointer也被undo保存

5、GAP产生的条件
    1、DML
        i d u  select for update 
    2、没有主键和唯一键=条件,
        dml where 主键  between and
    3、DML不走索引(表锁)
6、避免gap锁
    主键或者唯一键where=
    事务隔离级别采用已提交读
    insert into valuse,如果有主键或者唯一键,不会产生gap锁

7、gap锁定范围
    dml不走索引,全表锁
    对于中间值,锁上不锁下
    对于最上面的值,无穷小-下一个值
    对于最下面的值,上一个值-无穷大

猜你喜欢

转载自blog.csdn.net/qq_39570637/article/details/81461086