首先再次推荐一下《Release It!》,下面接着上一篇日志继续这个话题
Pattern 1. Use Timeouts 一定要设置超时
“等待”是大多数系统无法服务的直接原因:不响应的服务,Sync Flood攻击,死锁的IO,太多的并发连接。网络永远是个不可靠因素,设置超时是任何一个涉及到网络的接口需要的参数,而且要设置一个合理的值,太长等于没有,太短会造成很多不必要的错误。
Pattern 2. Circuit Breaker
小时候听大人说了不少农村刚通上电的时候很多中电的惨案,而现在已经鲜有触电身亡的人了,我还被220V AC点到过两次,所幸有断路器的保护,没有造成任何伤害。软件系统设计里也有这么一个“断路器”的设计模式,把一个系统暂时隔离出去,避免造成更严重的损害,在排除危险后再重新闭合。使用超时是一个保护性的措施,但是如果一个服务完全失效了,所有的连接都需要等待到超时也是个不小的代价。这种情况就适合用断路器了:可以指定连续多少次的超时就可以认为这个服务已经死了,就把断路器设为断开状态,然后每间隔一段时间会将连接置为半开状态,来检查服务是否恢复,在半开状态会尝试连接这个服务,成功则改为连接状态,否则立即回到断开状态。 这样可以避免一个不稳定的,或是已经出问题的接口占用大量的连接。
Pattern 3. Bulkheads
Bulkheads的意思是“舱壁”,就像泰坦尼克,有16个隔舱,当船遭遇碰撞时,4个隔舱进水船也是不会沉的,不幸的是… 软件设计里也有这么一种策略,宁可损失一部分,也要保证其他的系统可以运行。比如一个资源有限的网站要搞个秒杀活动,说不好流量能到大到什么程度,为了防止这个新功能影响网站的其他重要业务,可以把这个功能做到几台独立的服务器上,和原有系统的接口也加上流量控制,也就是把这个功能放在一个隔绝的船舱里,这样即使这个系统因为流量过大崩溃了,系统的其他重要业务依然可以正常运转。当然这样做会带来很多额外的成本:不均衡的资源分配,过多的冗余,复杂的管理,这就需要权衡一下利弊了。
Pattern 4. Steady State
这个模式我觉得应该算是个原则:一个稳定的系统应该是可以不需要人工干预的。如果一个系统经常需要有人登录到生产服务器上做一些维护任务,那么这个系统的稳定性非常值得怀疑。威胁到一个系统长时间稳定运行的因素主要是数据,产品往往会要求要保留所有的历史数据,但这对于开发是不现实的,一个合理的数据清理或归档的策略是一个稳定的系统必须的。另外两个因素是磁盘和内存,很多时候磁盘被填满都是因为日志文件,所以项目代码里最好包含一个logrotate的配置,定期清理一下日志。内存是另一个重点,内存泄露是一方面,做Web系统的人一般接触不到,就算是碰到了也是要等底层的服务器软件提供方来解决的.另外一个用内存的地方就是缓存了,对于PHP这个问题也不大,每个请求结束都会回收资源,对于其他语言就要注意了,保存的Session或者缓存的对象最好放在memcached或者redis里。
Pattern 5. Fail Fast
这个是对于服务提供端的要求:如果能预料到失败,就早点儿告诉用户,免得别人等,也浪费自己的时间。设置超时就是要防着没有做到这一点的服务端的。比如在处理数据之前,先验证一下客户端输入是否正确;比如一个需要依赖数据库的服务,在进行复杂计算之前先检查一下数据连接是否就绪,这样就能节省客户端的等待时间,避免自己无用的计算;如果一个服务需要依赖多个资源,提前获得各种资源也可以避免造成相会之间的死锁。这样做也是有缺点的,提前获得了资源也意味着可能占用资源的时间更长,影响并发处理的效率。
Pattern 6. Handshaking
这个一般会用在比较底层的协议中(TCP链接就是需要先握握手的),握手的目的主要是要检查一下相互的状态是否准备好,通信的协议的版本,双方的处理能力,请求速度限制之类的东西,进行一个动态的协商。看起来是比较高端的技术啦,对于Web开发估计用到的机会不多,算是提供个思路吧。
Pattern 7. Test Harness
这个就是要强调测试的重要性了,强壮的系统需要有黑客般彪悍的测试。
Pattern 8. Decoupling Middleware
这儿说的就是中间件的价值,我也不是很懂。中间件也就是运用前面说到的那些Pattern来达到系统间解耦的,提高系统可靠性的工具。各种开源的或者商业的中间件提供了不同的系统集成的架构,在自己实现之前,可以先找找有没有别人做好的。
最后总结一下,健壮的系统并不是不会生病,而是病了之后能很快康复,不会造成大的伤害。所以研究系统的可靠性并不是要杜绝故障,而是训练免疫系统,当故障出现时尽量减少伤害,并且尽快恢复。