您的位置:首页 > 其它

On Designing and Deploying Internet-Scale Services(译)-下

2015-08-24 22:13 197 查看


发布周期和测试

在生产环境下的测试是必需的,所有的大规模服务都应该把它作为QA方案的一部分。对于大多数服务来说,都至少会有一个尽可能接近生产的测试环境,同时所有优秀的工程团队都会用实际的生产负载来驱动测试系统。但我们的经验表明,无论测试环境有多好,总是不可能会与生产环境完全一致。与生产相比,总是或多或少会有些差别。随着测试环境与生产系统的接近,成本也会逐步与生产系统相当。

 

我们推荐在新版本服务经过标准单元测试、功能测试和类生产环境测试后,就到一个受限的生产环境下进行最后的测试。当然,我们都不想进入生产环境的软件无法工作,或者是给数据一致性带来风险,因此这一切都务必要小心翼翼。严格遵守以下规则:

1.      生产系统要有足够的冗余,当新服务发生灾难性故障时,可以快速恢复状态。

2.      绝对不能破坏数据或状态一致性(必须先要经过严格的功能测试)

3.      错误必须能够被检测到,同时工程团队(而不是运维)必须持续监控受测代码的系统状态

4.      保证所有变更都能被快速回滚,同时在上线之前回滚步骤也必须经过测试

 

这看起来很危险。但是我们发现,使用这种技术实际上能够改善新版本发布时的用户体验。部署时不求快,而是先把一个数据中心的某个生产系统升级,测试几天。然后再把所有数据中心的该系统升级。然后再把某个数据中心的所有系统升级。最后,如果质量和性能符合预期,再升级其它数据中心。这样就可以在服务处于危险之前发现问题,同时也可以切实地在版本过渡阶段为客户提供更好的用户体验。一刀切(Big-bang)的部署方式是非常危险的。

 

我们青睐的另一种可能违反直觉的方式是,在每天正午而不是半夜部署。在晚上部署,出错的风险更高,而且在半夜部署时如果有异常情况突然发生,那么能处理这些问题的工程师肯定会少些。这样做的目标是为了最小化开发和运维人员与系统的总体交互次数,尤其在正常工作日之外的,降低成本的同时,质量也得到提高。

 

一些发布周期和测试方面的最佳实践:

l  经常进行发布。直觉上看,人们可能会认为发布越频繁会越困难,同时也越容易出错。但是,我们却发现发布越频繁大爆炸(big-bang)式的变更会越少。这样发布的质量倾向于更高,客户的体验也会更好。一次良好发布的酸性测试(acid
test),应该是用户体验可能发生变化,但是围绕着可用性和延迟的运维性问题数在整个发布周期内应该保持不变。我们比较喜欢以三个月为一个发布周期,但是也可以视具体情况作出调整。我们感觉,正常来说都应该是不多于3个月,而且有些服务已经是在以周为单位进行发布了。如果周期超过3个月,通常都是很危险的。

l   利用线上数据发现问题。大规模系统中的质量保证,是个数据挖掘和可视化问题,而不是测试问题。每个人都应该专注于如何从生产环境中的大量数据中获取到最有价值的信息。可以采用如下一些策略:

n  可衡量的发布标准。定义出关于所期望的用户体验的具体标准并持续监测它。如果可用性目标设定为99%,那么就对可用性进行测量看它是否达标。如果无法达标,要进行报警和诊断。

n  始终对实际数字进行收集。收集实际的度量值,而不是那些红红绿绿的图或其他形式的摘要报告。摘要和图表有用,但是对于问题诊断来说还是需要原始数据。

n  最小化“false positives(误报)”。在数据不正确时,人们很快就会放弃对它的关注。不过度报警很重要,否则运维人员很快就会习惯于忽略它们。这非常重要,以至于即使是附带地把某些真实问题隐藏掉也是可以接受的。

n  分析趋势。这个可以用来预测问题。例如,当系统中的数据流动速率异于往常时,通常预示着更大的问题。仔细挖掘现有的可用数据。

n  使系统健康程度保持高度可见。需要为整个组织提供一个随处可查并实时显示的系统健康状况报告。构建一个内部网站,使得大家可以随时查看当前系统状态。

n  持续监控。值得一提的是,人们必须要每天查看这些监控数据。每个人都应该这样做,但是也要为这项工作明确地指定某些负责人。

l  加大工程投入。良好的工程化可以最小化运维需求,同时可以将问题消除在萌芽状态。非常常见的一个现象是,组织通过不断地扩大运维团队来解决规模问题,而不是花时间设计实现一个可伸缩的、可靠的系统。那些起初没有考虑过大规模问题的服务,往往后面都会变得手忙脚乱。

l  支持版本回滚。版本回滚支持应是强制性的,同时在上线之前必须经过测试和证明。如果没有回滚支持,任何形式的生产级测试都将是非常危险的。回滚到前一版本就像降落伞上的“开伞索”,应保证它在任意部署中都是可用的。

l  保持向前和向后兼容性。{!Forwards
Compatibility,向前兼容。Forward有“将来”的含义,因此是指以前的版本支持现在版本生成的数据,现在的版本支持以后的版本数据。Backwards
Compatibility,向后兼容。Backward有“回头”的意思,所以是指现在的版本可以支持以前的版本数据}。这一点与前面一点非常相关。对文件格式、接口、日志/调试信息、仪表、监控和组件间的连接点进行的改变,都是潜在的风险。不要丢掉对旧文件格式的支持,否则未来将没有机会回滚到老版本。

l  单机部署支持。这既是测试的需求也是开发的需求。整个服务必须可以很容易地托管到单一系统中。对于某些单服务器无法实现的组件(比如,它依赖于一个外部的、不支持单机部署的服务),需要为它编写模拟器以支持单机部署。如果不支持这点,那么单元测试将很难进行,同时也没法完全展开。同时,如果运行整个系统很困难,开发人员也会倾向于在组件的级别上进行开发,而不是系统级。

l  针对负载进行压力测试。采用两倍(或更多)的负载来运行生产系统的某些子集,确保系统在高于预期负载情况下的行为仍然是可理解的,以及不会随着负载的上升而宕掉。

l  在新发布之前进行容量和性能测试。除了要在服务级上进行,还要对每个组件进行,因为负载特征会随着时间发生变化。需要尽早捕获系统内部的问题及退化现象。

l  增量地迭代地进行构建和部署。在开发的早期阶段,先把整个服务的骨架先搭建好。这个完整的服务可能几乎做不了什么,但是它可以让测试和开发人员更具有产品思维,可以一开始就站在用户的角度思考问题。在构建软件系统时这是一个非常好的实践,但对于服务来说更尤其重要。

