奔跑在虚拟化大路上的你 请看一看路边的荆棘 7月01

Tags

Related Posts

奔跑在虚拟化大路上的你 请看一看路边的荆棘

曾几何时,虚拟化还是个时髦的词儿,而如今,却似乎已如一夜春风吹遍大江南北。随便逛一圈,已经很难找到没有使用虚拟化技术的企业组织。实际上,有大量的企业全面实现虚拟化,连找一台物理实体机想用一下都很困难了。

虚拟化带来的好处毋庸置疑,无论是灵活性、资源有效利用率都比物理实体机要好上不少,更不用说在全球能源紧张的今天,数据中心正受到电力供应紧张的困扰,虚拟化在这方面也有着先天的优势。因此,越来越多人都觉得虚拟化能够完全取代物理实体机的方式提供服务器资源。

然而,任何看起来很美好的事情,都无法避免拥有晦暗的一面,至少在特定的应用场合,虚拟化还有明显的不足,包括虚拟CPU资源调度、宿主机的可用性与稳定性等。其中最难回避以下两个问题:

1. 密集压力下的性能

包括同一宿主机上多台虚拟机高密度运算请求下的CPU竞争问题,和同样场景下的IO瓶颈。

2. 系统时钟的准确性

关于第一个问题,涉及到CPU的调度、IO的调度和队列等问题,本文不打算深入分析阐述。本文主要是针对第二个问题进行展开,希望引起快速部署虚拟化的用户的重视。

众所周知,系统时钟准确性对于企业级应用来说,是非常重要的,试想一下运行着Oracle的服务器时钟慢了半小时,或是金融交易系统时钟快了10分钟……那都是非常可怕的事情,因此才有了NTP、PTP、GPS和CDMA等时钟同步的手段。也许你会说,以前没做时钟同步,系统的走时也挺准的。的确,以前的物理实体机,大部分的情况下走时都比较准确,因此就算不做时间同步,其误差也不会很大,对时间敏感度不高的应用来说没有明显影响。

但对于类似NetScout、Splunk这种需要精确时间戳来保证在海量数据中挖掘有效信息进行故障排除、分析等工作的应用来说,时间精确同步便是必要条件。

而这,正是当前的虚拟化技术水平下容易被忽略的问题之一。

如果找几个具有多年部署VMware经验的系统管理员来问一问:那些虚拟机的时钟走的准吗?得到的回答应该都是“不太准”。这是一个客观存在的事实,我们需要了解这种现象背后的机理,然后才能对症下药来最小化或消除这种现象带来的影响。

要了解虚拟机时钟不准的原因,我们还要从计算时间的机制说起。

操作系统通常情况下通过以下两种方式之一来测量时间的流逝:

1. 滴答计数——操作系统设置一个硬件设备按照一个已知的速率定期产生中断,例如100次每秒。然后操作系统处理这些叫做“滴答”的中断,保持对它的计数,来判断经过了多少时间。

2. 无滴答计时——一个硬件设备专用于计数自从系统启动以来已经过去的时间单元,操作系统只需在必要的时候读取这个计数器。无滴答计时有几个好处,通常情况下,它不需要CPU忙于处理中断,并且可以保持更好的时间精度。然而,无滴答计时只能应用在配备合适的硬件计数器的机器上。这个计数器必须运行在一个固定的速率上,能够被以合理的速度读取,并且永远不会溢出或者难得溢出,这样操作系统可以通过检测并统计溢出量来可靠地扩展它的范围。

除了对流逝的时间进行计数,操作系统同时还需要跟踪绝对时间,通常被叫做“挂钟时间”。一般情况下,操作系统在启动时从电脑的主板电池供电的实时时钟来读取最近的挂钟时间,或通过查询NTP(网络时间协议)服务器来获取一个更精准的时间。然后利用以上描述的两种方法之一来计算时间流逝。另外,操作系统可能会运行一个守护进程定期查询NTP时钟来校准较长窗口的时间偏移或其他计时错误。

滴答计数

许多基于PC架构的操作系统使用滴答计数来计时。不幸的是,对虚拟机来说,要支持这种计时方式的准确度是很困难的。

