前言
相信点开这篇文章的读者,一定或多或少接触过“高可靠”“高可用”这些字眼,但是往往或语焉不详,或罗列术语(MTBF、MTTR ...),那么我们到底应该如何定量描述系统的可靠性和可用性指标呢,这些看着很上流的术语到底意味着什么呢?也许,看完这篇文章,您从此也可以和小伙伴们愉快地拽术语了!
故障定义
硬件故障(Hardware failure)
工业界通常使用“浴盆曲线”来描述硬件故障,具体如下图所示。具体来说,硬件的生命周期一般被划分为三个时期(http://en.wikipedia.org/wiki/Bathtub_curve):
1) The first part is a decreasingfailure rate, known as early failures
2) The second part is a constantfailure rate, known as random failures
3) The third part is an increasingfailure rate, known as wear-out failures
图1 浴盆曲线(Bathtubcurve)
软件故障(Software failure)
软件故障可以通过每千行代码的缺陷数(Defects/KLOC)进行测量,称为缺陷密度(Defect Density):
DefectDensity = Number of Defects / KLOC
影响缺陷密度的因素主要有如下几点:
1) 软件过程(代码评审、单元测试等)
2) 软件复杂度
3) 软件规模
4) 开发团队经验
5) 可复用代码比例(久经考验的代码)
6) 产品交付前的测试
衡量指标
平均故障间隔时间(MTBF)
英文全称:Mean Time Between Failure,顾名思义,是指相邻两次故障之间的平均工作时间,是衡量一个产品的可靠性指标。
故障率(Failure Rate)
以下文字摘自wiki,避免翻译失真(http://en.wikipedia.org/wiki/Failure_rate):
Failure rate is the frequency with which an engineered systemor component fails, expressed, for example, in failures per hour. It is often denoted by the Greek letter λ (lambda) and is importantin reliability engineering.
The failure rate of a system usually depends on time, withthe rate varying over the life cycle of the system. Forexample, an automobile's failure rate in its fifth year of service may be manytimes greater than its failure rate during its first year of service. One doesnot expect to replace an exhaust pipe, overhaul the brakes, or have majortransmission problems in a new vehicle.
In practice, the mean time between failures (MTBF, 1/λ) isoften reported instead of the failure rate. This is valid and useful if thefailure rate may be assumed constant – often used forcomplex units / systems, electronics – and is a general agreement in somereliability standards (Military and Aerospace). It does in this case onlyrelate to the flat region of the bathtub curve, also called the "usefullife period".Because of this, it is incorrect toextrapolate MTBF to give an estimate of the service life time of a component,which will typically be much less than suggested by the MTBF due to the muchhigher failure rates in the "end-of-life wearout" part of the"bathtub curve".
为便于理解,举个例子:比如正在运行中的100只硬盘,1年之内出了2次故障,则故障率为0.02次/年。
上文提到的关于MTBF和Failure Rate关系值得细细体会,在现实生活中,硬件厂商也的确更热衷于在产品上标注MTBF(个人猜测是因为MTBF往往高达十万小时甚至百万小时,容易吸引眼球)。Failure Rate伴随着产品生命周期会产生变化,因此,只有在前述“浴盆曲线”的平坦底部(通俗点说就是产品的“青壮年时期”)才存在如下关系:
MTBF = 1/λ
平均修复时间(MTTR)
英文全称:Mean Time To Repair,顾名思义,是描述产品由故障状态转为工作状态时修理时间的平均值。在工程学,MTTR是衡量产品维修性的值,在维护合约里很常见,并以之作为服务收费的准则。
图2 硬件MTTR估算
图3 软件MTTR估算
可用性(Availability)
GB/T3187-97对可用性的定义:在要求的外部资源得到保证的前提下,产品在规定的条件下和规定的时刻或时间区间内处于可执行规定功能状态的能力。它是产品可靠性、维修性和维修保障性的综合反映。
Availability = MTBF / (MTBF + MTTR)
关于Availability这个计算公式,很容易理解,这里不多做解释。通常大家习惯用N个9来表征系统可用性,比如99.9%(3-nines availability),99.999%(5-nines availability)。
宕机时间(Downtime)
顾名思义,指机器出现故障的停机时间。这里之所以会提Downtime,是因为使用每年的宕机时间来衡量系统可用性,更符合直觉,更容易理解。
图4 Availability与Downtime对应关系
延伸思考
MTBF不靠谱?
一般来说,服务器的主要部件MTBF,厂商标称值都在百万小时以上。比如:主板、CPU、硬盘为100wh,内存为400wh(4根内存约为100wh),从而可以推算出服务器整体MTBF约25wh(约30年),年故障约3%,也就是说,100台服务器每年总要坏那么几台。
上面的理论计算看着貌似也没啥问题,感觉还挺靠谱。但如果换个角度想想,总觉得哪里不太对劲:MTBF约30年,难道说可以期望它服役30年?先看看希捷的工程师如何解释:
(http://knowledge.seagate.com/articles/en_US/FAQ/174791en?language=en_US):
It iscommon to see MTBF ratings between 300,000 to 1,200,000 hours for hard diskdrive mechanisms, which might lead one to conclude that the specificationpromises between 30 and 120 years of continuous operation. This is not thecase! The specification is based on a large (statistically significant) numberof drives running continuously at a test site, with data extrapolated accordingto various known statistical models to yield the results.
Based on the observed error rate over a few weeks or months,the MTBF is estimated and not representative of how long your individual drive,or any individual product, is likely to last. Nor isthe MTBF a warranty - it is representative of the relative reliability of afamily of products. A higher MTBF merely suggests agenerally more reliable and robust family of mechanisms (depending uponthe consistency of the statistical models used). Historically, the field MTBF,which includes all returns regardless of cause, is typically 50-60% ofprojected MTBF.
看到这里,再联系前文对于Failure Rate的阐述,我知道各位读者有没有摸清其中的门道。其实说白了很简单,这些厂商真正测算的是产品在“青壮年”健康时期的Failure Rate,然后基于与MTBF的倒数关系,得出了动辄百万小时的MTBF。而现实世界中,这些产品的Failure Rate在“中晚年”时期会快速上升,因此,这些MTBF根本无法反映产品的真实寿命。文中也提到,希捷也意识到MTBF存在弊端,因此改用AFR(Annualized Failure Rate),俗称“年度不良率”。
其实,早在2007年,Google和CMU同时在FAST07发表论文,详细讨论了硬盘故障的问题:
- CMU《Diskfailures in the real world: What does an MTTF of 1,000,000 hours mean to you?》
- Google《FailureTrends in a Large Disk Drive Population》
Google采集了公司超过10w块消费级HDD硬盘数据(SATA和PATA,5400转和7200转,7家不同厂商,9种不同型号,容量从80G到400G不等),最终得出如下数据:
Googlefound that disks had an annualized failure rate (AFR) of 3% for the first threemonths, dropping to 2% for the first year. In the second year the AFR climbedto 8% and stayed in the 6% to 9% range for years 3-5.
如果各位读者对于MTBF仍然有疑问,再推荐一份入门材料给大家,《Meantime between failure: Explanation and standards》,其中对于人类的MTBF阐述绝对会让你恍然大悟。
系统可用性
前文的描述其实都是针对单一模块而言,而现实世界中的系统往往是由若干模块组合而成。其实,各个模块之间的关系无非“串联”和“并联”两种(与串并联电路类似),那么整体可用性计算方式就显而易见了。
串联模块
图5 串联模块
整体可用性计算公式如下:
A = Ax* Ay
并联模块
图6 并联模块
整体可用性计算公式如下:
A = 1 – (1 –Ax)2
示例计算
图7 系统模块构成
图8 软硬件抽象分离
图9 模块可用性计算
图10 系统可用性计算
系统设计启发
通过上一小节的示例系统可用性计算,相信各位对于“并联”的威力已经有了非常直观的感受。其实这就是我们做架构设计常说的“容灾”“冗余”,其实在硬件领域也很常见(如双电源、RAID、双网卡)。与此同时,对于“串联”的局限也应该有所体会,只要存在“短板”,整体可用性是上不去的。引申到后台软件系统设计,我个人有以下看法,欢迎大家拍砖:
1) “7*24不停机”不切实际
在不少开发人员的心目中,往往认为硬件是很可靠的,但是经过前文的洗礼,应该认识到,其实硬件真的没有我们想象得那么可靠。如果你仅仅围绕两三台服务器打转,可能一两年都未必碰到一次硬件故障,但是如果你维护的是上千台服务器,那么恭喜你,基本每周都会有硬件故障来拜访你。
单机软件的可靠性受限于硬件,因此,言必谈“7*24不停机”本身就是个无稽之谈。随之而来的就是一些根深蒂固的错误观念,比如内存碎片。新人一进公司往往就会被教导:后台开发应该尽量避免使用malloc/free等动态内存分配,因为容易导致内存碎片,随之而来的就是避免使用STL容器等。如果您有幸已经用上了64位系统,那么如果您还能遇到内存碎片,我只能说自求多福了;如果您还在使用32位系统,也不用太担心,今天的glibc也早就不是当年的glibc了,人家也在不断优化内存分配算法,何况kernel都在使用动态内存分配。退一万步讲,即使真的遇到了,那么就到了我想谈的下一个话题
2) “可重启”才是好设计
这里所说的“可重启”和很多人心目中的理解可能不太一样,我司相当多的开发人员热衷于共享内存的使用:
- 进程间通讯
- 重启后数据不丢失
比如应用升级或者程序CORE掉,往往借助所谓“秒起”来完成服务恢复,有些更极端的甚至拦截”段错误”一类信号。其实,无论如何秒起,总归会有部分用户受影响,另外,如果是由于程序错误导致的意外重启,谁能保证共享内存的数据仍然处于正确状态呢?
此外,如果出现机房搬迁、空调故障、供电故障等意外,所谓的共享内存+秒起也只能干瞪眼。
因此,正如上文所说的,通过容灾备份+路由切换实现优雅无缝重启才是好的设计。一般来说,“可重启”进程具备如下特征:
- 无论exit还是kill,都可以正确重启
- 不使用生命期大于进程的IPC(共享内存、跨进程的mutex等)
- 不使用难以重建的IPC(父子进程共享FD通信等)
那么又该如何优雅重启呢?一般分为两种场景:
- 有计划的重启(如版本升级)
首先将节点从服务列表中摘除,等待节点流量跌零,发起重启过程(更新文件等),确认服务启动正常后,重新将节点添加至服务列表,逐步引流进行正确性验证(若发现异常,及时摘除)。服务节点依次分批处理,真正实现无缝重启
- 意外故障发生
服务访问方支持Failover,自动切换备用节点,或者通过Name Service一类设施自动摘除故障节点,人工介入恢复
当然,前面一些看法并非“放之四海而皆准”,在实际设计系统的时候,还是应该因地制宜,选择最适合当时环境的方案。