云计算之路-阿里云上:“黑色1秒”问题与2009年Xen一个补丁的故事

在之前对“黑色1秒”问题的分析博文中,我们将最大嫌疑对象锁定在了Xen,在这篇博文我们将从Xen的角度进行分析。也许有人会问,为什么不知道天多高地多厚地去研究不属于自己范围的问题?只因我们对一个问题的强烈好奇心——究竟是不是我们用Windows的错?

2009年3月20日,来自Intel的Yu Ke通过Xen-dev Mailing List给来自Citrix的Keir
Fraser(负责的Xen开发者之一)发了一封邮件,提交了Xen的一个patch——cpuidle: suspend/resume scheduler tick
timer during cpu idle entry/exit.

这个补丁的用途是什么呢?

cpuidle can collaborate with scheduler to reduce unnecessary timer
interrupt. For example, credit scheduler accounting timer doesn‘t need to be
active at
idle time, so it can be stopped at cpuidle entry and resumed at
cpuidle exit. This patch implements this function by adding two ops in
scheduler:
tick_suspend/tick_resume, and implement them for credit
scheduler.

上面的文字是邮件中的第一段内容,大意是:Xen中的cpuidle(在物理CPU没有被分配VCPU时,cpuidle可以让物理CPU进入C-state,好处之一是省电,详见这里)可以与CPU调度器(负责CPU的调度,关于Xen中的CPU调度,详见这里)一起协作从而减少不必要的时钟中断。比如,当CPU空闲时,credit
scheduler(Xen中的一种CPU调度算法,详见这里)的accounting
timer就没有继续工作的必要,所以可以让它在cpuidle时停止工作,在退出cpuidle时再唤醒它。这个patch通过添加tick_suspend/tick_resum这两个调度器操作来实现这个。

简而言之,这个补丁的用途是——在CPU空闲时,让调度器也休息;当CPU工作时,再把调度器唤醒。

应该这个补丁会带来什么好处呢?

With this patch, under idle scenario, timer interrupt frequency decreased
from ~100HZ to ~10HZ, and average C state residency increase from ~10ms to
larger than 100ms. Also in a two-socket machine, about 4% idle power saving is
observed.

上面的文字是文字是邮件中的第二段内容,大意是:用了这个补丁,在CPU空闲场景下,时钟中断频率由~100HZ减少到~10HZ,平均的C状态(CPU的电源管理状态,详见这里)停留时间从10ms增加到100ms(看到这让我们想到“黑色0.1秒”)。在有2颗CPU的机器上,从观察情况看,可以节省4%的电量。

简单言之,这个补丁的好处是——省电。

这个补丁的临床试验情况怎么样?

However, one issue is observed with this patch, i.e. there is soft-lockup
in dom0 occasionally. This issue is still under debugging. Currently we
already find a >1s VCPUOP_set_singleshot_timer timeout, which imply this
may be a dom0 issue. we are working hard to figure the root
cause.

上面的文字是文字是邮件中的第三段内容,大意是:应用这个补丁后,观察到一个症状。在dom0(Xen中的特权虚拟机,“内部包含了真实的设备驱动,可直接访问物理硬件”)中偶尔会出现软死锁(soft-lockup),而且发现大于1秒的VCPUOP_set_singleshot_timer(详见Xen的domain.c代码)超时的情况,这暗示了dom0中可能藏着某个坑。

注意!这里的1秒!这个“1秒”与“黑色1秒”中的“1秒”,是偶然的巧合,还是本是同根生?这个地方是一个非常重要的线索,让我们看到了走出“黑色1秒”最有希望的一线光明。

继续看这封邮件中接下来的内容:

Considering the very visible effect of this patch, and the issue mentioned
above only occurs when cpuidle is enabled, and has no impact to normal user,
we
finally decide to send out this patch to see if it is possible for 3.4
inclusion. In the bug fix phase, we will send out bug fix for the
issue.

大意是:考虑到这个补丁诱人的省电效果(省电就是省钱啊),而且上面提到的问题(疑似黑色1秒)只在启用cpuidle的情况下发生,不会影响到正常普通用户(这地方有点疑惑,什么才是普通用户?),最终决定发出这个补丁(似乎缺少了一点不放过任何一个问题的偏执)。