虚拟机们与宿主主机操作系统(或VMWare ESX的VMkernel)共享底层的硬件。其他应用和其他虚拟机可能也运行在同一台宿主机硬件上。当一台虚拟机应该产生一个虚拟计时中断时,它实际上可能并不在运行。事实上,这台虚拟机可能没机会再次运行,直到它积累了很多积压的计时中断。除此之外,就算是一台正在运行的虚拟机,有时候也可能延迟提交一个虚拟计时中断。这台虚拟机只在特定的时间点检查等待中的虚拟计时中断,例如当底层硬件收到一个真实计时中断时。许多操作系统并不提供一种途径让虚拟机在精确的时间点请求一个真实计时中断。

因为虚拟机操作系统通过统计中断数量来计时,所以一旦存在计时中断的积压,测量出来的时间就会落后于真实的时间。VMware的虚拟机对这个问题的处理方式是:通过跟踪当前的计时中断积压以及在积压增长得太大时以更高的速度提交计时中断来赶上时间。但是因为操作系统在完全处理完上一个计时中断前不会生成一个新的计时中断,所以实际上很难赶上时间。另一方面,操作系统可能无法将下一个计时中断识别成一个独立的事件而漏掉对其计数。这种现象被称为“丢滴答”。

如果一台虚拟机的钟走得太慢,那就有可能是它与其他虚拟机或宿主机进程产生了CPU时间竞争,并因此无法提供这台虚拟机足够的中断来保持它的时钟跟上真实时间而导致的结果。在当前的VMware产品设定中,如果中断积压增长超过了60秒,虚拟机将放弃追赶时间,取而代之的是简单地将积压清零。在这种情况发生后,如果虚拟机操作系统安装了VMware Tools并且激活了时钟同步功能(默认不激活),VMware Tools会将系统时间与宿主机时间进行同步,并恢复对中断积压的跟踪。

计时中断面临的另一个问题是扩展性问题:越来越多的虚拟机会运行在同一台物理机上面。即使一台虚拟机完全空闲,它也需要在每次收到计时中断时简单运行一下。如果一台虚拟机每秒请求100次中断,意味着它每秒会在一个均匀间隔下切换100次可用状态。粗略地讲,假设有N台虚拟机在运行,处理这些中断会在后台施加100xN次上下文交换每秒(上下文交换:context switch,又称环境切换,电脑术语,是一个储存和重建CPU的状态,因此令多个进程可以分享单一CPU资源的计算过程。要交换CPU上的进程时,必需先行储存目前行程的状态,再将欲执行的行程之状态读回CPU中),即使所有的N台虚拟机都处于空闲状态。假如请求中断的频率变成1000次每秒,那这个压力则会变成10倍,以此类推。

无滴答计时

越来越多的PC操作系统使用无滴答计时。在虚拟机中,这种计时形式比较容易被支持,并有几个好处。但仍存在一些挑战。

从积极的一面来说,当虚拟机操作系统不再需要以计时为目的来统计计时中断时,它就没有必要保持对中断积压的跟踪以及赶上实际时间。迟些的中断可以简单地堆叠在一起,而不用担心丢滴答造成的时钟偏移。这样能够节约花在处理迟到中断上的CPU时间。此外,虚拟机的时钟也更加准确,因为它不会在未运行或运行缓慢时落后实际时间。

然而,为了实现这些优势,虚拟机本身必须意识到虚拟机操作系统用的是无滴答计时。相反,虚拟机必须默认设置成滴答计数方式,因为如果虚拟机操作系统实际上用滴答计数的,那么丢任何滴答都会造成时间错误。VMWare采用多种方式来检测虚拟机操作系统是否使用无滴答计时。首先,如果虚拟机操作系统没有任何编程的虚拟计时器装置来产生周期性中断,那么可以安全地认为它没用采用滴答计数方式。然而,有些操作系统在使用无滴答计时方式时,同时也编程了数个虚拟计时器装置来定期产生中断,这种情况下,通常可以根据操作系统类型来判断其采用的计时方式。另外,在虚拟机中运行的软件可以通过hypercall通知虚拟机宿主它采用了无滴答计时。

对两种计时方式来说都存在的一个额外的挑战是:虚拟机偶尔会运行一些对时间高度敏感的程序,例如测量一定时间段内一个特定的循环迭代的数量,这种程序更适合在采用滴答计数的操作系统里运行,因为在虚拟机慢下来或停止运行时,计时也跟着减缓或暂停。

初始化和校准“挂钟时间”

虚拟机和物理机同样需要面对的一个问题是:怎样在启动时获取准确的挂钟时间(即当前准确时间)?VMware采用和物理机同样的机制,虚拟了一个有后备电池的CMOS,虚拟了网卡来获取网络时间。还有一个额外的机制:VMware Tools在启动时重设虚拟机的时间,并调整至宿主机的时间。

