前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解MySQL中的CPU自旋锁及其调优实践

深入理解MySQL中的CPU自旋锁及其调优实践

作者头像
用户1278550
发布2024-04-24 16:00:56
4054
发布2024-04-24 16:00:56
举报
文章被收录于专栏:idba

一 背景

前一段时间针对 MySQL 使用 TPC-C 导入10000仓的数据,查看数据库性能指标发现 TPS 3-4w/s (不符合预期),伴随 CPU idle 特别比较高, sys CPU 比较低,CPU 在空跑。于是乎做了基本的诊断 :os系统调用栈 , MySQL 系统参数 。使用 perf top 工具观察 系统函数调用情况, ut_delay比较突出。

接着调整 MySQL 的 spin_lock 相关的参数,效果如下,insert 性能提升2倍

二 CPU自旋锁的工作机制

什么是 自旋锁

自旋锁(spin lock)是一种在多线程环境中用于同步的机制,它允许线程在尝试获取一个资源时,如果资源暂时不可用,线程不会进入睡眠状态,而是在一个循环中不断尝试获取资源,直到成功为止。这种方式被称为“自旋”,

代码语言:javascript
复制
线程A               自旋锁            线程B
  |                  |----尝试获取---->|
  |                  |<---已经锁定-----|
  |------自旋等待---->|              
  |<----保持自旋------|                |
  |                  |----释放锁------>|
  |----获取锁---------|                |

在上图中,线程B首先获取了自旋锁。当线程A也尝试获取这个锁时,由于锁已经被占用,线程A不会进入休眠,而是在当前位置不断检查锁是否可用,即“自旋”。一旦线程B释放了锁,线程B便能够立即获取到锁并继续执行。

为什么要用自旋锁

其实对比自旋锁机制,还有另外一种控制 资源抢占的方法--- 互斥锁(mutex)。比如进程A 抢不到锁,不能访问内存资源,就需要在 用户态,内核态 ,CPU上下文切换调度,增加 CPU 消耗。

自旋锁(spin lock)是一种非阻塞锁,也就是说,如果某线程需要获取锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗CPU的时间,不停的试图获取锁。

需要注意的是因为线程在等待获取锁的过程中会占用CPU资源进行无效的工作。如果锁被持有的时间较长,则自旋锁可能会浪费大量CPU资源,导致系统性能下降。因此自旋锁适用于 锁的持有时间非常短的情况

下面引用的文章(https://zhuanlan.zhihu.com/p/88427657)说明好处如下:

代码语言:javascript
复制
spinlock优点:没有昂贵的系统调用,一直处于用户态,执行速度快
spinlock缺点:一直占用cpu,而且在执行过程中还会锁bus总线,锁总线时其他处理器不能使用总线
mutex优点:不会忙等,得不到锁会sleep
mutex缺点:sleep时会陷入到内核态,需要昂贵的系统调用

而我们Innodb中大量使用的是先进行spin,如果spin一定次数不能获得,则转入mutex等待(或者sleep),放弃CPU,本处也是如此。

三 在MySQL中使用 Spin Lock 的场景

在 MySQL 系统设计中,特别是 InnoDB 存储引擎使用自旋锁来控制对其内部数据结构的访问,以实现高性能和并发。InnoDB存储引擎具有复杂的并发控制机制,自旋锁在其中扮演了重要角色。

相关代码:

MySQL关于spin lock的部分代码。如下代码可以看到MySQL默认作了30次(innodb_sync_spin_loops=30)mutex检查后,才放弃占用CPU资源。

代码语言:javascript
复制
{
    /* 在尝试获得锁的过程中旋转,直到`lock_word`变成空闲状态 */
    os_rmb;
    while (i < srv_n_spin_wait_rounds && lock->lock_word <= X_LOCK_HALF_DECR) {
        if (srv_spin_wait_delay) {
            // 如果获取锁失败,则调用`ut_delay`来引入随机延迟
            ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
        }
        i++;
    }
    spin_count += i;
    if (i >= srv_n_spin_wait_rounds) {
        // 如果达到旋转等待次数的上限后,主动让出当前占用的CPU时间片
        os_thread_yield();
    } else {
        // 否则,返回到锁等待循环,再次尝试获取锁
        goto lock_loop;
        // 注意这里的`goto lock_loop;`实际上是永远不会执行的,因为它后面紧跟着的是`os_thread_yield();`
        os_thread_yield();        
        // 主动让出当前占用的CPU时间片
    }
...
ulong srv_n_spin_wait_rounds  = 30; // 自旋等待循环的次数,即尝试获取锁的最大自旋次数
ulong srv_spin_wait_delay = 6;      // 自旋等待之间的延迟时间

其中 ulong srv_n_spin_wait_rounds 的值由 参数innodb_sync_spin_loops 决定,ulong srv_spin_wait_delay的值由 innodb_spin_wait_delay

ut_delay是Mysql中轻量级锁、读写锁做自旋时,用于产生一个pause暂时让出CPU,避免SPINLOCK引擎严重的CPU性能问题的一个公共函数。每次ut_delay默认执行pause指令300次( innodb_spin_wait_delay=6*50)

代码语言:javascript
复制
ut_delay(
/*=====*/
  ulint delay)  /*!< in: delay in microseconds on 100 MHz Pentium */
{
  ulint i, j;

  UT_LOW_PRIORITY_CPU();
  j = 0;

  for (i = 0; i < delay * 50; i++) {
    j += i;
    UT_RELAX_CPU();
  }
  UT_RESUME_PRIORITY_CPU();
  return(j);
}
# define UT_RELAX_CPU() asm ("pause" ) 
# define UT_RELAX_CPU() __asm__ __volatile__ ("pause")

MySQL 自旋锁的参数

优化自旋锁的目的是降低自旋等待对CPU资源的消耗,同时确保系统能够及时响应。MySQL提供了一些系统变量来帮助调整自旋等待的行为。

innodb_spin_wait_delay: 该参数决定线程在每次自旋迭代后等待的时间。增加这个值能增加获取锁的平均时间,同时能会降低CPU的使用率,减少线程上下文切换。在CPU高度争用的环境下,比如高并发写入时,适当增大这个参数可能有助于性能提升。

innodb_sync_spin_loops: 该参数控制自旋等待循环的迭代次数。在高并发的系统中,减少此参数的值有助于线程更快地放弃自旋,从而减少 CPU 的使用。但是,这也意味着线程可能会更频繁地进入休眠状态。

注意:

优化没有银弹。。

如果spinlock相关参数设置的不合理,那么就会出现 ut_delay 休眠的时间过长引起性能问题的情况出现,因为不同的CPU执行pause的时候,暂停的CPU周期数量并不相同,有的是3、40个周期,有的是100个周期。如果生产库上需要调整 这两个参数, 请务必在测试的时候 调大或者调小结合 perf top 命令观察相关函数的调用情况。

参考阅读

  1. https://www.cnblogs.com/chenpingzhao/p/5043746.html
  2. https://www.modb.pro/db/1680772051538878464
  3. 高并发数据库中的spinlock优化
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 yangyidba 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二 CPU自旋锁的工作机制
    • 什么是 自旋锁
      • 为什么要用自旋锁
      • 三 在MySQL中使用 Spin Lock 的场景
        • 相关代码:
          • MySQL 自旋锁的参数
            • 参考阅读
            相关产品与服务
            云数据库 MySQL
            腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档