Mysql 事务隔离机制、锁机制、MVCC多版本并发控制隔离机制、日志机制、

原子性 (Atomicity)当前事务的操作要么同时成功,要么同时失败。原子性由undo log日志来实现。
一致性 (Consistency) : 使用事务的最终目的,由其它3个特性以及业务代码正确逻辑来实现。
隔离性 (lsolation) : 在事务并发执行时,他们内部的操作不能互相干扰,隔离性由MySQL的各种锁以及MVCC机制来实现。
持久性 (Durability) : 一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由redo log日志来实现。

MVCC(Multi-Version Concurrency Control)多版本并发控制就可以做到读写不阻塞且避免了类似脏读这样的问题,主要通过undo日志链来实现。(undo 日志版本链在不同事务隔离级别基于可见性算法实现)。

select操作是快照读 (历史版本)

insert、update和delete是当前读 (当前版本)

read commit (读已提交),语句级快照

repeatable read (可重复读),事务级快照

序列化:本质是通过在select语句后面加了共享锁:lock in share mode;

大事务的影响

并发情况下,数据库连接池容易被撑爆;
锁定太多的数据,造成大量的阻塞和锁超时执行时间长,容易造成主从延迟;
回滚所需要的时间比较长;
undo log膨胀;
容易导致死锁;

事务优化实践原则

将查询等数据准备操作放到事务外

事务中避免远程调用,远程调用要设置超时,防止事务等待时间太久事务中避免一次性处理太多数据,可以拆分成多个事务分次处理

更新等涉及加锁的操作尽可能放在事务靠后的位置

能异步处理的尽量异步处理

应用侧(业务代码)保证数据一致性,非事务执行

事务问题定位

#查询执行时间超过1秒的事务,详细的定位问题方法后面讲完锁课程后会一起讲解
SELECT *
FROM
  information_schema.innodb_trx
WHERE
  TIME_TO_SEC( timediff( now( ),trx_started ) ) > 1;
#强制结束事务
kill 事务对应的线程id(就是上面语句查出结果里的trx_mysql_thread_id字段的值)

锁分类

乐观锁适合读操作更多的场景,悲观锁适合写操作较多的场景。

锁等待分析

通过检查InnoDB row lock状态变量来分析系统上的行锁的争夺情况。
show status like 'innodb_row_lock%';
对各个状态量的说明如下:
Innodb_row_lock_current_waits: 当前正在等待锁定的数量
Innodb_row_lock_time: 从系统启动到现在锁定总时间长度
Innodb_row_lock_time_avg: 每次等待所花平均时间
Innodb_row_lock_time_max: 从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_waits: 系统启动后到现在总共等待的次数


对于这5个状态变量,比较重要的主要是:
Innodb_row_lock_time _avg (等待平均时长)
Innodb_row_lock_waits (等待总次数)
Innodb_row_lock_time (等待总时长)

间隙锁是在可重复读级别下才会生效

-- 查看事务
select * from INFORMATION SCHEMA.INNODB TRX;
-- 查看锁,8.0之后需要换成这张表data_locks
select * from INFORMATION SCHEMA.INNODB_LOCKS;
-- 查看锁等待8.0之后需要换成data_lock_waits
select * from INFORMATION SCHEMA.INNODB_LOCK_WAITS;

-- 查看锁等待详细信息
show engine innodb status;

锁优化实践

尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
合理设计索引,尽量缩小锁的范围
尽可能减少检索条件范围,避免间隙锁
尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行
尽可能用低的事务隔离级别

sql执行流程:

 

 WAL:Write-Ahead Logging 磁盘文件预写机制。

undolog回滚日志

InnoDB对undo log文件的管理采用段的方式,也就是回滚段 (rollback segment)。 每个回滚段记录了1024个 undo log segment,每个事务只会使用一个undo log segment。

在MYSOL5.5的时候,只有一个回滚段,那么最大同时支持的事条数量为1024个。在MySOL5.6开始,InnoDB支持景大128个回滚段,故其支持同时在线的事条限制提高到了 128*1024 。

undo log日志什么时候删除?

新增类型的,在事务提交之后就可以清除掉了。
修改类型的,事务提交之后不能立即清除掉,这些日志会用于mvcc。只有当没有事务用到该版本信息时才可以清除.

为什么Mysql不能直接更新磁盘上的数据而设置这么一套复杂的机制来执行SQL了?

因为来一个请求就直接对磁盘文件进行随机读写,然后更新磁盘文件里的数据性能可能相当差。

因为磁盘随机读写的性能是非常差的,所以直接更新磁盘文件是不能让数据库抗住很高并发的。

Mysql这套机制看起来复杂,但它可以保证每个更新请求都是更新内存BufferPool,然后顺序写日志文件,同时还能保证各种异常情况下的数据一致性。

更新内存的性能是极高的,然后顺序写磁盘上的日志文件的性能也是非常高的,要远高于随机读写磁盘文件。

正是通过这套机制,才能让我们的MySQL数据库在较高配置的机器上每秒可以抗下几于甚至上万的读写请求。

错误日志

Mysq还有一个比较重要的日志是错误日志,它记录了数库启动和停止,以及运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。
在MySQL数据库中,错误日志功能是默认开启的,而且无法被关闭。

 # 查看错误日志存放位置
show variables like '%log_error%';

通用查询日志

通用查询日志记录用户的所有操作,包括启动和关闭MySQL服务、所有用户的连接开始时间和截止时间、发给 MYSQL数据库服务器的所有SQL指令等,如select、show等,无论SQL的语法正确还是错误、也无论SQL执行成功还是失败,MySQL都会将其记录下来。
通用查询日志用来还原操作时的具体场景,可以帮助我们准确定位一些疑难问题,比如重复支付等问题。
genera log:是否开启日志参数,默认为OFF,处于关闭状态,因为开启会消耗系统资源并且占用磁盘空间。一般不建议开启,只在需要调试查询问题时开启。
general log file: 通用查询日志记录的位置参数。

show variables like "%general log%':
# 打开通用查询日志
SET GLOBAL general_log=on;

MySQL连接参数如何配置?max_connections

连接的创建和销毁都需要系统资源,比如内存、文件句柄,业务说的支持多少并发,指的是每秒请求数,也就是QPS。
一个连接最少占用内存是256K,最大是64M,如果一个连接的请求数据超过64MB(比如排序),就会申请临时空间,放到硬盘上。
如果3000个用户同时连上mysql,最小需要内存3000*256KB=750M,最大需要内存3000*64MB=192G。
如果innodb_buter_pool_size是40GB,给提作系分4G,给连使用的最大内不到20G,如果连接过多,使用的内存超过20G,将会产生盘SWAP,此时将会影响性能,连接数过高,不一定带来吞吐量的提高,而且可能占用更多的系统资源。

 

End!

posted @ 2023-03-30 18:37  曾鸿发  阅读(53)  评论(0编辑  收藏  举报