从长期来讲,一台物理机系统的计时硬件的走时是会有误差的,这个漂移的量有大有小,与系统所处的环境温度也有关系,而虚拟机虚拟出来的计时硬件也有这个现象。因此,必须要采用某种校正方式来长期保证系统时间的准确,例如NTP或Windows Time Service。VMware还额外提供了VMware Tools工具来帮助虚拟机与宿主机之间的时间进行同步,不过它并不那么精确,并且在VMware Workstation 6.5 及更早版本或 ESX/ESXi 4.0及更早版本中,VMware Tools仅对虚拟机走时慢做出处理,而不会处理走时快的情况。

PC机的时钟硬件

因为历史的原因,现在的许多操作系统都同时支持多种计时设备,例如一个运行在已知速度下的设备被用来测量另一个设备的速度。有时候另一个精确校准过的设备被用来在滴答计时的基础上增加精度。理论上这些设备应该保持一致,尽管可能与真实时间有偏差。

所有的PC计时硬件的原理可以用以下这张图来描述:

常见的PC计时硬件包含以下几种:

PIT programmable interval timer
RTC CMOS real time clock
APIC local advanced programmable interrupt controller (APIC) timers
ACPI advanced configuration and power interface (ACPI) timer
TSC time stamp counter
HPET high precision event timer

那么对虚拟机来说,就必须要虚拟出这些计时硬件来保证虚拟机操作系统能够准确计时,可想而知这并不是一件容易的事情。

特定操作系统的计时方式

不同的操作系统的计时方式会怎样影响着他们在虚拟机中的计时行为呢?

Microsoft Windows

Microsoft Windows通常采用滴答计时的方式。计时设备每秒产生中断的数量取决于操作系统版本和所安装的HAL(硬件抽象层)的版本。有些单处理器的windows配置采用PIT作为主系统计时器,但多处理器HAL和一些ACPI单处理器HAL采用CMOS计数器。对用PIT的系统来说,中断频率一般是100Hz,不过Windows98是200Hz(微软真奇怪)。而用CMOS计时的基本中断频率一般是64Hz。

而在某些应用场景下,微软的操作系统允许把这个中断频率提升到1024Hz,例如多媒体程序运行时,或者Java运行时。

Linux

在Linux的历史上,计时有了长足的进步。最近,kernel的开发导向是更好地支持虚拟机。然而,在这个过程中,有一些kernel版本在运行在虚拟机中时会暴露出特定的bug。有些内核的计时中断过高,以至于计时效率的低下以及在虚拟机空闲时仍要消耗过多的宿主机负载。一般来说,支持VMware的最新的kernel拥有最好的计时效能。例如CentOS 5.6和RHEL 5.9。

在内核版本2.4和早期的2.6版本中,采用滴答计时的方式,而在2.6.18(32bit)和2.6.21(64bit)中,在计时子系统中加入了一个叫做clocksource的抽象层。这样内核在启动时可以在多个clocksource中做出选择,几乎所有提供的clocksource都是无滴答计时的。

Linux下的用户应用同样可以请求 更高的计时中断,当linux作为宿主机时,VMware自己也会用到这个功能,来应对同时运行的几台虚拟机请求更高的虚拟计时中断(超出物理机固定中断频率)的请求。

同时,大多数Linux都会在启动时从CMOS中读取时间(Time Of Day),并在关机时回写当前时间到CMOS里。有时候,Linux内核定期重写当前系统时间至CMOS中(每11分钟一次)。或者手工调用/sbin/hwclock程序来对CMOS时间进行读写。

虚拟机操作系统时间不准的案例

在日常使用中,我们经常会遇到因虚拟机走时不准带来的问题,有些甚至会产生较大的负面影响,而看过以上文字阐述后,我们应该对虚拟机走时不准的成因有了明确的了解,那么接下来就来了解一下具体的案例吧。

场景:

宿主机 VMware ESX
虚拟机 Windows Server2008 64-bit
应用 NetScout Performance Manager

现象:

在NetScout PM的统计图表上,出现了一个Gap。

过程:

似乎一开始没人会想到这是系统时间的问题,于是对NetScout的日志进行了大量分析,发现疑点:

几乎所有的日志记录都跳过了11:15这个数据采集点,直接从11:00跳到了11:34,并且没有其他报错。这是非常不正常的,因为一般来说如果PM因故跳过了某个采集周期,日志中都会记录相关报错信息。

