软件系统高可用架构思考

近期在重新评估我们系统的高可用性和弹性扩展能力,因此今天再整理下软件系统高可用架构方面的内容。重点还是对里面的一些关键点展开说明。

对于高可用整体概述,我在前面专门一篇文章写过,先做个说明:

高可用性整体概述

对于业务系统的高可用性,实际上包括了高可靠,高性能和高扩展三个方面的内容。而且三方面相互之间还存在相互的依赖和影响关系。

对于三者的关系,我们可以用下图进行描述。

上图可以看到高可靠性,高性能和高扩展性三者之间的关系。

  • 对于高可靠性来说,传统的HA架构,冗余设计都可以满足高可靠性要求,但是并不代表系统具备了高可靠性能和可扩展性能力。反过来说,当系统具备了高扩展性的时候,一般我们在设计扩展性的时候都会考虑到同时兼顾冗余和高可靠,比如我们常说的集群技术。
  • 对于高性能和高扩展性两点来说,高扩展性是高性能的必要条件,但是并不是充分条件。一个业务系统的高性能不是简单的具备扩展能力就可以,而是需要业务系统本身软件架构设计,代码编写各方面都满足高性能设计要求。
  • 对于高可靠和高性能,两者反而表现出来一种相互制约的关系,即在高性能支撑的状态下,往往是对系统的高可靠性形成严峻挑战,也正是这个原因我们会看到类似限流熔断,SLA服务降级等各种措施来控制异常状态下的大并发访问和调用。推荐:高性能、高可用平台架构的演变过程

早期的软件系统高可用

软件基础架构早期的高可靠性更多是围绕高可靠性展开的。

简单来说就是一个软件系统的部署应该采用HA或集群部署,整个IT基础设施架构里面不应该有任何的单点故障。常见的早期IT部署方式一般为:

所以你会看到整个高可用实现起来并不复杂,应用中间件可以实现负载均衡集群具备扩展性,数据库往往会成为瓶颈。所以数据库你也可以采用集群部署,类似Oracle RAC集群。通过数据库集群来实现数据库层面的扩展能力。

共享存储

不论是HA架构,还是数据库集群,都可以看到类似SAN共享存储是关键。也就是说必须要有共享存储才能够实现HA架构或者集群架构。在新的分布式架构下可以看到新的分布式架构会实现数据库本身也是分布式的,多副本存储,可以直接采用本地磁盘。

应用服务器集群

一个集群,如果本身是无状态的,那么就很容易上层增加负载均衡设备来实现负载均衡。一个软件系统中间件集群,常说的状态即Session保持。

为了更好地解决集群节点本身无状态的话,可以看到Session保持本身是从集群节点移出的。要不是在客户端进行Session保存,要不就是下移到数据库或Redis库来保存Session会话信息。其目的都是让集群节点本身无状态化。

高可靠 - 集群和可扩展

前面已经看到,如果仅仅是高可靠性保障, 实际上是比较简单的事情。整个IT基础架构的复杂性实际上是为了高性能和可扩展,引入了集群和分布式架构导致。

对于集群和分布式实际两个概念经常在混淆使用。

在这里强调下分布式实际更多会谈数据本身的分布式存储问题,这个分布式存储是和前面集中化共享存储最大的一个差异点。即数据需要存储在多个分布式节点,可以是每个节点都存储全量(读写分离集群),也可以是每个节点都只存储部分数据,并采用多副本机制保障数据的高可靠性。

对于集群更多会在大量请求过来进行请求分发的时候使用,即集群节点本身也是分布式的,但是针对的是多个请求的均衡,一般不涉及状态问题,同时也不会再对单个完整请求进行拆分处理。

CP优先还是AP优先

一个分布式架构一定会涉及到CAP定律。原因重点还是引入了状态保持和数据的持久化存储问题,这个本身就引入了一致性问题需要解决。

对于CP来说一致性优先,那么数据必须多节点复制同步成功请求才能够成功,那么自然就牺牲了高可用性,也就是说一个请求本身可能由于底层多节点数据同步问题,导致请求超时。而对于AP来说或高可用性优化,那么就容易引入类似脏读等问题,导致数据不一致性。

分布式架构的实现往往就在两者之间进行权衡。比如Zookeeper采用CP一致性优先,而对于微服务注册中心Eureka则采用AP高可用优先原则。

当应用中间件集群无状态化后,实际问题就变成了如何解决数据库,缓存库,服务注册和配置中心本身的分布式架构和集群扩展问题。

中心化还是去中心化

在微服务架构下,我们会更多地思考中心化和去中心化的问题。

类似服务注册中心Eureka则是一个去中心化的架构模式,其控制流和数据流是分离的,即数据流并不会经过注册中心进行路由分发和中转。当然注册中心你本身也要集群化,类似Eureka可以进行多节点集群部署,并且实现多个节点之间注册信息和配置信息的状态同步。

而对于中心化情况下,往往就有一个中心化的控制节点来管理多节点之间的状态和数据同步,即这些数据同步不是节点之间相互复制完成的,而是由控制节点来管理的。

对应到Dubbo注册中心来看,其集群中各个节点之间的配置信息和状态同步则是通过Zookeeper来配合完成的。也就是在一个分布式架构下,启用一个中心化控制节点来完成一致性协调和事务管理等问题。

数据库-主从,双主,读写分离

对于数据库本身,首先解决高可用性问题,其次解决性能扩展问题。

对于高可用在前面谈到如果存在集中存储模式实际上简单采用HA架构就可以解决。那么在采用本次盘进行存储的时候就一定涉及到数据库同步复制。

数据库基于日志的同步复制是一个基础能力。

