MySQL得益于其开源属性、成熟的商业运作、良好的社区运营以及功能的不断迭代与完善,已经成为互联网关系型数据库的标配。可以说,X86服务器、Linux作为基础设施,跟MySQL一起构建了互联网数据存储服务的基石,三者相辅相成。
本文将分享一个工作中的实践案例:因Intel PAUSE指令周期的迭代,引发了MySQL的性能瓶颈,美团MySQL DBA团队如何基于这三者来一步步进行分析、定位和优化。希望这些思路能对大家有所启发。
1. 背景
在2017年,Intel发布了新一代的服务器平台Purley,并将Intel Xeon Scalable Processor(至强可扩展处理器)重新划分为:Platinum(铂金)、Gold(金)、Silver(银)、Broze(铜)等四个等级。产品定位和框架也变得更加清晰。
因美团线上海量数据交易和存储等后端服务依赖大量高性能服务器的支撑。随着线上部分Grantly平台E系列服务器生命周期的临近,以及产品本身的发展和迭代。2019年开始,RDS(关系型数据库服务)后端存储(MySQL)开始大量上线Purley平台的Skylake CPU服务器,其中包含Silver 4110等。
Silver 4110相比上一代E5-2620 V4,支持更高的内存频率、更多的内存通道、更大的L2 Cache、更快的总线传输速率等。Intel官方数据显示Silver 4110的性能比上一代E5-2620 V4提升了10%。
然而,随着线上Skylake服务器数量的增加,以及越来越多的业务接入。美团MySQL DBA团队发现部分MySQL实例性能与预期并不相符,有时甚至出现较大程度的下降。经过持续的性能问题分析,我们定位到Skylake服务器存在性能瓶颈:
- CPU负载相对较高。
- TPS等吞吐量下降。
接下来,我们将从Intel CPU、ut_delay函数、PAUSE指令三方面入手,进行剖析定位,并探索相关优化方案。
2. 性能问题分析
2.1 Grantly与Purley CPU性能差异
首先,基于上述两代平台的CPU(Grantly和Purley),通过基准测试,横向对比在不同OS下的性能表现。
通过基准测试数据,总结如下:
- 在oltp_write_only(只写)的场景下Purley 4110的性能下降较为明显。
- 同为Purley 4110,CentOS 7比CentOS 6 oltp_write_only(只写)性能有提升。
我们通过二维折线图,来展示性能之间的差异:
在上图中,同为Purley 4110,CentOS 7比CentOS 6性能有提升。具体提升原因,因不涉及本文重点内容,所以不在这里详细展开了。
New MCS-based Locking Mechanism
Red Hat Enterprise Linux 7.1 introduces a new locking mechanism, MCS locks. This new locking mechanism significantly reduces spinlock overhead in large systems, which makes spinlocks generally more efficient in Red Hat Enterprise Linux 7.1.
红帽官网Release Notes显示,从内核3.10.0-229开始,引入了新的加锁机制,MCS锁。可以降低spinlock的开销,从而更高效地运行。普通spinlock在多CPU Core下,同时只能有一个CPU获取变量,并自旋,而缓存一致性协议为了保证数据的正确,会对所有CPU Cache Line状态、数据,同步、失效等操作,导致性能下降。而MSC锁实现每个CPU都有自己的“spinlock”本地变量,只在本地自旋。避免Cache Line同步等,从而提升了相关性能。不过,社区对于spinlock的优化争议还是比较大的,后续又有大牛基于MSC实现了qspinlock,并在4.x的版本上patch了。具体实现可以参看:MCS locks and qspinlocks。
在大致了解CentOS 7性能的迭代后,接下来我们深入分析一下Skylake CPU 4110导致性能下降的缘由。
3. CPU性能跟踪
3.1 定位热点函数
具体定位4110性能瓶颈,分如下几步:
- 首先,通过perf top来跟踪一下Linux CPU性能开销。
- 然后,通过perf record记录函数CPU周期的消耗占比。
- 最后,通过火焰图来验证定位热点函数。
可以看到,其中占CPU消耗占比较大为:ut_delay函数。
我们继续深挖一下函数链调用关系:
........ ........ ....... ................... ..................................................................................................................................................................................
define UT_RELAX_CPU() asm (&34; )
34;pause&39;s also a small power benefit in 2-core and 4-core systems.As the PAUSE latency has been increased significantly, workloads that are sensitive to PAUSE latency will suffer some performance loss.
…
- 上一代架构中(Grantly平台E系列)PAUSE的周期时长为10 cycles,新一代的Skylake架构中则为140 cycles。
- 如果程序中使用固定次数的PAUSE循环来实现一段时间的延迟,以此阻塞程序执行,可能引发非预期的延迟。
- 由于PAUSE周期增加,对于PAUSE敏感的应用会有一定的性能损失。
衡量程序执行性能的简化公式:
ExecutionTime(T)=InstructionCount∗TimePerCycle∗CPI
即:程序执行时间 = 程序总指令数 x 每CPU时钟周期时间 x 每指令执行所需平均时钟周期数。
MySQL内部自旋,就是通过固定次数的PAUSE循环实现。可知,PAUSE指令周期的增加,那么执行自旋的时间也会增加,即程序执行的时间也会相对增加,对系统整体的吞吐量就会有影响。
显然,Intel文档已说明不同平台、不同架构CPU PAUSE定义的周期是不一样的。
下面,我们通过一个测试用例来大致验证、对比一下新老架构CPU执行PAUSE的cycles:
define TIMES 5
static inline unsigned long long rdtsc(void){
unsigned long low, high;
asm volatile(&34; : &34; (low), &34; (high) );
return ((low) | (high) << 32);
}
void pause_test()
{
int i = 0;
for (i = 0; i < TIMES; i++) {
asm(
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;\
&34;
::
:);
}
}
unsigned long pause_cycle()
{
unsigned long start, finish, elapsed;
start = rdtsc();
pause_test();
finish = rdtsc();
elapsed = finish - start;
printf(&34;, elapsed / 100);
return 0;
}
int main()
{
pause_cycle();
return 0;
}
其运行结果统计如下:
- 4110和5118 PAUSE周期较大,均为100多,它们属于Purley第一代架构:Skylake。
- 4210和5218 PAUSE相比前一代有提升,是因为它们同属Purley第二代架构:Cascadelake,该代CPU PAUSE指令有优化。
3.2.3 Intel 提升PAUSE猜想
Intel提高PAUSE指令周期的原因,推测可能是减少自旋锁冲突的概率,以及降低功耗;但反而导致PAUSE执行时间变长,降低了整体的吞吐量。
The increased latency (allowing more effective utilization of competitively-shared microarchitectural resources to the logical processor read to make forward progress) has a small positive performance impact of 1-2% on highly threaded applications. It is expected to have negligible impact on less threaded applications if forward progress is not blocked executing a fixed number of looped PAUSE instructions.
3.3 PAUSE导致写瓶颈分析
接下来,我们深入分析一下PAUSE指令导致MySQL写瓶颈的原因。
首先,通过MySQL 内部统计信息,查看一下InnoDB信号量监控数据:
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 153720
--Thread 139868617205504 has waited at row0row.cc line 1075 for 0.00 seconds the semaphore:
X-lock on RW-latch at 0x7f4298084250 created in file buf0buf.cc line 1425
a writer (thread id 139869284108032) has reserved it in mode SX
number of readers 0, waiters flag 1, lock_word: 10000000
Last time read locked in file not yet reserved line 0
Last time write locked in file /mnt/workspace/percona-server-5.7-redhat-binary-rocks-new/label_exp/min-centos-7-x64/test/rpmbuild/BUILD/percona-server-5.7.26-29/percona-server-5.7.26-29/storage/innobase/buf/buf0flu.cc line 1216
OS WAIT ARRAY INFO: signal count 441329
RW-shared spins 0, rounds 1498677, OS waits 111991
RW-excl spins 0, rounds 717200, OS waits 9012
RW-sx spins 47596, rounds 366136, OS waits 4100
Spin rounds per wait: 1498677.00 RW-shared, 717200.00 RW-excl, 7.69 RW-sx
可见写操作并阻塞在:storage/innobase/buf/buf0flu.cc第1216行调用上。
跟踪一下发生等待的源码:buf0flu.cc line 1216:
if (flush_type == BUF_FLUSH_LIST
&& is_uncompressed
&& !rw_lock_sx_lock_nowait(rw_lock, BUF_IO_WRITE)) { // 加锁前,判断锁冲突
if (!fsp_is_system_temporary(bpage->id.space())) {
/* avoiding deadlock possibility involves
doublewrite buffer, should flush it, because
it might hold the another block->lock. */
buf_dblwr_flush_buffered_writes(
buf_parallel_dblwr_partition(bpage,
flush_type));
} else {
buf_dblwr_sync_datafiles();
}
rw_lock_sx_lock_gen(rw_lock, BUF_IO_WRITE); // 加sx锁
}
...
39;t expect overflow here, as ut::spin_wait_pause_multiplier is limited
to 100, and values of delay are not larger than @@innodb_spin_wait_delay
which is limited by 1 000. Anyway, in case an overflow happened, the program
would still work (as iterations is unsigned). */
const ulint iterations = delay * ut::spin_wait_pause_multiplier;
UT_LOW_PRIORITY_CPU();
j = 0;
for (i = 0; i < iterations; i++) {
j += i;
UT_RELAX_CPU();
}
UT_RESUME_PRIORITY_CPU();
return (j);
}
...
namespace ut {
ulong spin_wait_pause_multiplier = 50;
}
4.2.3 移植spin_wait_pause_multiplier patch优化
既然MySQL 8.0参数spin_wait_pause_multiplier可以控制PAUSE执行的时长,那么就可以减少该值,从而降低整体PAUSE影响。
了解MySQL 8.0相关代码后,我们将该patch移植到线上的稳定版本:
MySQ >select version();
+------------------+
| version() |
+------------------+
| 5.7.26-29-mt-log |
+------------------+
1 row in set (0.00 sec)
MySQL>show global variables like &39;;
+-----------------------------------+-------+
| Variable_name | Value |
+-----------------------------------+-------+
| innodb_spin_wait_delay | 6 |
| innodb_spin_wait_pause_multiplier | 5 |
| innodb_sync_spin_loops | 30 |
+-----------------------------------+-------+
3 rows in set (0.00 sec)
由上述可知,Silver 4110的PAUSE cycles是E5-2620 v4的14倍左右。基于此,将innodb_spin_wait_pause_multiplier值调整为默认值的1/14,取稍大值:5。即将该参数由原默认的50调整为5。
最后,还是通过二维折线图来对比该patch调优后的基准测试数据:
- Silver 4110移植spin_wait_pause_multiplier patch,并调整优化后,4110(patch)性能有了较大的提升。
- Silver 4110(patch) 相对调优innodb_spin_wait_delay性能上更优。
- Silver 4110(patch)并发线程大于64的只写场景,性能略低于E5-2620 V4 ,其他均优。
- 按照真实的线上读写比例,4110(patch)可以将吞吐量恢复到原先的性能水平。
4.3 PAUSE指令周期优化
上述章节中,我们测出Cascadelake CPU PAUSE周期下降了。在跟Intel技术专家确认后得知:从Purley的第二代产品Cascadelake开始,Intel将PAUSE的指令周期降低到了44。(估计Intel也发现了第一代增加PAUSE周期后的性能瓶颈问题。)
我们针对第二代CPU产品继续做基准测试,来看一下性能表现:
接着用perf diff来对比一下4110和4210在ut_delay上的开销:
- 可以看到4210比4110占比下降了8%。
- 由于PAUSE指令周期还是数倍于E5系列CPU,4210在高负载下,PAUSE的开销对MySQL吞吐量还是有较大的影响。而在128并发线程以下,性能相比4110有了较大的提升。按理,可以满足线上业务需求(该测试结果跟移植spin_wait_pause_multiplier patch性能测试数据曲线一致)。
5. 总结
最后针对本篇内容,我们可以做个简单的总结:
Intel在新平台CPU产品调大了PAUSE指令周期,在高并发spinlock竞争激烈场景下,可能会造成程序性能较大损耗(特别是执行固定PAUSE次数的程序)。
1. 针对Skylake架构CPU(比如:4110等)PAUSE指令周期较长引起性能问题的优化方法如下:
- 将MySQL 8.0 innodb_spin_wait_pause_multiplier patch移植到线上稳定版本(或升级到MySQL 8.0),通过降低PAUSE执行时长,来提升吞吐量。
- 如果是OS为CentOS 6,可以升级到CentOS 7,CentOS 7本身spinlock优化,对MySQL性能也有一定提升。
- 最简单、直接的方法可以替换为Cascadelake架构CPU。
2. 针对Cascadelake架构CPU,由于Intel本身在PAUSE周期已经优化,性能上已经做了修复。当然也可以采用上述优化方案,让性能提升一个台阶。
6. 作者简介
春林,2017年加入美团,主要负责MySQL运维开发和优化工作。
---------- END ----------
招聘信息
美团DBA团队招聘各类人才,Base北京、上海均可。我们致力于为公司提供稳定、可靠、高效的在线存储服务,打造业界领先的数据库团队。这里有数万各类架构的MySQL实例,每天提供万亿级的OLTP访问请求。真正的海量、分布式、高并发环境。欢迎感兴趣的同学发送简历至:tech@meituan.com(邮件标题注明:美团DBA团队)