见下表的日志比对

通过对其中一个不断输出的日志memorylog分析,定位到精确的时间点是PM在11:13分这个时间点直接跳到了11:34分,而PM的采集周期是以15分钟为间隔的,即分别会在11:00、11:15、11:30采集数据, 而时间戳从11:13跳到11:34意味着11:15分的数据采集被跳过了,这也与工作台中显示11:00~11:15的数据缺失现象相吻合。

此时初步怀疑:PM服务器的时间被调整。但与客户确认在该时段没有人登陆过PM服务器进行调整时间的操作。因此需要进一步分析操作系统的日志。

在NetScout日志分析定位到时间调整的问题后,进一步调取PM服务器所安装的Windows系统日志进行查看,试图找出时间调整的痕迹:

结果发现在4月25日的11:13:37秒时果然发生了时间更改:

(注:日志时间戳是更改后的时间,而日志内容里是GMT时间,需加上8小时时差)从11:13:37改为11:33:58

为了进一步确认该事件调整是人工操作还是系统与NTP同步引起,我们进一步查看了NTP同步状态:

发现PM果然在4月25日的11:13与NTP 10.255.0.10进行了同步。

而下一次同步显示在5月2日,也就是同步间隔7天,意味着PM的系统时钟在7天内走慢了20分钟。

原因分析:

按照前文所述,Windows操作系统采用滴答计时的方式,这样的话,在一个多台虚拟机同时运行并且负载较大的环境下,因为竞争不到足够的计时中断,系统的时间会越走越慢。这种情况下,我们一般需要启用NTP或者VMware Tools来校准时间。

然而,这台Windows服务器已经启用了W32 Time服务,并与外部NTP服务器进行了同步,为什么还会有如此大的时间跳跃?这里,不得不提到Windows的两个坑爹的设定:

第一:Windows默认7天才与NTP同步一次。

为何Windows 2008会7天才与NTP同步一次时间?假如能够实现更频繁地同步时间,那么应该能够大大减小发生时间跳跃式调整的可能性。

关于这个问题,微软有一篇官方文章作出了解释:

http://technet.microsoft.com/zh-cn/library/cc731790(v=ws.10).aspx

当运行 Windows Server 2008 的计算机是工作组的一部分时 

在工作组中,时间同步频率的默认设置为“每周一次”,且此默认设置将 time.windows.com 站点作为受信任的时间同步源。在进行手动设置前将保持此设置。也可以选择一台或多台计算机作为本地可靠的时间源,并在这些计算机上配置 Windows 时间服务,使其使用已知的正确时间源(特殊硬件或可从 Internet 上获得的时间源)。可以手动将所有其他工作组中的计算机配置为与这些本地时间源同步时间。

要对Windows 2008的NTP同步频率进行调整,可按照以下步骤进行:

1. 打开注册表编辑器,依次展开

“HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\W32Time\TimeProviders\NtpClient”

2. 接着双击“SpecialPollInterval”,把其中的604800(十进制)改成“xxx”(十进制)。修改的这个数字是校对时间间隔的秒数。

3. 增加一个DWORD值,名称为“SpecialInterval”,值为1

4. 重启Windows Time服务。

第二:Windows的时间调整是直接跳跃式的,不管跨度多大。

用惯Unix的管理员们仍然会表示不理解,为何Windows的W32 Time服务允许一次调整20分钟的时间那么多。

因为在Unix的NTP实现中,默认是不允许有大幅度的时间调整的,因为这会必然地影响到系统上运行的关键应用,例如数据库。

在Unix的NTP实现中,假如NTP服务发现系统时间距离标准时间相差过大,它会尝试一点一点地调整时间,每次都不超过一个上限,例如这个环境里差20分钟的话,它可能会花数小时甚至数天来逐步调整到位。

其实Windows也可以通过修改注册表来增加这个限制,只是默认设置下没有,并且这个很少被人注意到(Windows管理员所关注的东西和Unix管理员显然是有明显差别的,例如杀病毒,lol)

总之,任何新技术的发展都会面临这样一个问题:大家都在大步前进,你想跟上,却因为速度太快而磕磕绊绊或者丢了东西。我想说的是,面对新技术的发展,急于跟上说明我们还抱有基本的上进心,但是却不要忘记做好充分的准备来拥抱变化才是脚踏实地稳步前进的基础。任何时候,准备不足的前进总是会带来代价,只是有些代价是可以承受的,但你无法保证你能够一直保持幸运……。

Soni