zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

MySQL 服务挂了 CPU 消耗接近 100% 你知道怎么回事吗???

mysql服务CPU 知道 100% 消耗 接近 怎么回事
2023-09-11 14:14:53 时间

在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不妨来瞅瞅码农的轨迹。

在活动时间开始的时候, MySQL 服务就挂了,登上服务器一看,CPU 消耗接近 100%, 但整个数据库每秒就执行不到 100 个事务,这是什么原因呢?


MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类。

  • 全局锁主要用在逻辑备份过程中
  • 表锁一般是在数据库引擎不支持行锁的时候才会被用到的
  • 行锁在引擎层由各个引擎自己实现

行锁就是针对数据表中行记录的锁,如事务 A 更新了一行,而这时候事务 B 也要更新同一行,则必须等事务 A 的操作完成后才能进行更新。


1 MySql 两阶段锁协议

在 InnoDB 引擎事务中,行锁是在需要的时候才加上,然后等到事务结束时才释放,这个标准被称为 两阶段锁协议。

两阶段锁协议中,整个事务分为两个阶段,前一个阶段为加锁,后一个阶段为解锁

顾客 A 要在商家 B 购买一支笔,这个业务需要涉及到以下操作:

  1. 从顾客 A 账户余额中扣除一支笔的费用;(update操作)
  2. 给商家 B 的账户余额增加支笔的费用; (update操作)
  3. 记录一条交易日志。(insert操作)

要完成这个交易,需要 update 两条记录(如 1、2的操作),并 insert 一条记录(如3的操作),为 了保证交易的原子性,需要把这三个操作放在一个事务中。

假设正在此时,顾客C也在商家B这购买了这样的一支笔,那这个过程中出现事务冲突的就是第二步 商家 B 的账户增加笔的费用,因为需要修改同一行数据。

根据两阶段锁协议,所有的操作需要的行锁都是在事务提交的时候才释放的,也就是说只有在顾客A交易完成后,顾客C才能交易完成。

一个操作细节就是:把语句 2 安排在最后,比如按照 3、1、2 这样的顺序,那么商家 B账户余额这一行的锁时间就最少,这就最大程度地减少了事务之间的锁等待,提升了并发度。

2 死锁问题

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。

MySql 参数 innodb_deadlock_detect 设置为 on(默认也为开启),表示开启这个逻辑,死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他 事务得以继续执行。

死锁检测要耗费大量的 CPU 资源,这就是CPU 消耗接近 100%的原因。

一种解决方案就是控制并发度,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题,

一般这个并发控制要做在数据库服务端,如果有中间件,可以考虑在中间件实现,当然也可以做在 MySQL 里面。

【后续章节会更新Java中的并发编程】


完毕

不局限于思维,不局限语言限制,才是编程的最高境界。

以小编的性格,肯定是要录制一套视频的,随后会上传

有兴趣 你可以关注一下 西瓜视频 — 早起的年轻人

在这里插入图片描述