l  采用真实数据进行测试。将生产环境中的用户请求和工作负载搬到测试环境中。挑选一些生产数据,并将它们放到测试环境中。多样化的真实用户群体在发现bug上总是更有创造力。显然,必须要进行隐私承诺,非常关键的是保证数据永远不会泄露回到生产系统中。

l  运行系统级验收测试。在本地运行一些可以加速迭代开发过程的完整性检查。为避免产生繁重的维护成本,它们都应当是系统级的。

l  在完整环境中进行测试开发。留出一定的硬件,以可以进行特定规模的测试。最重要的是,在这些环境中使用那些与生产系统相同的数据集合和挖掘技术,以最大化资源投入的价值。


硬件选型和标准化

采用SKU(Stock Keeping Unit,库存单元)标准化的常见理由是,批量采购可以节省大量的金钱。毋庸置疑这是正确的。但是硬件标准化的更大需要是,它可以支持更快的服务部署及规模增长。如果每个服务都是自己采购的基础设施,那么它们将需要:

1.      确定哪些硬件当前具有最好的性价比

2.      订购这些硬件

3.      一旦硬件被安装到数据中心,进行硬件认证及软件部署

这通常要花一个月,同时很容易就会花更多时间。

 

更好的方法是采用包含了硬件SKUs、自动化管理和配置设施的“services fabric”,让所有服务运行在它之上。如果一个测试集群需要添加更多机器,可以通过网页服务来提交请求,之后很快就直接可用了。如果一个小服务越来越成功,也可以从现有机器池里添置资源。

 

这种方法保证了如下两个关键原则:1)所有服务,甚至是小服务,都在使用自动化管理和配置设施;2)新服务可以非常快的进行部署和测试。

 

针对硬件选型的最佳实践如下:

l  只使用标准SKUs。如果生产系统中只有单个或少量SKU,就可以实现资源在服务间的按需流转。成本效益最好的模式是开发一种包含了自动化管理和配置、硬件以及一组标准共享服务集合的标准服务托管框架。标准化SKUs是实现该目标的核心要求。

l  整机柜采购。采购硬件应该以机柜或多个机柜为单位进行配置和测试。在大多数数据中心,机器组柜和堆垛成本是非常高的,因此要让系统制造商以机柜为单位进行交付。

l  硬件抽象。将服务编写地只是依赖于抽象的硬件描述。而不需要完全暴露硬件SKU,服务既不应该暴露SKU,也不应该依赖于它的内部细节。这样才可以在具有更高性价比的系统可用时,将现有设备替换掉。SKU应当只是一个包含了CPU和磁盘数,及最低内存要求的抽象描述。更细粒度上的SKU信息不应该被利用。

l  对网络和命名服务进行抽象。使用DNS和CNAMEs尽可能地将网络和命名进行抽象。始终坚持使用CNAME。硬件可能损坏、到期或挪作它用。在代码的任何地方都不要依赖于机器的名称。改变DNS中的CNAME要与需要改变配置文件甚至是代码相比,要容易得多。如果需要避免更新(Flush)DNS缓存,需要记得将TTL{!
Time-To-Live,简单的说它表示一条域名解析记录在DNS服务器上的缓存时间.当各地的DNS服务器接受到解析请求时,就会向域名指定的DNS服务器发出解析请求从而获得解析记录;在获得这个记录之后,记录会在DNS服务器中保存一段时间,这段时间内如果再接到这个域名的解析请求,DNS服务器将不再向DNS服务器发出请求,而是直接返回刚才获得的记录;而这个记录在DNS服务器上保留的时间,就是TTL值}设得足够低以保证变更可以尽可能快地被push。


运维和容量规划

要高效地运维服务,关键在于构建系统时消除各种需要运维交互的过程。目标在于让一个高可靠的,7*24小时可用的服务只需要5*8小时工作的运维团队维护即可。

 

但是,可能会发生不寻常的故障,而且系统或多个系统可能会无法恢复在线工作。要理解这种可能性的发生,并将受损系统的下线过程自动化。依赖于运维人员手动更新SQL表或者是使用特别的技术移动数据,都可能会招致灾难。处理故障的过程中也容易产生失误。运维团队需要预料遇到各种故障时的正确应对方式,并将这些过程提前进行编写和测试。一般来说,开发团队要将紧急恢复操作自动化

,并必须要对它们进行测试。很明显,无法将所有的故障都提前预料到,但是通常通过一小组恢复动作的集合就可以从类型广泛的故障中恢复过来。本质上来说,是需要构建和测试可以根据故障范围和危害以不同方式使用及组合的“恢复内核”。

 

恢复脚本需要在生产环境下测试。没有经过频繁测试的东西是无法工作的,因此不要实现团队没有勇气去使用的任何东西。如果在生产环境下测试的风险太高,那么说明脚本要么是没准备好,要么是在紧急情况下使用时也不会安全。这里的关键点是,灾难总是在发生,同时那些因为恢复步骤未按预期执行而导致由小灾难演变为大灾难的情况也是屡见不鲜。要预料到这些情况,并且要能在不造成更多的数据丢失和不服务时间的前提下,将服务恢复过程自动化。

 

l  增强开发团队责任感。在这方面,Amazon应该算是最激进的了,他们的格言是“you
built it, you manage it”。他们的主张要比我们现在所采用的方式稍微强些,但是这无疑是一个正确的方向。如果开发总是被在午夜吵醒,那么自动化就会是必然结果。但是如果是运维被吵醒,通常的反应是扩充运维团队。

l  只进行软删除。绝不要删除任何东西,只是将它们标记为已删除。当有新数据进来时,将请求记录下来。保存一个以两周(或更长时间)为单位滚动的变更历史记录,以便从软件或操作错误中恢复。比如有谁犯了错,忘记在delete语句中加上where子句(以前曾经发生过并且也难保将来不会再发生),数据的所有逻辑拷贝都会被删除。RAID和镜像都无法防止这种形式的错误。数据恢复能力可以让一个原本非常严重的问题变成一个微小的,不起眼的问题。对于那些已经进行了离线备份的系统来说,只需要额外记录那些上次备份之后进来的数据即可。但是,谨慎起见,多备份一些会更保险。

l  跟踪资源分配。理解容量规划中的额外负载带来的成本开销。每个服务都应该开发一些像并发在线用户、每秒请求数或者其他的一些相关指标。无论是何种指标,都需要在负载的此种测量方法和所需的资源之间有一个直接的已知关系。所估计的负载数应通过销售和市场团队的反馈得到,同时将会被运维团队用来进行容量规划。不同的服务具有不同的变化速度,同时有不同的订购周期要求。对于我们的服务来说,每90天会更新一下市场预测,每30天更新一次容量规划和订购需求。