接下来我们看看负责向Xen提交代码的Keir Fraser的回复

I don‘t really want to take the patch while it is soft locking up. I would
expect linux-2.6.18-xen.hg:22 to avoid lockup warnings due to too
long
singleshot timeouts (I assume you are testing with the 2.6.18
tree?).

Personally I would rather have cpuidle be enabled by default
(or even always with no disable option) and get existing Cx benefits for
everyone, rather
than have a slightly broken cpuidle option.

Is
there a reason not to turn on cpuidle by default now? Or even enable
and
then remove the boot option?

还好Keir Fraser不愿放过这个小问题,他希望解决软死锁问题之后再发布这个补丁,而且他希望默认开启cpuidle。这里可以看出Keir
Fraser坚持的原因,如果默认开启cpuidle,这个问题的影响就会很大。

再看一下Yu Ke紧接着的回复

Right, I am testing it with 2.6.18 tree. I am also looking into the dom0
code, to see if should change dom0.

There is no obvious obstacle to turn on cpuidle by default. According to
our testing and measurement, cpuidle is pretty stable now, maybe it is time to
enable it by default.

Keir Fraser的坚持打动了Yu Ke,决定寻找并填掉这个坑,并且他也希望默认开启cpuidle。

那Yu Ke究竟有没有找到这个坑,有没有填平这个坑?

去哪里寻找答案?我们想到了Xen的git日志

2009年3月31日,Keir Fraser向Xen代码库提交了Yu Ke完成的补丁代码。在这个提交中,只字未提坑的事。

这个坑究竟有没有被填平呢?照之前Keir Fraser的性格,应该不会有让有坑的代码提交上去。所以,我们更关注的是这个坑究竟是怎么被填平的?

于是,我们又回到Xen-devel mailing list中寻找。。。

终于找到了:[Xen-devel] [PATCH] cpuidle: suspend/resume scheduler tick timer
during cpu idle entry/exit V2- msg#01762

2009年3月26日Yu Ke向Keir Fraser发了一封邮件并提交了填好坑的代码:

Hi Keir,

This attached is the version 2 of the patch. The major update is fixing the
soft-lockup issue.

The root cause is: sched_tick_suspend will call __stop_timer and may raise
TIMER_SOFTIRQ if the timer deadline is changed. In this case, the assumption
of
no softirq pending in acpi_processor_idle is broken, and later the hpet
broadcast wakeup IPI will not be delivered to this CPU, since its softirq
pending bit is set. Then the CPU will be sleeping until random external
interrupt happen. To fix this issue, the sched_tick_suspend is moved before
the softirq pending bit checking, to keep the assumption correct.

I also measure the performance by SPECJbb in dom0, no performance
degradation observed.

Best Regards
Ke

原来Yu Ke遇到的“黑色1秒”问题的原因是这样的:

前面我们说过这个补丁的用途是在CPU空闲时,让调度器也休息;当CPU工作时,再把调度器唤醒。让调度器休息调用的是sched_tick_suspend(),而sched_tick_suspend则会调用_stop_timer(),如果这时时钟(Timer)的时间戳被改变,会触发TIMER_SOFTIRQ(时钟软中断,欲了解软中断的知识,详见这里),而坑就是这个软中断造成的。

开始的补丁代码是这样的:


if ( softirq_pending(smp_processor_id()) )
do_softirq();

sched_tick_suspend();
//...

开始的softirq_pending代码就是为了处理软中断,之后的代码就认为不会再出现软中断,可是在执行sched_tick_suspend()时在某种条件下(比如时钟时间戳被改变)会触发软中断,造成softirq
pending bit被设置了值;当CPU由空闲状态进入工作状态时(比如某个线程被调度到该CPU执行),系统会发出hpet(High Precision
Event Timer)广播唤醒IPI(Inter-processor interrupt)从而唤醒CPU,但由于当时处于softirq
pending状态,hpet到达不了这个CPU,于是CPU没有被唤醒,继续悠闲着。而那个需要被执行的线程只能傻傻地等着,直到CPU被外部的中断唤醒。

