第37问:自旋锁 旋着旋着人就糊涂了

作者: admin 分类: 公众号存档            0 次浏览 发布时间: 2021-05-23 22:48

【转载声明】本文为转载文章,原作者「黄炎」,版权归原作者所有。 原文链接:https://mp.weixin.qq.com/s/oB9goYuLbymy9n_QK6Fa6w

公众号:杨建荣的学习笔记 · 作者:黄炎 · 发布:2021-05-23 22:48:03 · 原文链接

问题

追求 MySQL 的性能时,总听说要调整自旋锁的参数: innodb_spin_wait_delay 和 innodb_sync_spin_loops,是真的么?

实验

首先我们要知道自旋锁的优点:自旋锁要上锁时,如果需要等待其他线程释放锁,那么:

  • 在等待锁的过程中会先线程会先自旋一段时间

    • 自旋阶段,线程不会放弃 CPU

  • 自旋过后:

    • 如果可以获取锁了,那么响应会比较快(自旋没发生上下文切换)

    • 如果还需要等待锁,再用更高成本的方式进行锁等待

innodb_spin_wait_delay 参数决定了自旋阶段的长度。现在我们试着调整 innodb_spin_wait_delay 参数,来测试一下:

先宽油起一个数据库,此处忽略步骤

建个表,放点数据:

配置好 performance_schema:

检查一下相关参数:

清理 performance_schema 的统计值:

来点压力:

查询一下锁等待成本最高的锁:

可以看到锁等待成本最高的是 lock_mutex,是保护 MySQL 锁系统的锁

下面我们来调整一下 innodb_spin_wait_delay,让自旋的时间变长:

重做一次压力(记得先清理统计数据),查看统计数据:

可以看到 lock_mutex 的平均等待时间从 751267 增加到了 1399041。我们让自旋阶段增加了 10 倍,锁等待的时间也会随之增大。

目前的实验看上去自旋阶段越短越好,那么自旋阶段是不是就没有意义了?当然不会。

大家可以将 innodb_spin_wait_delay 设置为 1,再进行测试,随着自旋阶段的减少,锁等待的时间也会随之增大(大部分锁都使用了高成本的方式来进行等待)。

那么如何选择自旋的参数呢?我们建议“不出问题不瞎调”。

在之前的统计数据中,时间的单位是:cycle,根据以下换算表,锁的平均时间是 1399041 cycle,大概也就 0.5ms(1399041 / 2385353233 = 0.00058 s),占 SQL 的整体时间很低,可以不用瞎调。

一个著名的 CPU 问题

自旋阶段,MySQL 会调用 CPU 的 PAUSE 指令,既能占用了 CPU,同时 PAUSE 指令(比起其他占用 CPU 的指令)也比较节能。

不过既然占用了 CPU,那么就会体现在 CPU 的使用率上。

现在我们将 innodb_spin_wait_delay 再放大一点比较一下:

可以看到 CPU 使用率会随着自旋阶段变长而升高

Intel 的 Skylake 系列 CPU,调大了 PAUSE 指令的周期时长。从 10 cycles 调大到 140 cycles(也许是因为让 PAUSE 周期变长更有利于节能)

类似于今天的实验,这个指令的调整相当于拉长了自旋阶段。

这就导致了在 Skylake 系列 CPU 下,MySQL 的锁表现和 CPU 占用率表现都有可能更糟糕。

(推荐文章:https://tech.meituan.com/2020/04/16/intel-pause-mysql.html)

小贴士

看到这里大家是不是开始焦虑了,要准备换 CPU 了?

其实不必焦虑,绝大部分情况下,大家不用追求极致的性能。比起榨取服务器的一点点极限性能,业务稍微调整一下 SQL 取得的收益会 大几个数量级。

俗话说:业务写得好,运维回家早。


相关推荐

第36问:用 mysqlslap 压测的结果,为什么比用 sysbench 的结果平稳?

第35问:InnoDB 刷脏页慢,会影响我的业务么?

第34问:我没有让 SQL 使用联合索引,但它不听


关于 MySQL 的技术内容,你们还有什么想知道的吗?赶紧留言告诉小编吧!

本文关键字:#spin lock# #performance#

admin

杨建荣,《Oracle DBA工作笔记》《MySQL DBA工作笔记》作者,dbaplus社群发起人之一,腾讯云TVP,现任竞技世界系统部经理,拥有十多年数据库开发和运维经验,目前专注于开源技术、运维自动化和性能调优

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注