l  一次只进行一个变更。碰到问题时,应该一次对环境只做一个变更。这看起来显而易见,但是我们也多次看到过因多个变更导致的因果关系无法确定的情况发生。

l  使所有东西可配置。任何可能在产品系统中发生改变的东西都应该是在生产环境下可配置和调整的,而不需要改变代码。即使某个值看起来没有很好的在生产环境中发生变更的理由,如果很容易的话也应让它可配置。但是不要在生产环境中随意更改它们,同时应该对系统连同那些将在生产系统中使用的配置一块进行严格的测试。但是当生产出现问题时,与编码、编译、测试、部署相比,简单地修改下配置总是要更简单、安全、快速。


审计、监控和报警

运维人员无法在部署中再对服务进行调整(instrument)。在开发过程中要付出足够的努力,来确保系统中的所有组件都可以产生相应的性能数据、健康数据以及吞吐率等数据。

 

在任何有配置变更发生的时候,都要在审计日志中记录下改了什么,谁改的,什么时间改的。在生产环境出现异常时,第一个要回答的问题就是最近到底进行过哪些变更。如果没有审计跟踪,那么答案通常是“没有改过什么”,而通常最可能的情况就是正是因为某个变更导致了问题。

 

报警是一门艺术。有一种倾向就是对所有事件进行报警,开发者期望可以从中发现有趣的事情,这就导致很多服务的第一版通常都会产生大量根本没人会看的无用报警信息。要提高效率,每个报警都应该对应着一个问题。否则,运维团队将会习惯于将它们忽略。我们不知道除了交互式地对报警条件进行调整外,还有何灵丹妙药可以让每个报警都正确,以保证所有关键事件都会被报警,在不需要采取任何措施的情况下就不报警。要得到正确的报警级别,有两个指标可能会有帮助,并值得进行追踪:1)报警和实际故障比(理想情况它的值应接近1);2)没有产生相应报警的系统故障数(理想情况它的值应接近0)。

l  Instrument everything。对通过系统的每个客户交互和事务进行监测,并报告异常。这是一个“runners”(可以合成工作负载来模拟生产环境中的用户交互)可以施展的地方,但是仅有它们还不够。如果只使用runners,我们曾看到一个严重问题甚至需要几天时间才被发现,因为标准工作负载一直被处理得很好,然后还要再花几天时间才能查到原因。

l  数据是最有价值的资产。如果对系统正常行为没有很好的理解,那么在它发生异常时也没法很好地进行处理。需要对关于系统行为的大量数据进行收集以确定系统状态是否正常。很多服务都经历过灾难性的故障,但是只有在电话铃响起时,人们才意识到故障的发生。

l  具有服务的客户视角。进行E2E测试。仅有Runners虽不足够,但是它们可以用来确保服务在完整运行。确保复杂和重要的路径能够被Runners测试到。避免误报,如果Runners的失败可以被忽略,那么就修改测试使得它是不可忽略的。再次强调一下,一旦人们习惯了忽略数据,以后即使再真的发生也无法再得到及时的关注。

l  对生产环境测试进行监测。要想安全地在生产环境中进行测试,需进行完整的测试和监控。如果组件发生了故障,需要能够快速地监测到。

l  延迟是最棘手的问题。比如像IO缓慢,虽未成故障但是处理变慢这样的问题。这些都很难发现,需仔细进行监测才能发现。

l  要有足够的生产数据。为了找到问题,数据必须是可用的。及早构建细粒度的监控,否则后面进行改造的成本会很高。我们所依赖的重要数据包括:

n  为所用操作采用性能计数器。至少要将操作延迟及每秒的操作数记录下来。这些数据的起伏通常是一个危险信号。

n  对所有数据进行审计跟踪。每当某人做了某事,尤其是重要之事,都要进行记录。这样做主要有两个目的:首先,日志可以用来进行挖掘以找出用户经常进行哪些操作(在我们的例子中,就是他们经常进行何种查询);其次,可以用它来在发现问题时帮助进行debug。

 与此相关的一个观点:如果所有人都使用同一个账号来管理系统,这样做不会带来太多好处。一个非常糟糕的想法,但是并不罕见。

n  跟踪所有容错机制。容错机制会将故障隐藏。每当重试发生,或将数据从一个地方拷贝到另一个地方,或机器重启以及服务重启时,都进行跟踪。在容错机制隐藏了小故障时,要能了解到并对它进行追踪,防止小故障演变成大故障。我们曾经有一个2000台机器的服务在几天内慢慢地下降到只有400台可用,但是一开始却没人注意到。

n  跟踪针对重要实体的所有操作。为发生在每个重要实体上的事件记录一个“审计日志”,无论实体是一个文档还是多个文档组成的集合。在运行数据分析时,通常能够通过数据发现异常。要了解数据的来源及其所经过的处理过程。到了项目后期再添加这些功能会变得特别困难。

n  断言。自由地在整个产品中使用断言。收集产生的日志以及程序奔溃后的core文件,并对它们进行研究。对于那些在同一个进程边界内运行了多个服务,以及无法使用断言的地方,要写下追踪记录。

n  保留历史数据。历史上的性能和日志数据对于趋势分析和问题诊断来说都是非常必要的。

l  日志可配置。支持可配置的日志,日志可以根据调试需求选择性地打开、关闭。在故障期间去部署具有额外监控的新构建版本是非常危险的。

l  向监控系统暴露健康信息。考虑多种从外部对系统健康状况进行监控的方法,并使之易于在生产环境下进行监控。

l  保证所有被报告的错误都有与之相应的处理动作。问题会发生。事情会出错。如果代码中的一个不可恢复的错误被检测到并记入日志,或者是报告为错误,错误信息应该能揭示错误产生的可能原因及建议的处理方法。不具备可操作性的错误报告是无用的,并且时间长了它们会被忽略,而真正的故障将会被错过。

l  实现生产问题的快速诊断

n  为诊断提供足够信息。当问题被标记出来时,提供足以让人进行诊断的信息。否则,进入门槛将会过高,同时标记也会被忽略。比如不要仅仅是说“有10个查询没有返回结果”,还需再加上“下面是它们的列表及问题出现次数”。

n  证据链。确保有一个可以让开发人员进行问题诊断的从头到尾的完整路径。这通常是通过日志实现的。

