创建可扩展性系统-2

 系统稳健性的一些模式

 

 

 

抛开稳健性来谈谈系统的可扩展性,就像一只没有稳固后防的球队想取得好成绩,或者在沙滩上堆建宏伟的城堡,注定缘是木求鱼式的努力。一个很明显的例子是当今社会的维稳成本已经高过国防支出,没有稳定性,就没有可持续发展的可能。这个章节我们先讨论和稳健性相关的一些常用模式。

稳健性概念看似直观,但是由于开发小组和维护小组往往是不同成员, 多数程序开发员并没有实际经验去处理产品的稳健性问题。在XP和敏捷开发中,测试导向[Test Driven ] 的开发理念强调开发可测试的单元,在一定程度上导致了实现所有功能和系统可实际交付使用之间的差距。系统稳健性的很多问题往往在系统交付运行一定时间后才显示出来。比如很多系统存在一定程度的内存泄漏,程序在运行一段时间后需要重新启动; 或者产品运行时关联系统崩溃,用户负载的突然变化,以及网络阻塞。所有这些在开发测试环境中被忽略或难以重复的因素,程序开发人员应该在技术架构及开发时加以考虑。

 

有人开玩笑说,程序员的一生有3件事情不可避免,交税,死亡,和BUG。社会学中著名的墨菲定律告诉我们: 如果�氖掠锌赡馨l生,不管�@�N可能性有多小,它����l生,�K造成最大可能的危害。既然一个具有一定复杂度的软件系统中的Bug是不可避免的,开发人员在设计开发系统时,需要考虑处理各种可能的差错;而不是因为直觉上认为这些差错发生的可能性比较低而指望它们在实际运行中不会发生。

稳健性原则的核心是在不改变系统的复杂度的同时, 如何使各种固有的不确定性对系统整体运行的影响最小。 Michael T. Nygard 的《Release It! -Design and Deploy Production-Ready Software》一书很受好评。本书总结了和稳健性相关的一些模式和反面模式,把不确定性给系统带来的负面影响控制在最小范围,值得一读。

Nygard在书中提到数年前一家美国航空公司因为系统升级时故障造成了全国范围内成千上万的旅客没法登机。Nygard在事故诊断中发现因为防火墙的设置,造成了闲置的数据库连接的失败, 一行标准代码引起了系统灾难性的崩溃,给企业的正常业务带来严重损失。类似的例子几乎经常发生。那么如何控制系统运行中的各种不确定性风险呢?

 

中国人在宋代最先发明了水密隔舱的造船技术。方法是�⒋��w分成�S多����^,各��互不相通,�@�赢�船在航行�r,如果某�����^破�p�M水,船仍然不��沉�]。�@�拥脑O�提升了船的安全性。 在现代船舶设计中,大型船舶设有多个锅炉舱; 这样一个锅炉舱 进水停止工作,不会影响船舶正常工作。

 

在软件系统架构中,我们也采取了相同的策略来提高系统的稳健性。 当系统出现错误时(船体进水),一方面我们需要尽可能的孤立错误,防止影响扩大(密隔舱);另一方面,最好有冗余的替代方案(多个锅炉舱)来替代不能正常工作的组件(进水的锅炉舱)。

 

一。隔离错误, 防止负面影响扩大的策略

从不确定性来源分类,一种是来自程序自身代码的潜伏的BUG,一种是来自调用的第三方系统

减少程序自身的不确定性的原则是尽量减小程序执行中的变动产生的影响范围和影响持久程度。 实现起来主要有几点: 一是尽可能的不修改状态, 把对象状态的不变性(Immutability)做为设计的基本原则;二是在系统内部相互作用时,使用无副作用的函数调用(Referential Transparency 引用透明),在调用过程中,过程内部状态不允许对全局变量赋值操作;三是严格遵守DRY(Dont Repeat Yourself)原则,避免相同信息的分散和重复。在代码水平上,遵守良好的编程习惯,比如局域变量声明尽可能的接近变量的使用。

从系统架构角度,控制整合第三方(Integration Point)产生的不确定性,包括所有的socket, process, pipe, 远程调用和数据库调用。调用可以看做通过整合点的电流,电流过大超过系统自身的负荷承受范围, 组件会烧坏;电流过小系统又无法正常工作。我们也可以把调用理解为信息流,在信息流通过软件组件时,信息流量过大过小组件都没法正常工作。 与此相对应的,我们有两种防御性的设计模式来确保接口正常工作: 流量过大时的保险丝模式和流量过小时的超时模式。 保险丝模式在 Nygard的《ReleaseIt 中有一个相似的概念“Fail Fast” 它是针对外部调用自身接口, 有点像男女之间的那点事儿:好的服务就是好的人品,不喜欢就直接拒绝,不暧昧~;而超时模式主要是针对系统调用外部接口, 好比追求异性时有坚持,也有止损底线,千万别在一棵树上吊死(SPOF) 另外Nygard 还提出了断路器(Circuit Breaker)模式来描述暂时中断对问题端口的调用,而在实际应用中,我们往往使用指数回退法重试(Retries With Exponential Backoff)。

通过对于整合点异常状态的控制,在一定程度上对调用双方进行了去耦合化处理;这样系统一部分出错产生的负面影响就不会扩散而导致系统其他部分的功能障碍。

 

模式名称:使用不变性做为设计的原则。

描述 在系统运行中不改变对象状态。

动机/试图解决问题:当系统运行中,对象状态改变时,增加了程序的复杂度。

原理 在系统运行中不改变对象状态, 避免了状态管理的复杂度。 尤其对于多进程的调用,使用不变性是防止多进程编程中的进程死锁等一系列问题的最基本的策略。

