系统的可用性(Availability)是描述应用系统可有效访问的特性。
基本策略
我们都知道,硬件故障是常态,网站的高可用架构设计的主要目的就是保证服务器硬件故障时服务依然可用、数据依然保存并能够被访问。
实现上述高可用架构的主要手段是数据和服务的冗余备份及失效转移,一旦某些服务器宕机,就将服务切换到其他可用的服务器上,如果磁盘损坏,则从备份的磁盘读取数据。
一个典型的网站设计通常遵循应用层、服务层、数据层的基本分层架构模型。各层之间具有相对独立性,应用层主要负责具体业务逻辑处理;服务层负责提供可复用的服务;数据层负责数据的存储与访问。
在应用层,可以通过负载均衡设备将一组服务器组成一个集群共同对外提供服务,当负载均衡设备通过心跳检测等手段监控到某台服务器不可用时,就将其从集群列表中剔除,并将请求分发到集群中其他可用的服务器上,使整个集群保持可用,从而实现应用高可用。
服务层的情况和应用层类似,也是通过集群方式实现高可用,只是这些服务器被应用层通过分布式服务调用框架访问,分布式服务调用框架会在应用层客户端程序中实现软件负载均衡,并通过服务注册中心对提供服务的服务器进行心跳检测,发现有服务不可用,立即通知客户端程序修改服务访问列表,剔除不可用的服务器。
位于数据层的服务器情况比较特殊,为了保证服务器宕机时数据不丢失,数据访问服务不中断,需要在数据写入时进行数据同步复制,将数据写入多台服务器上,实现数据冗余备份。当数据服务器宕机时,应用程序将访问切换到有备份数据的服务器上。
高可用应用层
应用层主要处理网站应用的业务逻辑,因此有时也称作业务逻辑层,用户的请求都是由这层来处理,而大多数情况下请求都是无状态的。
通过负载均衡进行失效转移
负载均衡,顾名思义,主要使用在业务量和数据量较高的情况下,当单台服务器不足以承担所有的负载压力时,通过负载均衡手段,将流量和数据分摊到一个集群组成的多台服务器上,以提高整体的负载处理能力。
当服务器集群中的服务器都可用时,负载均衡服务器会把用户的请求分发到任意一台服务器上进行处理,而当某台服务器宕机时,负载均衡服务器通过心跳检测机制发现该服务器失去响应,就会把它从服务器列表中删除,而将请求发送到其他服务器上,请求在任何一台服务器中处理都不会影响最终的结果。
集群的Session管理
不过事实上,业务总是有状态的,例如在交易类的电子商务网站,需要有购物车记录用户的购买信息。在使用负载均衡的集群环境中,由于负载均衡服务器可能会将请求分发到集群任何一台应用服务器上,所以保证每次请求依然能够获得正确的Session比单机时要复杂很多。
集群环境下,Session管理主要有以下几种手段。
Session复制
Session复制是早期应用系统使用较多的一种服务器集群Session管理机制。它的原理是在集群中的服务器之间同步Session对象,使得每台服务器上都保存所有用户的Session信息,而服务器使用Session时,只需要在本机获取即可。
这种方案虽然简单,从本机读取Session信息也很快速,但只能使用在集群规模比较小的情况下。当集群规模较大时,集群服务器间需要大量的通信进行Session复制,占用服务器和网络的大量资源,系统不堪负担。
Session绑定
Session绑定可以利用负载均衡的源地址Hash算法实现,负载均衡服务器总是将来源于同一IP的请求分发到同一台服务器上。这样在整个会话期间,用户所有的请求都在同一台服务器上处理,保证Session总能在这台服务器上获取。
但是Session绑定的方案显然不符合我们对系统高可用的需求,因为一旦某台服务器宕机,那么该机器上的Session也就不复存在了,用户请求切换到其他机器后因为没有Session而无法完成业务处理。
Session服务器
目前的主流方案是使用Session服务器。利用独立部署的Session服务器(集群)统一管理Session,应用服务器每次读写Session时,都访问Session服务器。
这种解决方案事实上是将应用服务器的状态分离,分为无状态的应用服务器和有状态的Session服务器,然后针对这两种服务器的不同特性分别设计其架构。
对于有状态的Session服务器,一种比较简单的方法是利用分布式缓存如Redis等,在这些产品的基础上进行包装,使其符合Session的存储和访问要求。
高可用服务层
服务模块为业务产品提供基础公共服务,这些服务通常都独立分布式部署,被具体应用远程调用。服务是无状态的,因此可以使用类似负载均衡的失效转移策略实现高可用。除此之外,具体实践中,还有以下几点高可用的策略。
分级管理
运维上将服务器进行分级管理,核心应用和服务优先使用更好的硬件,在运维响应速度上也有更高优先级。例如,用户及时付款购物比能不能评价商品更重要,所以订单、支付服务比评价服务有更高优先级。
同时在服务部署上也进行必要的隔离,避免故障的连锁反应。低优先级的服务通过部署在不同的容器或虚拟机上进行隔离,而高优先级的服务则需要部署在不同的物理机上,核心服务和数据甚至需要部署在不同地域的数据中心。
超时设置
由于服务端宕机、线程死锁等原因,可能导致应用程序对服务端的调用失去响应,进而导致用户请求长时间得不到响应,同时还占用应用程序的资源,不利于及时将访问请求转移到正常的服务器上。
可以在应用程序中设置服务调用的超时时间,一旦超时,通信框架就抛出异常,应用程序根据服务调度策略,可选择继续重试或将请求转移到提供相同服务的其他服务器上。
异步调用
应用对服务的调用通过消息队列等异步方式完成,避免一个服务失败导致整个应用请求失败的情况。如提交一个新用户注册请求,应用需要调用三个服务:将用户信息写入数据库,发送账户注册成功邮件,开通对应权限。如果采用同步服务调用,当邮件队列阻塞不能发送邮件时,会导致其他两个服务也无法执行,最终导致用户注册失败。
如果采用异步调用的方式,应用程序将用户注册信息发送给消息队列服务器后立即返回用户注册成功响应。而记录用户注册信息到数据库、发送用户注册成功邮件、调用用户服务开通权限这三个服务作为消息的消费者任务,分别从消息队列获取用户注册信息异步执行。即使邮件服务队列阻塞,邮件不能成功发送,也不会影响其他服务的执行,用户注册操作可顺利完成,只是晚一点收到注册成功的邮件而已。
当然不是所有服务调用都可以异步调用,对于获取用户信息这类调用,采用异步方式会延长响应时间,得不偿失。对于那些必须确认服务调用成功才能继续下一步操作的应用也不适合使用异步调用。
服务降级
在网站访问高峰期,服务可能因为大量的并发调用而性能下降,严重时可能会导致服务宕机。为了保证核心应用和功能的正常运行,需要对服务进行降级。降级有两种手段:拒绝服务及关闭服务。
拒绝服务:拒绝低优先级应用的调用,减少服务调用并发数,确保核心应用正常使用;或者随机拒绝部分请求调用,节约资源,让另一部分请求得以成功。
关闭功能:关闭部分不重要的服务,或者服务内部关闭部分不重要的功能,以节约系统开销,为重要的服务和功能让出资源。例如淘宝在每年的“双十一”促销中,在系统最繁忙的时段关闭“评价”、“确认收货”等非核心服务,以保证核心交易服务的顺利完成。
幂等性设计
应用调用服务失败后,会将调用请求重新发送到其他服务器,但是这个失败可能不是真正的失败。比如服务已经处理成功,但因为网络故障应用没有收到响应,这时应用重新提交请求就导致服务重复调用,如果这个服务是一个转账操作,就会产生严重后果。
服务重复调用是无法避免的,应用层也不需要关心服务是否真的失败,只要没有收到调用成功的响应,就可以认为调用失败,并重试服务调用。因此必须在服务层保证服务重复调用和调用一次产生的结果相同,即服务具有幂等性。
高可用数据层
不同于高可用的应用和服务,由于数据层服务器上保存的数据不同,当某台服务器宕机的时候,数据访问请求不能任意切换到集群中其他的机器上。
保证数据存储高可用的手段主要是数据备份和失效转移机制。数据备份是保证数据有多个副本,任意副本的失效都不会导致数据的永久丢失,从而实现数据完全的持久化。而失效转移机制则保证当一个数据副本不可访问时,可以快速切换访问数据的其他副本,保证系统可用。
对于数据层的“守护神”缓存服务,也需要保证简单的高可用。对于缓存服务器集群中的单机宕机,如果缓存服务器集群规模较大,那么单机宕机引起的缓存数据丢失比例和数据库负载压力变化都较小,对整个系统影响也较小。
扩大缓存服务器集群规模的一个简单手段就是所有应用共享同一个分布式缓存集群,单独的应用只需要向共享缓存集群申请缓存资源即可。并且通过逻辑或物理分区的方式将每个应用的缓存部署在多台服务器上,任何一台服务器宕机引起的缓存失效都只影响应用缓存数据的一小部分,不会对应用性能和数据库负载造成太大影响。
CAP原理
在讨论高可用数据服务架构之前,必须先讨论的一个话题是,为了保证数据的高可用,系统通常会牺牲另一个也很重要的指标:数据一致性。
高可用的数据层有如下几个层面的含义:
- 数据持久性:保证数据可持久存储,在各种情况下都不会出现数据丢失的问题。
- 数据可用性:即使存在损坏的副本,也需要保证数据是可以访问的。
- 数据一致性:数据多个副本之间内容需要保持相同。
CAP原理认为,一个提供数据服务的存储系统无法同时满足数据一致性(Consistency)、数据可用性(Availibility)、分区耐受性(Patition Tolerance,系统具有跨网络分区的伸缩性)这三个条件,如图所示。
在大型应用中,数据规模总是快速扩张的,因此可伸缩性即分区耐受性必不可少,规模变大以后,机器数量也会变得庞大,这时网络和服务器故障会频繁出现,要想保证应用可用,就必须保证数据可用性。所以在大型网站中,通常会选择强化分布式存储系统的可用性(A)和伸缩性(P),而在某种程度上放弃一致性(C)。
一般说来,数据不一致通常出现在系统高并发写操作或者集群状态不稳(故障恢复、集群扩容……)的情况下,应用系统需要对分布式数据处理系统的数据不一致性有所了解并进行某种意义上的补偿和纠错,以避免出现应用系统数据不正确。
CAP原理对于可伸缩的分布式系统设计具有重要意义。因为难以满足数据强一致性,系统通常会综合成本、技术、业务场景等条件,结合应用服务和其他的数据监控与纠错功能,使存储系统达到用户一致,保证最终用户访问数据的正确性。
数据备份
数据备份是一种古老而有效的数据保护手段,早期的数据备份手段主要是数据冷备。冷备的优点是简单和廉价,成本和技术难度都较低。缺点是不能保证数据最终一致,由于数据是定期复制,因此备份设备中的数据比系统中的数据陈旧,如果系统数据丢失,那么从上个备份点开始后更新的数据就会永久丢失。同时也不能保证数据可用性,从冷备存储中恢复数据需要较长的时间,而这段时间无法访问数据,系统也不可用。
因此,数据冷备作为一种传统的数据保护手段,依然在网站日常运维中使用,同时在网站实时在线业务中,还需要进行数据热备,以提供更好的数据可用性。数据热备可分为异步热备方式和同步热备方式。
异步方式是指多份数据副本的写入操作异步完成,应用程序正常情况下只连接主存储服务器,数据写入时,由主存储服务器的写操作代理模块将数据写入本机存储系统后立即返回写操作成功响应,然后通过异步线程将写操作数据同步到从存储服务器。
同步方式是指多份数据副本的写入操作同步完成,即应用程序收到数据服务系统的写成功响应时,多份数据都已经写操作成功。但是当应用程序收到数据写操作失败的响应时,可能有部分副本或者全部副本都已经写成功了(因为网络或者系统故障,无法返回操作成功的响应)。
延伸阅读:【分布式—要点】数据复制
失效转移
若数据服务器集群中任何一台服务器宕机,那么应用程序针对这台服务器的所有读写操作都需要重新路由到其他服务器,保证数据访问不会失败,这个过程叫作失效转移。失效转移操作由三部分组成:失效确认、访问转移、数据恢复。
判断服务器宕机是系统进行失效转移的第一步,系统确认一台服务器是否宕机的手段有两种:心跳检测和应用程序访问失败报告。对于应用程序的访问失败报告,控制中心还需要再一次发送心跳检测进行确认,以免错误判断服务器宕机。
确认某台数据存储服务器宕机后,就需要将数据读写访问重新路由到其他服务器上。对于完全对等存储的服务器(几台存储服务器存储的数据完全一样),当其中一台宕机后,应用程序根据配置直接切换到对等服务器上。如果存储是不对等的,那么就需要重新计算路由,选择存储服务器。
因为某台服务器宕机,所以数据存储的副本数目会减少,必须将副本的数目恢复到系统设定的值,否则,再有服务器宕机时,就可能出现无法访问转移(所有副本的服务器都宕机了),数据永久丢失的情况。因此系统需要从健康的服务器复制数据,将数据副本数目恢复到设定值。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。