n  在生产环境中进行debug。我们更喜欢这样一种模式,在该模式中,系统几乎从不会被包括运维在内的任何人直接触碰,而debug是通过让系统产生快照,将内存内容dump出来,然后转移出生产环境再进行的。当在生产环境中进行debug是唯一选择时,开发者则是不二人选。确保他们对于可以在生产环境中做哪些事情是经过严格培训的。我们的经验表明,系统在生产环境中被触碰地越少,客户满意度越高。因此我们建议,一定要竭尽全力避免对生产环境中的系统进行改动。

n  记录所有的重要动作。每当系统执行重要动作时,尤其是在收到网络请求或修改数据时,要记录下发生的事情。包括用户何时发送了命令以及系统内部做了什么。有了这些记录,对问题调查大有裨益。更重要的是,还可以开发出挖掘工具来找到有用的聚合结果,比如当前的用户正在执行哪些种类的查询(比如,哪些关键字,多少关键字等等)。


优雅降级和准入控制

有些时候比如受到DOS攻击或使用模式发生某些改变时,会导致负载突然爆发。服务需要能够进行优雅降级及准入控制。比如在9.11期间,大多数新闻服务都崩溃了,无法为任何用户提供可用的服务。与此相比,就算是仅能够提供所有文章的一部分子集也是一个更好的选择。两个最佳实践,“big
red switch”和准入控制,需要针对每个服务进行量身定制。但是这两个都是非常强大和必要的。

l  支持“big red switch”。“big
red switch”的想法最初源自于Windows Live Search团队,它非常强大。我们对它进行了一些扩展,使得它可以应用在那些与搜索具有显著不同的事务型服务中。这个想法非常强大,实际上可以应用到任何地方。大体来说,“big red switch”是一种当服务不再满足它的SLA或迫在眉睫时,可采取的经过设计和测试的动作。将优雅降级比喻为“big
red switch”,稍微有些不太恰当,但核心的意思是指那种可以在紧急情况下摒弃那些非关键负载的能力。

“big red switch”概念是以丢弃或延迟非关键负载为代价,保证关键处理过程能继续进行的关键。根据设计,这种情况应永不发生,但是当真的发生时这也不失为一个好方法。等到服务已处于危险的情况下,再考虑这些就太迟了。如果有些负载可以被暂时放入队列后面再处理,那这也可以作为“big
red switch”的候选。另外如果在关闭高级查询的情况下,事务可以继续执行,那这也可以作为一个候选。关键在于确定碰到问题时系统所需的最小集合,然后实现关闭那些不必要的服务的开关,并进行测试。需要注意的是,正确的“big red switch”应是可逆的。同时应对开关的重置进行测试,确保所有服务可以回到完整服务状态,包括所有的批处理任务及先前被暂停的非关键工作。

l  准入控制。第二个重要概念是准入控制。如果当前的负载系统已经无法处理了,那么再往系统中增加负载也只是会让更多的用户产生糟糕的体验。如何实现这一点与系统本身有关,某些系统比其他系统更容易完成。以电子邮件处理服务为例,如果系统已经超负荷,并开始排队,此时最好不要再接收邮件而是让它们在来源队列中等候。这样可以产生效果并能实际减少总体服务延迟的关键原因是,如果队列形成处理时间会变更慢。如果我们不允许队列的建立,那么吞吐量将会更高。另一种技术是:提供服务时高端用户优先于非高端用户,注册用户优先于访客,或者是访客优于用户如果是以“试用和购买”为商业模型的话。

l  准入计量。另一个非常重要概念是上面所确定的准入控制点的修改。如果系统发生故障并宕机,为确保一切正常恢复时必须能够缓缓进行。比如先让一个用户进入,然后每秒允许10个用户进入,如此慢慢加大。对于每个服务来说,拥有一个细粒度的旋钮可以在重新上线或从灾难性失败中恢复时缓慢增加使用量,是至关重要的。在任何服务的第一个版本中很少会包含这种能力。对于一个有客户的服务来说,一定有方法来通知它的客户暂时无法提供服务以及何时会恢复。这就允许客户端在可以接受的情况下继续修改本地数据,同时也可以让客户端暂时退下避免干扰服务,让服务可以尽快恢复上线。这样也同时为服务owner提供了一个直接与用户沟通的机会,并可借此调整他们的期望。另外的一个可以避免所有客户端同时涌向服务端的技巧是:故意制造抖动和对每个实体进行自动备份。


客户和媒体沟通计划

系统发生故障时,就需要就由此引发的延迟和其他问题与客户进行沟通。沟通应以可选的方式通过多种媒介进行:RSS,网站,即时消息,电子邮件等。对于那些具有客户端的服务来说,让服务具备通过客户端直接与用户联系的能力是非常有用的。可以在特定的时间点或时间段,要求客户端下线。如果支持的话,也可以让客户端运行在连接断开或缓存模式下。可以通过客户端将系统状态告知用户,并说明预计在何时会完全可用。

 

即使没有客户端,用户也可以通过其他方式与系统交互,比如通过网页将系统状态公布给用户。如果用户了解什么正在发生,并且对于服务何时恢复也有一个合理的预期,就会大大提高他们的满意度。对于服务提供者来说,有一个想要隐藏系统问题的自然倾向,但是随着时间的推移,我们越来越确信,将服务可用性的信息提供给客户几乎总是可以提高他们的满意度。即使是对于免费系统来说,如果人们可以清楚地知道什么正在发生及何时可以恢复正常,他们就会对服务更有信心而不会轻易放弃使用。

 

某些特定类型的事件将会引发媒体报导。如果事先考虑到这些场景做好应对,那么服务将会带给人们更好的印象。像大量数据丢失或损坏,安全入侵,隐私侵犯以及长时间的服务停机等问题都可能引起媒体的关注。事先准备好沟通计划。知道需要与谁、何时、怎么通电话。沟通方案的框架应该提前准备好草案。针对每种类型的灾难,都应该提前准备好沟通计划,包括与谁、何时、如何沟通。


客户自配置与自助

客户自配置可以大大降低成本,同时还能提升客户满意度。如果客户可以简单地通过打开网页,输入所需数据,然后就可以开始使用服务,这会比他需要打电话然后在呼叫处理队列里浪费大量时间,满意度要高地多。我们一直觉得主要的移动运营商因为一直未为那些不想致电客户服务的人们提供自助服务,错过了一个既节省成本又可以提高客户满意度的机会。


总结

对于大规模互联网服务来说,降低运维成本和提高服务可靠性始于编写运维友好的服务。在本文中,我们定义了何谓运维友好,并总结了来自于从事大规模服务的工程师在服务设计、部署、开发和运维方面的最佳实践。