使用:在程序的设计实现时。

相关模式:使用引用透明原则。

 

模式名称:使用引用透明原则。

描述 在调用过程中,过程内部状态不允许对全局变量赋值操作。

动机/试图解决问题:当函数调用时,调用产生负作用,而使得同样调用对系统产生不同的影响。

原理 引用透明原则使得代码API易于理解,易于诊断,易于优化; 而且简化了状态管理,支持模块化。

使用:在程序的设计实现时。

相关模式 使用不变性做为设计的原则。

 

模式名称:保险丝模式

描述:当系统负载超过固有的承受范围,严重违反SLA 让服务立即返回错误代码。

动机/试图解决问题:避免响应迟缓

原理:引起响应迟缓的因素很多,比如系统负载过高,网络阻塞,防火墙超负荷等。 当响应迟缓发生时,有可能引起关联服务的连锁反应,或者严重影响系统的处理能力,加速系统资源的最终耗竭而崩溃,

使用:在整合点有系统外部调用时。

相关模式Fail Fast/Crash Early/Let It Crash/Circuit Breaker

模式名称:超时模式

描述:对任何第三方调用,需要准备超时处理。

动机/试图解决问题:任何对第三方的调用,都有被挂起的可能性。

原理:如果调用被挂起, 处理相应调用的线程也被挂起,在占用系统资源的同时, 降低了系统的事务处理容量。超时处理可以释放被挂起的资源。

使用:在调用socket, process, pipe, 远程调用和数据库连接时。

相关模式:指数回退法重试, 断路器(Circuit Breaker

模式名称:指数回退法重试(Retries With Exponential Backoff

描述:在对第三方服务调用失败时,重试的策略。

动机/试图解决问题

原理 西谚有一句“When it rains, it pours”, 也就是我们说的祸不单行。这句话有2 层意思:一个灾害可以引发别的灾害; 或者灾害的发生,往往是大范围的。 当一个用户面临服务调用失败时,往往会有多个用户面临同样问题。 反复的重试,往往会加大负载,而劳而无功。 指数回退法是用于防止网络阻塞的一种重试策略,也可以用于降低重试冲突,避免加大的系统负载。

指数回退法的原理十分简单, N次重试的时间点是[0 2n ]区间内的任意值。

使用:在调用失败时。

相关模式:超时模式, 断路器(Circuit Breaker

备注 指数回退本身也需要对重试次数N设定阈值。

二。 为出错准备替代方案的策略。

单点失效(single point of failure (SPOF) )是指一个系统的这样一个部件,如果它失效或停止运转,将会导致整个系统不能工作[百度百科】。SPOF存在于商业运作(物流管理),软件系统和其他工业系统中, 直接影响到系统的可用性或者稳健性。

 

解决SPOF的基本原理是对所有的SPOF使用冗余复制。 冗余可以设计在不同的层次; 以信息系统为例, 冗余可以分为内部组件级冗余,系统级冗余和网站级冗余。 对于高可用性服务器集群,每个服务器可以有多个电源供应器,硬盘驱动器和其他元件,以此实现内部组件水平的冗余。系统级冗余的实现是使用备用服务器承担失效服务器的工作 。数据中心是在网站级别的一个潜在的SPOF。因此整个服务器集

群可以被复制在另一个物理位置,作为主访问站点不工作时的替代。

 

对于系统的不同架构所引入的SPOF也不一样。比如硬盘可能在一种系统设置中是SPOF而在不同的设计中却不是。在设计系统时需要检查每一个组件是否是SPOF 而且需要进一步权衡使用冗余处理SPOF的代价和忽略SPOF的风险。

 

1.    Service Gateway 等部署在多台机器上。

2.    如果使用消息服务,设置备份切换。

3.    对于数据库连接,需要定期检查连接是否被挂起。不同的RDBMS提供了类似的功能。比如Oracle 失效链接监测(Dead connection detection). DB2 RECONNECT group

4.    对于保存在数据库里的数据和数据库实例本身的冗余, 不同的RDBMS的处理方式略有不同。对于Oracle, Mysql DB2, 都可以使用冗余的备份切换来获得更高的系统可用性。

5.    网络中网线,网卡,路由器,文件系统(NFS)的SPOF

6.    硬件,系统软件的SPOF

7.  存储硬盘的SPOF

 

数据的冗余复制的机制分为主动复制和被动复制两类。主动复制是一种”(Push) 的模式,需要复制的原始数据被到不同的复制点;被动复制是一种Pull)的模式, 复制点在需要复制数据时向存储原始数据的节点索取该数据。比如基于超时的缓存或者分布式缓存系统很适合应用拉动的模式。

模式名称:复制/备份切换

描述 当系统的一个组件不能正常工作时,负载被重新分配到运行中的相同组件或者后备的相同组件。

动机/试图解决问题 SPOF影响系统的可用性。

原理 复制/备份可能出错的组件节点, 防止了单个组件节点的出错而引起的系统失效

使用:可以在任何SPOF点使用。

相关模式:主-- (Master-Slave) --(Master-Master) 同伴复制(Buddy Replication) ,备份切换(Fall-Over)

  

总结:

在软件系统架构中,我们采取了相同的类似造船技术中的密隔舱策略来提高系统的稳健性。一方面我们使用去耦合,保险丝,超时重试等策略尽可能的孤立错误,防止影响扩大;另一方面,使用冗余复制的方案来解决SPOF,替代不能正常工作的组件。

本文出自 “静水流深” 博客,转载请与作者联系!

你可能感兴趣的:(系统架构,可扩展性)