打个比方来说明一下CPU的这种状态。你中午吃过饭闲着没事想睡会觉,于是在iPad定了一下闹钟就开始睡觉;但是一个同事在你睡觉的时候把iPad设置为了静音,结果闹钟准时工作了,你却听不到,继续做着美梦直到有人叫你或打你手机,你才开始干活。

由此,我们联想到,我们遭遇“黑色1秒”问题时,CPU很可能处于同一种状况。HTTP.SYS的一个线程被调度到一颗空闲的CPU核,系统给美梦中的CPU发了一个通知——“快起床,开始快活啦!”,结果某种原因造成CPU没收到,继续美梦。而HTTP.SYS的线程只能傻等着,直到1秒后,有人直接去敲CPU的门把CPU叫醒,于是CPU开始忙活起来。

这时你也许会问,如果真是这样的话,那只会造成当时线程卡住。为什么“黑色1秒”期间,所有的HTTP.SYS线程都会卡住?那是因为HTTP.SYS不是一般人,它运行于Windows的内核模式,我们猜测HTTP.SYS很有可能用到spinlock,所以只要一个线程卡住,所有线程都无法干活(猜测依据的是我们在曾经遭遇的“黑色10秒”期间写的一篇博文,其中有一句话:“SpinLock是在Windows内核级别使用了”)。而如果是用户模式的线程(比如ASP.NET线程),就不会这样。从昨天进一步的监测数据看,在“黑色1秒”期间有时有些ASP.NET线程会卡住,但不会全部卡住。

在之前的分析中,我们有这样的猜想:

黑色10秒,黑色30秒,黑色1秒,黑色5秒。。。就叫黑色n秒吧。不管黑色多少秒,这些都只是问题的表象,而真正的黑色在虚拟机层面,更准确地说就是Xen。

而这一次,我们要作出更更准确的猜想——黑色n秒的问题很可能出在Xen的CPU调度环节。

2009年Xen那个的补丁引发的“黑色1秒”问题的解决方法出人意料地简单——只要把softirq_pending与sched_tick_suspend()的代码调换一下位置,让sched_tick_suspend()先执行。

而对于我们遇到的“黑色1秒”问题,只要阿里云从内心承认是Xen的问题,我们就觉得出人意料了!

不管怎么样,这次是黑色n秒问题最重要的一次突破,同时也让我们遇到了千载难逢的学习Xen的好机会!

云计算之路-阿里云上:“黑色1秒”问题与2009年Xen一个补丁的故事,布布扣,bubuko.com

时间: 2024-08-09 13:55:19

云计算之路-阿里云上:“黑色1秒”问题与2009年Xen一个补丁的故事的相关文章

云计算之路-阿里云上:对“黑色n秒”问题的最终猜想——CPU C-states引起的

如果说2013年云计算之路的主题是"踩坑",那么2014年我们希望云计算之路的主题变成"填坑"--当然填坑是阿里云来完成的,我们只是见证曾经的坑坑洼洼变成平坦大道. 15号(周四)晚上我们发现了SLB会话保持的坑,16号晚上阿里云成功定位并进行修复,这两天正式发布后会填平这个坑.这次从踩坑到填坑的过程是最痛快的一次. 接下来我们的目标锁定在"黑色n秒"(刚发现一个英文说法:stuck for x seconds)这个坑我们最多.最神秘.最诡异的坑

云计算之路-阿里云上:什么是“黑色1秒”?

为了更好地分享我们解决"黑色1秒"问题的过程,在这篇博文中我们将专门描述一下"黑色1秒"问题的表现. "黑色1秒"是我们使用阿里云以来继"黑色10秒"之后遭遇的最奇特.最诡异.最难以捉摸.最富有戏剧性的问题. 它有2个最显著的特征: 第一个是最直观的表现,在Windows性能监视器(Performace Monitor)中会出现1秒的ASP.NET Applications -> Requests/Sec(简称QPS)为

云计算之路-阿里云上:消灭“黑色n秒”第一招——不让CPU空闲

昨天对"黑色n秒"问题的最终猜想以失败而告终,从而让我们结束了被动猜想阶段,进入了主动进攻阶段--出招. 今天出第一招--用C#写个小程序,让其在每个CPU核上运行一个线程,不让任何一个CPU核进入空闲(idle)状态,以进一步排除CPU idle引起的"黑色n秒". 在这一招中,借助的最重要的武器是System.Diagnostics.ProcessThread.ProcessorAffinity.通过给ProcessorAffinity设置一个掩码,就可以指定当

云计算之路-阿里云上:消灭“黑色n秒”第二招——给w3wp进程指定CPU核

虽然昨天的第一招失败了,但是从失败中我们学到了与多核CPU相关的Processor Affinity(处理器关联)的知识. 既然我们可以让.NET程序的不同线程运行于指定的CPU核,那是不是也可以让IIS应用程序池的进程w3wp运行于指定的CPU核? 虽然看起来"黑色n秒"似乎与w3wp运行于哪些CPU核没有什么关系,但是我们既然把怀疑对象锁定在CPU,那么任何与CPU相关的线索都不能放过.即使失败,也会满载而归,因为如果没有"黑色n秒"这个问题的驱动,我们根本不会

云计算之路-阿里云上:“黑色1秒”最新线索——w3tp与w3dt

向大家分享一下最近排查"黑色1秒"问题的进展,"黑色1秒"的问题表现详见什么是黑色1秒. 1. 发生在w3wp进程内 判断依据:"黑色1秒"期间,http.sys的HTTP Service Request Queues\ArriveRate正常,W3SVC_W3WP\Requests/Sec正常. 2. 请求未进入.NET线程池 判断依据:"黑色1秒"期间静态文件的请求也不能被处理,如果"黑色1秒"发生在.

云计算之路-阿里云上:消灭“黑色n秒”第三招——禁用网卡的TCP/IP Offload

程咬金有三板斧,我们有三招.在这篇博文中我们要出第三招,同时也意味着昨天在"希望的田野"上的第二招失败了. 前两招打头(CPU)不凑效,这一招要换一个部位,但依然要坚持攻击敌人最弱(最忙最累)部位的原则.那除了CPU,最忙最累的部位是哪里呢?对于Web服务器来说,毫无悬念,当然是网卡.而且阿里云的云服务器,所有的网络负载都集中在一块内网网卡上,SLB(负载均衡)用它,OCS(缓存服务)用它,RDS(数据库服务)也用它.所以,就对它出招! 招式受这篇博文(XenServer – Wind

云计算之路-阿里云上:读取缓存时的“黑色0.1秒”

看到标题中的"0.1秒",你也许会呲之以鼻:不会吧,0.1秒也要计较,不是吃饱撑着,是没吃饱也撑着. 依然没撑着!在memcached应用场景中,响应速度是处于1ms级别的,0.1s可是比1ms慢了100倍啊. 如果你不相信1ms级别,请看这篇文章(微博CacheService架构浅析)中的一段话: 目前微博平台部分业务子系统的Cache服务已经迁移到了CacheService之上,它在实际的运行过程中也取得了良好的性能表现,目前整个集群在线上每天支撑着超过300W的QPS,平均响应耗

云计算之路-阿里云上:神奇的“黑色30秒”再次出现,究竟是谁的错?

自从4月28日我们从ASP.NET线程的角度对"黑色30秒"问题进行分析之后,我们采用了新的线程设置,然后观察"黑色30秒"是否再次出现. <processModel enable="true" requestQueueLimit="5000" maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50&q

云计算之路-阿里云上:原来“黑色0.1秒”发生在socket读取数据时

在昨天的博文(云计算之路-阿里云上:读取缓存时的"黑色0.1秒")中我们犯了一个很低级的错误--把13ms算成了130ms(感谢陈硕发现这个错误!),从而对问题的原因作出了错误的推断,望大家谅解! 从中我们吸取到了一个教训:趁热打铁要小心,容易失去冷静,作出错误的判断. 今天我们痛定思痛,用了一个下午的时间重新分析了"黑色0.1秒"问题,这次从EnyimMemcached的源代码下手(https://github.com/enyim/EnyimMemcached).