发布周期和测试

在生产环境下的测试是必需的,所有的大规模服务都应该把它作为QA方案的一部分。对于大多数服务来说,都至少会有一个尽可能接近生产的测试环境,同时所有优秀的工程团队都会用实际的生产负载来驱动测试系统。但我们的经验表明,无论测试环境有多好,总是不可能会与生产环境完全一致。与生产相比,总是或多或少会有些差别。随着测试环境与生产系统的接近,成本也会逐步与生产系统相当。

 

我们推荐在新版本服务经过标准单元测试、功能测试和类生产环境测试后,就到一个受限的生产环境下进行最后的测试。当然,我们都不想进入生产环境的软件无法工作,或者是给数据一致性带来风险,因此这一切都务必要小心翼翼。严格遵守以下规则:

1.      生产系统要有足够的冗余,当新服务发生灾难性故障时,可以快速恢复状态。

2.      绝对不能破坏数据或状态一致性(必须先要经过严格的功能测试)

3.      错误必须能够被检测到,同时工程团队(而不是运维)必须持续监控受测代码的系统状态

4.      保证所有变更都能被快速回滚,同时在上线之前回滚步骤也必须经过测试

 

这看起来很危险。但是我们发现,使用这种技术实际上能够改善新版本发布时的用户体验。部署时不求快,而是先把一个数据中心的某个生产系统升级,测试几天。然后再把所有数据中心的该系统升级。然后再把某个数据中心的所有系统升级。最后,如果质量和性能符合预期,再升级其它数据中心。这样就可以在服务处于危险之前发现问题,同时也可以切实地在版本过渡阶段为客户提供更好的用户体验。一刀切(Big-bang)的部署方式是非常危险的。

 

我们青睐的另一种可能违反直觉的方式是,在每天正午而不是半夜部署。在晚上部署,出错的风险更高,而且在半夜部署时如果有异常情况突然发生,那么能处理这些问题的工程师肯定会少些。这样做的目标是为了最小化开发和运维人员与系统的总体交互次数,尤其在正常工作日之外的,降低成本的同时,质量也得到提高。

 

一些发布周期和测试方面的最佳实践:

l  经常进行发布。直觉上看,人们可能会认为发布越频繁会越困难,同时也越容易出错。但是,我们却发现发布越频繁大爆炸(big-bang)式的变更会越少。这样发布的质量倾向于更高,客户的体验也会更好。一次良好发布的酸性测试(acid
test),应该是用户体验可能发生变化,但是围绕着可用性和延迟的运维性问题数在整个发布周期内应该保持不变。我们比较喜欢以三个月为一个发布周期,但是也可以视具体情况作出调整。我们感觉,正常来说都应该是不多于3个月,而且有些服务已经是在以周为单位进行发布了。如果周期超过3个月,通常都是很危险的。

l   利用线上数据发现问题。大规模系统中的质量保证,是个数据挖掘和可视化问题,而不是测试问题。每个人都应该专注于如何从生产环境中的大量数据中获取到最有价值的信息。可以采用如下一些策略:

n  可衡量的发布标准。定义出关于所期望的用户体验的具体标准并持续监测它。如果可用性目标设定为99%,那么就对可用性进行测量看它是否达标。如果无法达标,要进行报警和诊断。

n  始终对实际数字进行收集。收集实际的度量值,而不是那些红红绿绿的图或其他形式的摘要报告。摘要和图表有用,但是对于问题诊断来说还是需要原始数据。

n  最小化“false positives(误报)”。在数据不正确时,人们很快就会放弃对它的关注。不过度报警很重要,否则运维人员很快就会习惯于忽略它们。这非常重要,以至于即使是附带地把某些真实问题隐藏掉也是可以接受的。

n  分析趋势。这个可以用来预测问题。例如,当系统中的数据流动速率异于往常时,通常预示着更大的问题。仔细挖掘现有的可用数据。

n  使系统健康程度保持高度可见。需要为整个组织提供一个随处可查并实时显示的系统健康状况报告。构建一个内部网站,使得大家可以随时查看当前系统状态。

n  持续监控。值得一提的是,人们必须要每天查看这些监控数据。每个人都应该这样做,但是也要为这项工作明确地指定某些负责人。

l  加大工程投入。良好的工程化可以最小化运维需求,同时可以将问题消除在萌芽状态。非常常见的一个现象是,组织通过不断地扩大运维团队来解决规模问题,而不是花时间设计实现一个可伸缩的、可靠的系统。那些起初没有考虑过大规模问题的服务,往往后面都会变得手忙脚乱。

l  支持版本回滚。版本回滚支持应是强制性的,同时在上线之前必须经过测试和证明。如果没有回滚支持,任何形式的生产级测试都将是非常危险的。回滚到前一版本就像降落伞上的“开伞索”,应保证它在任意部署中都是可用的。

l  保持向前和向后兼容性。{!Forwards
Compatibility,向前兼容。Forward有“将来”的含义,因此是指以前的版本支持现在版本生成的数据,现在的版本支持以后的版本数据。Backwards
Compatibility,向后兼容。Backward有“回头”的意思,所以是指现在的版本可以支持以前的版本数据}。这一点与前面一点非常相关。对文件格式、接口、日志/调试信息、仪表、监控和组件间的连接点进行的改变,都是潜在的风险。不要丢掉对旧文件格式的支持,否则未来将没有机会回滚到老版本。

l  单机部署支持。这既是测试的需求也是开发的需求。整个服务必须可以很容易地托管到单一系统中。对于某些单服务器无法实现的组件(比如,它依赖于一个外部的、不支持单机部署的服务),需要为它编写模拟器以支持单机部署。如果不支持这点,那么单元测试将很难进行,同时也没法完全展开。同时,如果运行整个系统很困难,开发人员也会倾向于在组件的级别上进行开发,而不是系统级。

l  针对负载进行压力测试。采用两倍(或更多)的负载来运行生产系统的某些子集,确保系统在高于预期负载情况下的行为仍然是可理解的,以及不会随着负载的上升而宕掉。

l  在新发布之前进行容量和性能测试。除了要在服务级上进行,还要对每个组件进行,因为负载特征会随着时间发生变化。需要尽早捕获系统内部的问题及退化现象。

l  增量地迭代地进行构建和部署。在开发的早期阶段,先把整个服务的骨架先搭建好。这个完整的服务可能几乎做不了什么,但是它可以让测试和开发人员更具有产品思维,可以一开始就站在用户的角度思考问题。在构建软件系统时这是一个非常好的实践,但对于服务来说更尤其重要。

