除了避免单点外,降低耦合也是设计高可用性系统时应考虑的重点,通常可以采取异步化来降低耦合,将非关键逻辑和关键逻辑隔离开,例如在淘宝上买一件商品,确认购买了后,需要旺旺通知卖家,如果旺旺通知卖家这个过程是同步通知的话,对于系统来说无疑增加了一个风险点,因此可以将旺旺通知卖家的步骤变为异步的方式来做,这种场景的异步通常又采用消息中间件来实现;还有另外一种场景也经常采用异步化的方式来降低耦合,例如打开天猫的商品详情时,都会有相关商品的推荐,如果这个推荐系统出问题的话,就会导致商品详情也看不到了,因此这里也可以采用异步化来加载推荐系统,在这种场景中通常采用Ajax带超时的方式来实现。
各网站在总结多年的可用性系统设计的经验时,有一个设计原则被所有网站列入:保持简单,简单的方案意味着容易掌控,而复杂的方案一方面意味着实现难度大,另一方面意味着出现问题时很难排查。
可控性也是各网站强调的重点,可控性就意味着一切的代码都在掌握下,并且最好是每个使用到的部分都有专业的人士(对可用性要求越高,在这点上要求也就越高),这样才能清楚在出现问题的时候是哪个地方造成的,并且可以自行排查和解决,如不可控,则意味着一旦出现问题,就得依赖第三方来排查,那这个时间就非常不可控了,这也是网站不采用商用软件的重要原因。
编写高质量软件是保障系统高可用性的重要一环(可控性也是编写高质量软件的基础),但软件几乎不可能做到0 bug,各网站在总结自己保障高可用的经验中提到了一些策略用于保障系统的高可用,这些策略主要包括:监控/报警、容错、自我保护、隔离、和降级,需要做到高可用的软件在交付时都应具备这些特性。
监控/报警是软件自身能够保障高可用的重要策略,就像是汽车的仪表盘一样,可以告诉你油还剩多少,速度是多少,胎压是否正常等重要信息,对于软件而言,同样需要让外部可以获取到其运行的状况,例如Google的软件都会提供一个html的页面供使用者或开发人员访问(用过Hadoop的人也会发现这个特征),在这个页面上可通过key/value的方式来获取系统的一些运行指标,对外RPC的系统Google会采集所有的正常请求、错误请求以及其消耗时间的分布状况(>0.05s的,>0.1s等),除了监控系统的运行状况外,也需要提供一些方式以便外部能简单判断系统运行是否正常,例如curl某页面等,对于不正常的现象要进行即时的报警,以尽可能做到在故障尚未影响到用户时进行解决。
软件会依赖很多外部的因素,例如机房、硬件、数据库、服务等,而所有依赖的部分都是有可能出现故障的(要坚信这点,互联网的特色是所有小概率事件都会发生),在设计软件时需要考虑当依赖方出问题时,如何能保障软件本身的可用性,因此一定要做一些容错的处理,例如对于机房故障,各网站通常都会租用或建设多机房来避免;又例如Google采用IDE硬盘来存储文件,不做Raid,于是采用了复制三份的策略来避免硬盘故障导致数据丢失。
软件通常会接受外部的输入,而有些时候输入条件的不符合预期可能会导致软件的故障,在我们的系统中曾经出现的一个故障案例:某系统对外提供了批量查询的功能,结果有一次客户端提交了一个查找10000个用户的批量查询,导致系统由于内存不够出现了故障,因此在设计软件时需要保障处理自己能力范围的请求,对于超出能力的请求可以考虑直接抛错,还有一种常见的是后端处理变慢导致雪崩效应的故障,这种在软件上通常会采用超时、限流等方式来避免,对于这些可能出现的故障在设计软件时都应考虑采取一些保护的措施来保护自身的可用性。
软件通常提供了多种功能,这些功能会有重要的和不重要的,如果由于不重要的功能异常导致重要的功能出现问题,显然是不合算的,因此在设计软件时需要充分的考虑异常的隔离,不互相影响,例如在Google的系统设计中会采用Prioritized Request等策略。
降级即为James Hamilton的那篇著名的《On Designing and Deploying Internet-Scale Services》论文中提到的Graceful Degradation,降级通常采用的方法是在故障将要出现或出现后,通过关闭系统的一些功能来降低故障产生的影响,例如网站上有些操作可能是特别耗资源的,而这些资源的消耗又可能会导致影响到核心功能,一旦出现影响时,就可以通过关闭这些功能保障核心功能的可用,降级通常用于临时的绕开故障,故障的原因则事后排查。
交付具备高可用特征的软件是开发人员的重要职责,而对于一个网站而言,软件不是一次性交付的,也不是好几年才升级一次的,而是频繁交付的,因此对软件本身的维护也是保障高可用的重要环节。
通常,系统的不可用是变更造成的,如何降低变更对系统可用性造成的影响,是各网站都关注的重点,Google在发布时通常采取“滚木移石”的方法、Facebook则通常采用Dark launch的方法,以降低变更带来的影响。
人工来操作系统的变更是故障产生的隐患,因此各网站基本都会推荐多种工具来实现系统变更的自动化,例如采用puppet来实现自动化的部署。
除了发布这个重要环节外,处理故障也是维护的重要工作,系统总是会有出现故障的时候的,出现故障时如何快速的处理来降低对可用性的影响也成为了网站一直关注的重点,前文已经说到可控性对解决故障的帮助,除了可控外,各网站也会研究一些其他的方法,Facebook就采用了FBAR来自动处理部分故障,这显然可以一定程度降低故障产生的影响。
性能
在前文中提到的可控性同样也是保证性能的重点,只有明确的知道调用的每个API,依赖的环境(包括软硬件)的细节原理,才能编写出高性能的软件。
从系统结构上来看,我们可以看到各大网站在发展到今天的时候,为了保障高性能都采用了类似的方法,首先是前端Web系统这块,都采用了可编译为机器码的方式,例如即使是Facebook采用php,其仍然研发了一个可自动转化为C++代码的产品来提升运行效率。
设计系统时应考虑将没有前后依赖的逻辑并行化处理,,或者将大的请求进行拆分,例如在Google上进行搜索,Google会进行分词,然后并行的进行索引的查询,从而提高响应速度。
基本上各大网站都极度依赖Cache,这原因很明显,内存的访问速度远快于磁盘,依赖Cache的场景中最需要做到的是数据一致性的合理保障,一个典型的场景是数据更新时保障Cache一致性的策略,Cache的更新和数据的更新如果要做成一个事务显然有不小的难度,此时网站常采用一个简单策略来保障,就是先失效Cache,再更新数据,等到下次系统去访问此数据时,才更新到内存。
原文转自:http://bluedavy.me/?p=396