类似Mysql的双主数据库配置,读写分离集群配置等都需要采用到读写分离方式实现。这个时候实际上每个节点都存储的全量数据信息。

主从配置和一对多配置

对于Mysql数据库你可以采用Dual Master架构解决高可用问题。当然可以可以是双Master架构+多个读节点实现读写分离来解决数据库性能和扩展问题。

在数据库读取场景占主要业务场景的时候,这种方法本身可行。实际在实现的时候一般需要在Mysql上架构一个DaaS数据库中间件来实现SQL解析,路由等关键能力。

数据库Cluster集群

对于Mysql数据库本身也有Cluster集群,但是当前应用场景并不多见,其本身通过Cluster来扩展的性能提升也不明显。

RAC集群机制的简化

一个分布式数据库集群,可以看到最难的就是数据一致性保障,如果多个节点都能够同时读写,那么这个事务一致性保障是相对难实现的。类似Oracle RAC集群就采用的这个机制。而当前阿里的PolarDB数据库集群实际对这个进行了简化,即仍然是采用共享存储(这个共享存储是分布式节点进行整合后的共享存储能力,类似Ceph实现等),但是多节点配置下,仅仅一个节点写,其它节点仅仅是读节点。这个可以参考下PolarDB的一些文档说明。

数据库拆分

数据库层面性能扩展另外一个方法就是数据库拆分,既可以是水平拆分,也可以是垂直拆分。而对于垂直拆分一般就是和当前的微服务架构规划设计放在一起,不同的微服务可以独立独立的数据库完成拆分工作。

数据库拆分应该对上层应用访问透明,因此需要在切片完成的数据库节点上面架构一个分布式数据库访问中间件,一般我们叫DaaS数据库即服务中间件。比如Cobar,MyCat等各种开源实现等。

在微服务架构演进下,实际可以看到DaaS反而用得越来越少,其核心原因就是进来减少了跨库的一些关联查询和聚合等SQL操作,而是将类似操作上移到应用层去解决。

负载均衡和分布式集群

对于负载均衡来说实际不能算一个分布式集群,仅仅是做请求的路由分发工作。当谈到分布式集群的时候一般就会谈到两个点。

其一是状态和配置信息在集群节点的实时同步,其二就是集群节点的心跳检查,当节点出现问题的时候要实时从集群列表中去除掉直到恢复。

当前构建分布式集群比较常用的如ZookeeperEtcd等,Dubbo分布式集群采用了Zookeeper,而对于Kurbernetes集群则采用Etcd来构建分布式集群管控。但是不论哪种开源实现,类似分布式锁,数据一致性保证,软负载均衡,心跳检查等都是最核心的基础能力。

心跳检查KeepAlive

在前面谈Mysql双主模式的时候,实际本质仍然还是主从模式。其关键就是需要实时心跳检查主节点当前状态,当心跳检查出现问题的时候需要能够及时地将从节点切换为主节点。这个过程需要自动切换和完成,以提升整体高可用性。

Redis主从到哨兵机制

一个高可用的Redis集群一般会涉及到6个节点,即三个哨兵节点,三个主从节点。Redis 官方的高可用解决方案

简单的主从架构下虽然可以实现高可用,但是无法实现在监测到主节点出现问题后自动切换到从节点,也正是这个原因引入了sentinel节点。也就是说sentinel节点做的是类似KeepAlive心跳检查的事情。

sentinel节点自身也需要高可用,因此这里至少就需要两个节点来确保sentinel节点本身的高可用性。那么为何要引入三节点?

可以看到当前主流的分布式架构集群中,管理节点往往都引入3节点模式。

即当两个节点的时候,容易出现一种情况:

  • sentinel-A节点监测到master当前可用
  • sentinel-B节点监测到master当前可用

那么这个时候就出现了矛盾,不清楚听谁的。因此需要引入更多的一个节点来进行投票,具体是否主从切换听票数多的。

对于高可用集群的搭建思路,在这里还是需要重新进行下总结和梳理。

首先在前面强调了一个点,即集群节点本身不要存在大量的本地数据或文件存储,如果存在那么就需要考虑两个思路来解决。其一是挂接集中存储或共享存储,其二是需要有一个机制来实施实时或准实时的数据或文件同步复制。

其次,对于集群搭建是否需要统一的出口IP,比如一个浮动VIP地址。实际这里是可以两种做法,一个是增加一个软负载均衡类似HaProxy来提供统一的VIP地址,其次就是不提供VIP地址,那么在服务提供端或消费端需要配置一个IP地址串。

集群节点本身也包括两种类型。

一种是仅仅为了高可靠性,一种是要进行实际的大流量负载分发。第一种情况往往存在通过心跳检查来进行主从切换的问题;而第二种情况往往还需要搭配软负载均衡能力,即管理端对于注册进入的节点,一方面可以进行负载均衡,一方面又可以通过心跳检查动态增删节点。类似k8s的分布式集群,自然是需要具备以上两个方面的能力。

如果你还是采用传统的负载均衡方式来实现集群,如果集群节点存在类似配置文件等有状态信息的下发你无法很好地完成,其次就是集群节点持续故障的时候很难做到的自动化的管理能力,比如出现问题后的自动卸载,恢复后的自动挂接等。

即使你使用硬件负载均衡来做大并发请求的路由分发,你仍然需要一个分布式集群的管理组件来实现集群节点的动态管理。比如我们在采用Weblogic的时候,对于整个集群仍然采用Weblogic Cluster来进行管理,包括节点检测,服务的部署等。但是对于所有节点又统一配置到硬件负载均衡设备上来提升负载均衡本身的性能。

注:以上内容有部分没有经过自己实践验证,因此内容有差错可反馈指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章