l  采用真实数据进行测试。将生产环境中的用户请求和工作负载搬到测试环境中。挑选一些生产数据,并将它们放到测试环境中。多样化的真实用户群体在发现bug上总是更有创造力。显然,必须要进行隐私承诺,非常关键的是保证数据永远不会泄露回到生产系统中。

l  运行系统级验收测试。在本地运行一些可以加速迭代开发过程的完整性检查。为避免产生繁重的维护成本,它们都应当是系统级的。

l  在完整环境中进行测试开发。留出一定的硬件,以可以进行特定规模的测试。最重要的是,在这些环境中使用那些与生产系统相同的数据集合和挖掘技术,以最大化资源投入的价值。


硬件选型和标准化

采用SKU(Stock Keeping Unit,库存单元)标准化的常见理由是,批量采购可以节省大量的金钱。毋庸置疑这是正确的。但是硬件标准化的更大需要是,它可以支持更快的服务部署及规模增长。如果每个服务都是自己采购的基础设施,那么它们将需要:

1.      确定哪些硬件当前具有最好的性价比

2.      订购这些硬件

3.      一旦硬件被安装到数据中心,进行硬件认证及软件部署

这通常要花一个月,同时很容易就会花更多时间。

 

更好的方法是采用包含了硬件SKUs、自动化管理和配置设施的“services fabric”,让所有服务运行在它之上。如果一个测试集群需要添加更多机器,可以通过网页服务来提交请求,之后很快就直接可用了。如果一个小服务越来越成功,也可以从现有机器池里添置资源。

 

这种方法保证了如下两个关键原则:1)所有服务,甚至是小服务,都在使用自动化管理和配置设施;2)新服务可以非常快的进行部署和测试。

 

针对硬件选型的最佳实践如下:

l  只使用标准SKUs。如果生产系统中只有单个或少量SKU,就可以实现资源在服务间的按需流转。成本效益最好的模式是开发一种包含了自动化管理和配置、硬件以及一组标准共享服务集合的标准服务托管框架。标准化SKUs是实现该目标的核心要求。

l  整机柜采购。采购硬件应该以机柜或多个机柜为单位进行配置和测试。在大多数数据中心,机器组柜和堆垛成本是非常高的,因此要让系统制造商以机柜为单位进行交付。

l  硬件抽象。将服务编写地只是依赖于抽象的硬件描述。而不需要完全暴露硬件SKU,服务既不应该暴露SKU,也不应该依赖于它的内部细节。这样才可以在具有更高性价比的系统可用时,将现有设备替换掉。SKU应当只是一个包含了CPU和磁盘数,及最低内存要求的抽象描述。更细粒度上的SKU信息不应该被利用。

l  对网络和命名服务进行抽象。使用DNS和CNAMEs尽可能地将网络和命名进行抽象。始终坚持使用CNAME。硬件可能损坏、到期或挪作它用。在代码的任何地方都不要依赖于机器的名称。改变DNS中的CNAME要与需要改变配置文件甚至是代码相比,要容易得多。如果需要避免更新(Flush)DNS缓存,需要记得将TTL{!
Time-To-Live,简单的说它表示一条域名解析记录在DNS服务器上的缓存时间.当各地的DNS服务器接受到解析请求时,就会向域名指定的DNS服务器发出解析请求从而获得解析记录;在获得这个记录之后,记录会在DNS服务器中保存一段时间,这段时间内如果再接到这个域名的解析请求,DNS服务器将不再向DNS服务器发出请求,而是直接返回刚才获得的记录;而这个记录在DNS服务器上保留的时间,就是TTL值}设得足够低以保证变更可以尽可能快地被push。


运维和容量规划

要高效地运维服务,关键在于构建系统时消除各种需要运维交互的过程。目标在于让一个高可靠的,7*24小时可用的服务只需要5*8小时工作的运维团队维护即可。

 

但是,可能会发生不寻常的故障,而且系统或多个系统可能会无法恢复在线工作。要理解这种可能性的发生,并将受损系统的下线过程自动化。依赖于运维人员手动更新SQL表或者是使用特别的技术移动数据,都可能会招致灾难。处理故障的过程中也容易产生失误。运维团队需要预料遇到各种故障时的正确应对方式,并将这些过程提前进行编写和测试。一般来说,开发团队要将紧急恢复操作自动化

,并必须要对它们进行测试。很明显,无法将所有的故障都提前预料到,但是通常通过一小组恢复动作的集合就可以从类型广泛的故障中恢复过来。本质上来说,是需要构建和测试可以根据故障范围和危害以不同方式使用及组合的“恢复内核”。

 

恢复脚本需要在生产环境下测试。没有经过频繁测试的东西是无法工作的,因此不要实现团队没有勇气去使用的任何东西。如果在生产环境下测试的风险太高,那么说明脚本要么是没准备好,要么是在紧急情况下使用时也不会安全。这里的关键点是,灾难总是在发生,同时那些因为恢复步骤未按预期执行而导致由小灾难演变为大灾难的情况也是屡见不鲜。要预料到这些情况,并且要能在不造成更多的数据丢失和不服务时间的前提下,将服务恢复过程自动化。

 

l  增强开发团队责任感。在这方面,Amazon应该算是最激进的了,他们的格言是“you
built it, you manage it”。他们的主张要比我们现在所采用的方式稍微强些,但是这无疑是一个正确的方向。如果开发总是被在午夜吵醒,那么自动化就会是必然结果。但是如果是运维被吵醒,通常的反应是扩充运维团队。

l  只进行软删除。绝不要删除任何东西,只是将它们标记为已删除。当有新数据进来时,将请求记录下来。保存一个以两周(或更长时间)为单位滚动的变更历史记录,以便从软件或操作错误中恢复。比如有谁犯了错,忘记在delete语句中加上where子句(以前曾经发生过并且也难保将来不会再发生),数据的所有逻辑拷贝都会被删除。RAID和镜像都无法防止这种形式的错误。数据恢复能力可以让一个原本非常严重的问题变成一个微小的,不起眼的问题。对于那些已经进行了离线备份的系统来说,只需要额外记录那些上次备份之后进来的数据即可。但是,谨慎起见,多备份一些会更保险。

l  跟踪资源分配。理解容量规划中的额外负载带来的成本开销。每个服务都应该开发一些像并发在线用户、每秒请求数或者其他的一些相关指标。无论是何种指标,都需要在负载的此种测量方法和所需的资源之间有一个直接的已知关系。所估计的负载数应通过销售和市场团队的反馈得到,同时将会被运维团队用来进行容量规划。不同的服务具有不同的变化速度,同时有不同的订购周期要求。对于我们的服务来说,每90天会更新一下市场预测,每30天更新一次容量规划和订购需求。

