复杂度中的可用性

2017, Nov 30    

维基百科是这么定义可用性的:系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一。

CAP定理中,A的定义:每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据。

简单讲就是有去必回!

但从实际情况来说,无论是单个硬件或软件都不可能做到无中断。而且除了软件和硬件本身,外界的因素也会导致中断。

既然是这样,那怎么最大限度避免呢? 做”冗余”!单节点容易出问题,就做冗余多节点。地区网络容易出问题,就”异地多活”。

高性能增加机器目的在于“扩展”处理性能;高可用增加机器目的在于“冗余”处理单元。

通过”冗余”增强了可用性,但也同时带来复杂性。

计算高可用

这里的“计算”指的是业务的逻辑处理。 计算有一个特点就是无论在哪台机器上进行计算,同样的算法和输入数据,产出的结果都是一样的,所以将计算从一台机器迁移到另外一台机器,对业务并没有什么影响。

随着性能的提升,单节点变为多节点集群,具有以下表现:

  • 需要增加一个任务分配器,选择合适的任务分配器也是一件复杂的事情,需要综合考虑性能、成本、可维护性、可用性等各方面因素。
  • 任务分配器和真正的业务服务器之间有连接和交互,需要选择合适的连接方式,并且对连接进行管理。例如,连接建立、连接检测、连接中断后如何处理等。
  • 任务分配器需要增加分配算法。例如,常见的双机算法有主备、主主,主备方案又可以细分为冷备、温备、热备。

对于高可用集群来说,分配算法更为复杂,可以是1主3备、2主2备、3主1备、4主0备。 当然具体算法要根据具体业务而定。例如,ZooKeeper 采用的就是 1 主多备,而 Memcached 采用的就是全主 0 备。

存储高可用

存储与计算相比,有一个本质上的区别:将数据从一台机器搬到到另一台机器,需要经过线路进行传输。 长距离的传输延迟会非常高。而高延迟意味着数据的不一致。

数据 + 逻辑 = 业务

如果数据不一致,就算逻辑一致,也会造成业务上的不一致。

例如:淘宝用户在陕西时,服务将其就近分配在陕西的服务节点上可以选购下单支付,但最终账户金额,需要从杭州服务上获取。 但因为陕西和杭州的延迟较大,同步不及时,用户就看不到正确的金额。

除了物理上的传输速度限制,传输线路本身也存在可用性问题,传输线路可能中断、可能拥塞、可能异常(错包、丢包),并且传输线路的故障时间一般都特别长,短的十几分钟,长的几个小时都是可能的。 例如,2015 年支付宝因为光缆被挖断,业务影响超过 4 个小时;2016 年中美海底光缆中断 3 小时等。在传输线路中断的情况下,就意味着存储无法进行同步,在这段时间内整个系统的数据是不一致的。

无论是正常情况下的传输延迟,还是异常情况下的传输中断,都会导致系统的数据在某个时间点或者时间段是不一致的,而数据的不一致又会导致业务问题; 但如果完全不做冗余,系统的整体高可用又无法保证, 所以存储高可用的难点不在于如何备份数据,而在于如何减少或者规避数据不一致对业务造成的影响

但要保证可用性的同时也要保证一致性是非常复杂的,可以参考 CAP定理:

不可能同时满足“一致性、可用性、分区容错性”,最多满足其中两个

P是基础,所以实现大方向都是基于CP或AP。

高可用状态决策

无论是计算高可用还是存储高可用,其基础都是“状态决策”, 即系统需要能够判断当前的状态是正常还是异常,如果出现了异常就要采取行动来保证高可用。

但在具体实践的过程中,恰好存在一个本质的矛盾:通过冗余来实现的高可用系统,状态决策本质上就不可能做到完全正确

常见的决策方式

独裁式

独裁式决策指的是存在一个独立的决策主体,我们姑且称它为“决策者”,负责收集信息然后进行决策;

所有冗余的个体,我们姑且称它为“上报者”,都将状态信息发送给决策者。

优点:独裁式的决策方式不会出现决策混乱的问题

缺点:因为只有一个决策者,当决策者本身故障时,整个系统就无法实现准确的状态决策

如果决策者本身又做一套状态决策,那就陷入一个递归的死循环了。

协商式

两个独立的个体通过交流信息,然后根据规则进行决策,最常用的协商式决策就是主备决策(1 主 1 备)。

这个架构的基本协商规则可以设计成:

  • 2 台服务器启动时都是备机。
  • 2 台服务器建立连接。
  • 2 台服务器交换状态信息。
  • 某 1 台服务器做出决策,成为主机;另一台服务器继续保持备机身份。

能看到这样设计主要依赖于两台机子之间的信息交换, 但如果信息交换出现问题:

  • 如果备机在连接中断的情况下认为主机故障,那么备机需要升级为主机, 但实际上此时主机并没有故障,那么系统就出现了两个主机,这与设计初衷(1 主 1 备)是不符合的。

  • 如果备机在连接中断的情况下不认为主机故障,则此时如果主机真的发生故障, 那么系统就没有主机了,这同样与设计初衷(1 主 1 备)是不符合的。

  • 如果为了规避连接中断对状态决策带来的影响,可以增加更多的连接。 例如,双连接、三连接。这样虽然能够降低连接中断对状态带来的影响(注意:只能降低,不能彻底解决), 但同时又引入了这几条连接之间信息取舍的问题, 即如果不同连接传递的信息不同,应该以哪个连接为准? 实际上这也是一个无解的答案,无论以哪个连接为准,在特定场景下都可能存在问题

民主式

民主式决策指的是多个独立的个体通过投票的方式来进行状态决策。 例如,ZooKeeper 集群在选举 leader 时就是采用这种方式。

民主式决策和协商式决策比较类似,其基础都是独立的个体之间交换信息, 每个个体做出自己的决策,然后按照“多数取胜”的规则来确定最终的状态。

除了算法复杂,当个体之前交互出现问题,形成多个子群体(每个子群体都会产生各自的领导,这样就违背来1主多备) ,就有一个固有的缺陷:脑裂。 脑裂指人体左右大脑半球的连接被切断后,左右脑因为无法交换信息, 导致各自做出决策,然后身体受到两个大脑分别控制,会做出各种奇怪的动作。

无论采取什么样的方案,状态决策都不可能做到任何场景下都没有问题, 但完全不做高可用方案又会产生更大的问题,如何选取适合系统的高可用方案, 也是一个复杂的分析、判断和选择的过程。

很多公司拿可用率作为运维人员的KPI,例如可达到99.99%(俗称4个9),我们可以算一下一年下来留给处理故障的时间有多少? 年度总时间=3652460=525600分钟 网站不可用时间=525600*(1-99.99%)=52.56分钟 也就是,如果网站要达到4个9的可用性,一年下来网站不可用时间最多53分钟(也就是不足1个小时)。

高可用的解决方法不是解决,而是减少或者规避,而规避某个问题的时候,一般都会引发另一个问题,只是这个问题比之前的小 ,高可用的设计过程其实也是一个取舍的过程。 这也就是为什么系统可用性永远只是说几个九,永远缺少那个一。

大多场景可用性要求大于一致性,毕竟”亲,稍后再试”比无法访问要友好太多 : )