云计算之路-阿里云上:“黑色1秒”问题与2009年Xen一个补丁的故事
在之前对“黑色1秒”问题的分析博文中,我们将最大嫌疑对象锁定在了Xen,在这篇博文我们将从Xen的角度进行分析。也许有人会问,为什么不知道天多高地多厚地去研究不属于自己范围的问题?只因我们对一个问题的强烈好奇心——究竟是不是我们用Windows的错?
(注1:文中所说的Xen补丁问题只是提供一种分析问题的思路,我们遇到的“黑色1秒”问题与有没有打这个补丁没有关系)
(注2:关于这个Xen补丁背后的故事,推荐阅读阿里云分享的博文:云计算之路:2009年Xen一个补丁背后那不为人知的故事)
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中寻找。。。
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一个补丁的故事的更多相关文章
- 云计算之路-阿里云上:从ASP.NET线程角度对“黑色30秒”问题的全新分析
在这篇博文中,我们抛开对阿里云的怀疑,完全从ASP.NET的角度进行分析,看能不能找到针对问题现象的更合理的解释. “黑色30秒”问题现象的主要特征是:排队的请求(Requests Queued)突增 ...
- 云计算之路-阿里云上:Web服务器遭遇奇怪的“黑色30秒”问题
今天下午访问高峰的时候,主站的Web服务器出现奇怪的问题,开始是2台8核8G的云服务器(ECS),后来又加了1台8核8G的云服务器,问题依旧. 而且3台服务器特地使用了不同的配置:1台是禁用了虚拟内存 ...
- 云计算之路-阿里云上:原来“黑色0.1秒”发生在socket读取数据时
在昨天的博文(云计算之路-阿里云上:读取缓存时的“黑色0.1秒”)中我们犯了一个很低级的错误——把13ms算成了130ms(感谢陈硕发现这个错误!),从而对问题的原因作出了错误的推断,望大家谅解! 从 ...
- 云计算之路-阿里云上:SLB会话保持的一个坑
冒着被大家厌烦的风险,今天再发一篇“云计算之路-阿里云上”.这是在前一篇发过之后真实发生的事情,我们觉得定位问题的过程值得分享.而且估计园子里不少朋友被这个问题骚扰过,我们有责任让大家知道问题的真正原 ...
- 云计算之路-阿里云上-容器难容:容器服务故障以及自建 docker swarm 集群故障
3月21日,由于使用阿里云服务器自建 docker swarm 集群的不稳定,我们将自建 docker swarm 集群上的所有应用切换阿里云容器服务 swarm 版(非swarm mode). 3月 ...
- 云计算之路-阿里云上-新发现:又一种与虚拟内存有关的CPU波动情况
在云上真是无奇不有,昨天偶然间发现在IIS的应用程序池回收设置中,仅仅设置了一下基于虚拟内存限制的回收,就引发了CPU有规律的波动.在这篇博文中,我们将向大家汇报一下云计算之路上的这个小发现. 在之前 ...
- 云计算之路-阿里云上:启用Windows虚拟内存引发的CPU 100%故障
今天上午11:35~11:40左右,由于负载均衡中的两台云服务器CPU占用突然飚至100%,造成网站5分钟左右不能正常访问,请大家带来了麻烦,请谅解! (上图中红色曲线表示CPU占用) 经过分析,我们 ...
- 云计算之路-阿里云上:禁用Windows虚拟内存引发的重启
昨天(2013年8月6日)下午,承载www.cnblogs.com主站的两台云服务器分别自动重启了1次,由于这两台云服务器使用了负载均衡(SLB),重启并未影响网站的正常访问. 与这次重启相关的Win ...
- 云计算之路-阿里云上:OCS问题的进展以及11:30-11:50遇到的问题
(上图是今天出问题期间Web服务器性能监控图,紫色表示的是Request Execution Time) 昨天我们发布了一篇博客分享了我们这两天遇到的OCS(开放缓存服务)问题,详见云计算之路-阿里云 ...
随机推荐
- 【牛客挑战赛30D】小A的昆特牌(组合问题抽象到二维平面)
点此看题面 大致题意: 有\(S\)张无编号的牌,可以将任意张牌锻造成\(n\)种步兵或\(m\)种弩兵中的一种,求最后步兵数量大于等于\(l\)小于等于\(r\)的方案数. 暴力式子 首先我们来考虑 ...
- fast、faster中ap值的计算
def voc_ap(rec, prec, use_07_metric=False): """ ap = voc_ap(rec, prec, [use_07_metric ...
- 【洛谷P1367】蚂蚁
蚂蚁 [题目描述] 在一根无限长的木棍上,用n只蚂蚁,每只蚂蚁有一个初始位置和初始朝向,蚂蚁们以每秒一个单位的速度向前移动,当两只蚂蚁相遇时,它们会掉头(掉头时间忽略不计).现给出每只蚂蚁的初始位置和 ...
- LeetCode14.最长公共前缀 JavaScript
编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...
- CSS实战3
1. z-index 层级 div 层 <!DOCTYPE html> <html> <head lang="en"> <meta ...
- some small knowledge
cookie 增查 <!--1.语义化标签的作用--> <!--1.1 从开发角度考虑是提高代码的可读性可维护性--> <!--1.2 网站的发布者:seo 搜索引擎优化 ...
- 在react中实现CSS模块化
react中使用普通的css样式表会造成作用域的冲突,css定义的样式的作用域是全局,在Vue 中我们还可以使用scope来定义作用域,但是在react中并没有指令一说,所以只能另辟蹊径了.下面我将简 ...
- Python基础—04-流程控制
流程控制 循环结构(while) 格式 while 表达式: 语句块 执行流程:当程序执行到while语句时,首先判断表达式的真假.若表达式的值为真,则执行对应的语句块,之后返回while继续判断表达 ...
- 原生js方面的兼容性问题
1.关于获取行外样式 currentStyle 和 getComputedStyle 出现的兼容性问题 我们都知道js通过style不可以获取行外样式,当我们需要获取行外样式时: 我们一般通过这两 ...
- Mybatis中使用UpdateProvider注解实现根据主键批量更新
Mapper中这样写: @UpdateProvider(type = SjjcSqlProvider.class, method = "updateTaskStatusByCBh" ...