l  一次只进行一个变更。碰到问题时,应该一次对环境只做一个变更。这看起来显而易见,但是我们也多次看到过因多个变更导致的因果关系无法确定的情况发生。

l  使所有东西可配置。任何可能在产品系统中发生改变的东西都应该是在生产环境下可配置和调整的,而不需要改变代码。即使某个值看起来没有很好的在生产环境中发生变更的理由,如果很容易的话也应让它可配置。但是不要在生产环境中随意更改它们,同时应该对系统连同那些将在生产系统中使用的配置一块进行严格的测试。但是当生产出现问题时,与编码、编译、测试、部署相比,简单地修改下配置总是要更简单、安全、快速。


审计、监控和报警

运维人员无法在部署中再对服务进行调整(instrument)。在开发过程中要付出足够的努力,来确保系统中的所有组件都可以产生相应的性能数据、健康数据以及吞吐率等数据。

 

在任何有配置变更发生的时候,都要在审计日志中记录下改了什么,谁改的,什么时间改的。在生产环境出现异常时,第一个要回答的问题就是最近到底进行过哪些变更。如果没有审计跟踪,那么答案通常是“没有改过什么”,而通常最可能的情况就是正是因为某个变更导致了问题。

 

报警是一门艺术。有一种倾向就是对所有事件进行报警,开发者期望可以从中发现有趣的事情,这就导致很多服务的第一版通常都会产生大量根本没人会看的无用报警信息。要提高效率,每个报警都应该对应着一个问题。否则,运维团队将会习惯于将它们忽略。我们不知道除了交互式地对报警条件进行调整外,还有何灵丹妙药可以让每个报警都正确,以保证所有关键事件都会被报警,在不需要采取任何措施的情况下就不报警。要得到正确的报警级别,有两个指标可能会有帮助,并值得进行追踪:1)报警和实际故障比(理想情况它的值应接近1);2)没有产生相应报警的系统故障数(理想情况它的值应接近0)。

l  Instrument everything。对通过系统的每个客户交互和事务进行监测,并报告异常。这是一个“runners”(可以合成工作负载来模拟生产环境中的用户交互)可以施展的地方,但是仅有它们还不够。如果只使用runners,我们曾看到一个严重问题甚至需要几天时间才被发现,因为标准工作负载一直被处理得很好,然后还要再花几天时间才能查到原因。

l  数据是最有价值的资产。如果对系统正常行为没有很好的理解,那么在它发生异常时也没法很好地进行处理。需要对关于系统行为的大量数据进行收集以确定系统状态是否正常。很多服务都经历过灾难性的故障,但是只有在电话铃响起时,人们才意识到故障的发生。

l  具有服务的客户视角。进行E2E测试。仅有Runners虽不足够,但是它们可以用来确保服务在完整运行。确保复杂和重要的路径能够被Runners测试到。避免误报,如果Runners的失败可以被忽略,那么就修改测试使得它是不可忽略的。再次强调一下,一旦人们习惯了忽略数据,以后即使再真的发生也无法再得到及时的关注。

l  对生产环境测试进行监测。要想安全地在生产环境中进行测试,需进行完整的测试和监控。如果组件发生了故障,需要能够快速地监测到。

l  延迟是最棘手的问题。比如像IO缓慢,虽未成故障但是处理变慢这样的问题。这些都很难发现,需仔细进行监测才能发现。

l  要有足够的生产数据。为了找到问题,数据必须是可用的。及早构建细粒度的监控,否则后面进行改造的成本会很高。我们所依赖的重要数据包括:

n  为所用操作采用性能计数器。至少要将操作延迟及每秒的操作数记录下来。这些数据的起伏通常是一个危险信号。

n  对所有数据进行审计跟踪。每当某人做了某事,尤其是重要之事,都要进行记录。这样做主要有两个目的:首先,日志可以用来进行挖掘以找出用户经常进行哪些操作(在我们的例子中,就是他们经常进行何种查询);其次,可以用它来在发现问题时帮助进行debug。

 与此相关的一个观点:如果所有人都使用同一个账号来管理系统,这样做不会带来太多好处。一个非常糟糕的想法,但是并不罕见。

n  跟踪所有容错机制。容错机制会将故障隐藏。每当重试发生,或将数据从一个地方拷贝到另一个地方,或机器重启以及服务重启时,都进行跟踪。在容错机制隐藏了小故障时,要能了解到并对它进行追踪,防止小故障演变成大故障。我们曾经有一个2000台机器的服务在几天内慢慢地下降到只有400台可用,但是一开始却没人注意到。

n  跟踪针对重要实体的所有操作。为发生在每个重要实体上的事件记录一个“审计日志”,无论实体是一个文档还是多个文档组成的集合。在运行数据分析时,通常能够通过数据发现异常。要了解数据的来源及其所经过的处理过程。到了项目后期再添加这些功能会变得特别困难。

n  断言。自由地在整个产品中使用断言。收集产生的日志以及程序奔溃后的core文件,并对它们进行研究。对于那些在同一个进程边界内运行了多个服务,以及无法使用断言的地方,要写下追踪记录。

n  保留历史数据。历史上的性能和日志数据对于趋势分析和问题诊断来说都是非常必要的。

l  日志可配置。支持可配置的日志,日志可以根据调试需求选择性地打开、关闭。在故障期间去部署具有额外监控的新构建版本是非常危险的。

l  向监控系统暴露健康信息。考虑多种从外部对系统健康状况进行监控的方法,并使之易于在生产环境下进行监控。

l  保证所有被报告的错误都有与之相应的处理动作。问题会发生。事情会出错。如果代码中的一个不可恢复的错误被检测到并记入日志,或者是报告为错误,错误信息应该能揭示错误产生的可能原因及建议的处理方法。不具备可操作性的错误报告是无用的,并且时间长了它们会被忽略,而真正的故障将会被错过。

l  实现生产问题的快速诊断

n  为诊断提供足够信息。当问题被标记出来时,提供足以让人进行诊断的信息。否则,进入门槛将会过高,同时标记也会被忽略。比如不要仅仅是说“有10个查询没有返回结果”,还需再加上“下面是它们的列表及问题出现次数”。

n  证据链。确保有一个可以让开发人员进行问题诊断的从头到尾的完整路径。这通常是通过日志实现的。

