终于彻底搞清楚了 MySQL spin-lock 之一次CPU问题定位过程总结

自旋锁 pause版权看源码的时候get的一个新的知识点,可以提升自旋锁spinlock的性能-pause指令,看到的源码如下:

define UT_RELAX_CPU() asm (“pause” )

define UT_RELAX_CPU() asm volatile (“pause”)

经过上网查找资料pause指令。当spinlock执行lock()获得锁失败后会进行busy loop,不断检测锁状态,尝试获得锁。这么做有一个缺陷:频繁的检测会让流水线上充满了读操作。另外一个线程往流水线上丢入一个锁变量写操作的时候,必须对流水线进行重排,因为CPU必须保证所有读操作读到正确的值。流水线重排十分耗时,影响lock()的性能。

自旋锁spinlock剖析与改进Pause指令解释(from intel):Description Improves the performance of spin-wait loops. When executing a “spin-wait loop,” a Pentium 4 or Intel Xeon processor suffers a severe performance penalty when exiting the loop because it detects a possible memory order violation. The PAUSE instruction provides a hint to the processor that the code sequence is a spin-wait loop. The processor uses this hint to avoid the memory order violation in most situations, which greatly improves processor performance. For this reason, it is recommended that a PAUSE instruction be placed in all spin-wait loops.

MySQL spin lock处理代码

===================

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

rw_lock_sx_lock_func( // 加sx锁函数

{

/* Spin waiting for the lock_word to become free */

os_rmb;

while (i < srv_n_spin_wait_rounds

&& lock->lock_word <= X_LOCK_HALF_DECR) {

if (srv_spin_wait_delay) {

ut_delay(ut_rnd_interval(

0, srv_spin_wait_delay)); // 加锁失败,调用ut_delay

}

i++;

}

spin_count += i;

if (i >= srv_n_spin_wait_rounds) {

os_thread_yield(); //暂停当前正在执行的线程对象(及放弃当前拥有的cup资源)

} else {

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

os_thread_yield(); //暂停当前正在执行的线程对象(及放弃当前拥有的cup资源)

}

ulong srv_n_spin_wait_rounds = 30;

ulong srv_spin_wait_delay = 6;

注:上面代码,线程中的yield()方法说明

yield 多线程版权Thread.yield()方法作用是:暂停当前正在执行的线程对象(及放弃当前拥有的cup资源),并执行其他线程。yield()做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。

每次ut_delay默认执行pause指令300次( innodb_spin_wait_delay=6*50)

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”)

操作系统中,SYS和USER这两个不同的利用率代表着什么?


操作系统中,SYS和USER这两个不同的利用率代表着什么?或者说二者有什么区别?

简单来说,CPU利用率中的SYS部分,指的是操作系统内核(Kernel)使用的CPU部分,也就是运行在内核态的代码所消耗的CPU,最常见的就是系统调用(SYS CALL)时消耗的CPU。而USER部分则是应用软件自己的代码使用的CPU部分,也就是运行在用户态的代码所消耗的CPU。比如ORACLE在执行SQL时,从磁盘读数据到db buffer cache,需要发起read调用,这个read调用主要是由操作系统内核包括设备驱动程序的代码在运行,因此消耗CPU计算到SYS部分;而ORACLE在解析从磁盘中读到的数据时,则只是ORACLE自己的代码在运行,因此消耗的CPU计算到USER部分。

那么SYS部分的CPU主要会由哪些操作或是系统调用产生呢?具体如下所示。

1> I/O操作。比如读写文件、访问外设、通过网络传输数据等。这部分操作一般不会消耗太多的CPU,因为主要的时间消耗会在1/O操作的设备上。比如从磁盘读文件时,主要的时间在磁盘内部的操作上,而消耗的CPU时间只占I/O操作响应时间的一少部分。只有在过高的并发I/O时才可能会使得SYS CPU 有所增加。

2> 内存管理。比如应用程序向操作系统申请内存,操作系统维护系统可用内存,交换空间换页等。其实与ORACLE类似,越大的内存,越频繁的内存管理操作,CPU的消耗会越高。

3> 进程调度。这部分CPU的使用,在于操作系统中运行队列的长短,越长的运行队列,表明越多的进程需要调度,那么内核的负担就越高。

4> 其他,包括进程间通信、信号量处理、设备驱动程序内部的一些活动等等。

什么是用户态?什么是内核态?如何区分?


一般现代CPU都有几种不同的指令执行级别。

在高执行级别下,代码可以执行特权指令,访问任意的物理地址,这种CPU执行级别就对应着内核态。

而在相应的低级别执行状态下,代码的掌控范围会受到限制。只能在对应级别允许的范围内活动。

举例:

intel x86 CPU有四种不同的执行级别0-3,linux只使用了其中的0级和3级分别来表示内核态和用户态。

系统调用与context switch


进程上下文切换,是指从一个进程切换到另一个进程运行。而系统调用过程中一直是同一个进程在运行

系统调用过程通常称为特权模式切换,而不是上下文切换。当进程调用系统调用或者发生中断时,CPU从用户模式(用户态)切换成内核模式(内核态),此时,无论是系统调用程序还是中断服务程序,都处于当前进程的上下文中,并没有发生进程上下文切换。

当系统调用或中断处理程序返回时,CPU要从内核模式切换回用户模式,此时会执行操作系统的调用程序。如果发现就需队列中有比当前进程更高的优先级的进程,则会发生进程切换:当前进程信息被保存,切换到就绪队列中的那个高优先级进程;否则,直接返回当前进程的用户模式,不会发生上下文切换。

system call

System calls in most Unix-like systems are processed in kernel mode, which is accomplished by changing the processor execution mode to a more privileged one, but no process context switch is necessary

context switch

Some operating systems(Not include Linux) also require a context switch to move between user mode and kernel mode tasks. The process of context switching can have a negative impact on system performance

通过vmstat查看context switch


一般vmstat工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数,如:

root@local:~# vmstat 2 1

procs -----------memory---------- —swap-- -----io---- -system-- ----cpu----

r b swpd free buff cache si so bi bo in cs us sy id wa

1 0 0 3498472 315836 3819540 0 0 0 1 2 0 0 0 100 0

context switch 高,导致的争用其它案例


有很多种情况都会导致 context switch。MySQL 中的 mutex 和 RWlock 在获取不成功后,短暂spin,还不成功,就会发生 context switch,sleep,等待唤醒。

在 MySQL中,mutex 和 RWlock导致的 context switch,一般在show global status,show engine innodb mutex,show engine innodb status,performance_schema等中会体现出来,针对不同的mutex和RWlock等待,可以采取不同的优化措施。

除了MySQL的mutex和RWlock,还发现一种情况,是MySQL外的mutex竞争导致context switch高。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

image

image

其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
存中…(img-flKfRxz6-1712505312495)]

[外链图片转存中…(img-kVQpPaOG-1712505312495)]

其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值