n  在生产环境中进行debug。我们更喜欢这样一种模式,在该模式中,系统几乎从不会被包括运维在内的任何人直接触碰,而debug是通过让系统产生快照,将内存内容dump出来,然后转移出生产环境再进行的。当在生产环境中进行debug是唯一选择时,开发者则是不二人选。确保他们对于可以在生产环境中做哪些事情是经过严格培训的。我们的经验表明,系统在生产环境中被触碰地越少,客户满意度越高。因此我们建议,一定要竭尽全力避免对生产环境中的系统进行改动。

n  记录所有的重要动作。每当系统执行重要动作时,尤其是在收到网络请求或修改数据时,要记录下发生的事情。包括用户何时发送了命令以及系统内部做了什么。有了这些记录,对问题调查大有裨益。更重要的是,还可以开发出挖掘工具来找到有用的聚合结果,比如当前的用户正在执行哪些种类的查询(比如,哪些关键字,多少关键字等等)。


优雅降级和准入控制

有些时候比如受到DOS攻击或使用模式发生某些改变时,会导致负载突然爆发。服务需要能够进行优雅降级及准入控制。比如在9.11期间,大多数新闻服务都崩溃了,无法为任何用户提供可用的服务。与此相比,就算是仅能够提供所有文章的一部分子集也是一个更好的选择。两个最佳实践,“big
red switch”和准入控制,需要针对每个服务进行量身定制。但是这两个都是非常强大和必要的。

l  支持“big red switch”。“big
red switch”的想法最初源自于Windows Live Search团队,它非常强大。我们对它进行了一些扩展,使得它可以应用在那些与搜索具有显著不同的事务型服务中。这个想法非常强大,实际上可以应用到任何地方。大体来说,“big red switch”是一种当服务不再满足它的SLA或迫在眉睫时,可采取的经过设计和测试的动作。将优雅降级比喻为“big
red switch”,稍微有些不太恰当,但核心的意思是指那种可以在紧急情况下摒弃那些非关键负载的能力。

“big red switch”概念是以丢弃或延迟非关键负载为代价,保证关键处理过程能继续进行的关键。根据设计,这种情况应永不发生,但是当真的发生时这也不失为一个好方法。等到服务已处于危险的情况下,再考虑这些就太迟了。如果有些负载可以被暂时放入队列后面再处理,那这也可以作为“big
red switch”的候选。另外如果在关闭高级查询的情况下,事务可以继续执行,那这也可以作为一个候选。关键在于确定碰到问题时系统所需的最小集合,然后实现关闭那些不必要的服务的开关,并进行测试。需要注意的是,正确的“big red switch”应是可逆的。同时应对开关的重置进行测试,确保所有服务可以回到完整服务状态,包括所有的批处理任务及先前被暂停的非关键工作。

l  准入控制。第二个重要概念是准入控制。如果当前的负载系统已经无法处理了,那么再往系统中增加负载也只是会让更多的用户产生糟糕的体验。如何实现这一点与系统本身有关,某些系统比其他系统更容易完成。以电子邮件处理服务为例,如果系统已经超负荷,并开始排队,此时最好不要再接收邮件而是让它们在来源队列中等候。这样可以产生效果并能实际减少总体服务延迟的关键原因是,如果队列形成处理时间会变更慢。如果我们不允许队列的建立,那么吞吐量将会更高。另一种技术是:提供服务时高端用户优先于非高端用户,注册用户优先于访客,或者是访客优于用户如果是以“试用和购买”为商业模型的话。

l  准入计量。另一个非常重要概念是上面所确定的准入控制点的修改。如果系统发生故障并宕机,为确保一切正常恢复时必须能够缓缓进行。比如先让一个用户进入,然后每秒允许10个用户进入,如此慢慢加大。对于每个服务来说,拥有一个细粒度的旋钮可以在重新上线或从灾难性失败中恢复时缓慢增加使用量,是至关重要的。在任何服务的第一个版本中很少会包含这种能力。对于一个有客户的服务来说,一定有方法来通知它的客户暂时无法提供服务以及何时会恢复。这就允许客户端在可以接受的情况下继续修改本地数据,同时也可以让客户端暂时退下避免干扰服务,让服务可以尽快恢复上线。这样也同时为服务owner提供了一个直接与用户沟通的机会,并可借此调整他们的期望。另外的一个可以避免所有客户端同时涌向服务端的技巧是:故意制造抖动和对每个实体进行自动备份。


客户和媒体沟通计划

系统发生故障时,就需要就由此引发的延迟和其他问题与客户进行沟通。沟通应以可选的方式通过多种媒介进行:RSS,网站,即时消息,电子邮件等。对于那些具有客户端的服务来说,让服务具备通过客户端直接与用户联系的能力是非常有用的。可以在特定的时间点或时间段,要求客户端下线。如果支持的话,也可以让客户端运行在连接断开或缓存模式下。可以通过客户端将系统状态告知用户,并说明预计在何时会完全可用。

 

即使没有客户端,用户也可以通过其他方式与系统交互,比如通过网页将系统状态公布给用户。如果用户了解什么正在发生,并且对于服务何时恢复也有一个合理的预期,就会大大提高他们的满意度。对于服务提供者来说,有一个想要隐藏系统问题的自然倾向,但是随着时间的推移,我们越来越确信,将服务可用性的信息提供给客户几乎总是可以提高他们的满意度。即使是对于免费系统来说,如果人们可以清楚地知道什么正在发生及何时可以恢复正常,他们就会对服务更有信心而不会轻易放弃使用。

 

某些特定类型的事件将会引发媒体报导。如果事先考虑到这些场景做好应对,那么服务将会带给人们更好的印象。像大量数据丢失或损坏,安全入侵,隐私侵犯以及长时间的服务停机等问题都可能引起媒体的关注。事先准备好沟通计划。知道需要与谁、何时、怎么通电话。沟通方案的框架应该提前准备好草案。针对每种类型的灾难,都应该提前准备好沟通计划,包括与谁、何时、如何沟通。


客户自配置与自助

客户自配置可以大大降低成本,同时还能提升客户满意度。如果客户可以简单地通过打开网页,输入所需数据,然后就可以开始使用服务,这会比他需要打电话然后在呼叫处理队列里浪费大量时间,满意度要高地多。我们一直觉得主要的移动运营商因为一直未为那些不想致电客户服务的人们提供自助服务,错过了一个既节省成本又可以提高客户满意度的机会。


总结

对于大规模互联网服务来说,降低运维成本和提高服务可靠性始于编写运维友好的服务。在本文中,我们定义了何谓运维友好,并总结了来自于从事大规模服务的工程师在服务设计、部署、开发和运维方面的最佳实践。

src: "http://duanple.blog.163.com/blog/static/709717672013511101045985/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: