如何基于AppActive 设计一套多数据中心应用多活方案
——邱康
AppActive 社区负责人
一、背景
系统在运行过程中总是会遇到各种各样的问题,比如硬件故障,包括磁盘损坏、内存短路、智能系统损坏等;比如软件故障,包括容量不足、健康检查失效等;比如人为故障,包括错误配置、错误发布、删库跑路等;再比如不可抗力,包括地震、火山雷电、断电断网等。
只要系统规模足够大或运营时间足够长,就一定会出现故常。因此,需要使用有效手段来应对和缓解故障。
上文提到的几个故障类型,其中硬件故障一般是小规模问题,比如单台主机失效,但如果产生级联效应,则可能会演变成大规模问题。不可抗力故障往往会引起大规模问题。
针对不同规模、不同影响面的故障,可以使用不同的手段来避免和缓解。比如主机级故障可以通过集群手段提高可用性或避免故障,无状态应用可以通过集群化部署加负载均衡来解决,有状态应用需要通过副本以及算法来解决,软件故障可以使用热点隔离、限流降级、熔断、弹性伸缩等手段,人为故障可以通过信息安全变更管控、质量保证等手段,不可抗力需要通过容灾架构来避免和缓解。与此同时,无论是小规模还是大规模问题,都需要监控和告警功能来辅助。
二、容灾架构选型
容灾架构大致可以分为以下几个类型:
① 数据备份:核心要点是数据定期备份,而应用没有备份。故障发生时只能被动等待,故障恢复后才能继续对外服务。
② 冷备:应用没有备份,但基础设施存在,需要时可手工或自动拉起应用。故障发生时,即可拉起应用对外进行服务。
③ 温备:应用备份以最小集群部署并运行,但不对外提供服务。故障发生时,备份应用只需要Scale out 即可对外服务。
④ 热备:比温备多一步,应用备份对等部署。故障发生时,备份应用可以直接对外服务。
⑤ 多活:比热备更进一步,多个站点对等部署,并同时对外提供服务。故障发生时,只需将故障站点流量切零即可。
容灾架构选型的核心在于 RPO、RTO、成本以及性能,所以需要考虑每种架构的指标综合进行架构选型。
RPO 方面:数据备份的 RPO 取决于备份周期,其余几种架构都是实时异步复制,RPO 约等于0。
RTO 方面:数据备份架构在故障发生时没有任何应对办法,因此需要小时级/天级;冷备架构从 0 拉起应用并不是容易,因此也需要小时级/天级;温备只需要做 Scale out ,可以实现小时级/分钟级;热备可以实现分钟级/小时级;多活可以实现分钟级/秒级。
资源价格方面:数据备份冗余量很低,因此资源价格较低;冷备有冗余基础设施,温备更多了冗余应用,因此资源价格略高;热备和多活有应用对等部署冗余,资源价格最高。
资源利用率方面:数据备份冗余量最低,因此资源利用率最高;冷备相对略低一些;温备和热备中,温备资源利用率略高,因为容量较低;热备资源利用率最低,因为是对等部署,但没有很好地利用;多活相较于热备略高,其资源虽然是对等部署,但有被较好地利用。
复杂度方面:数据备份和冷备都很低,温备比热备略高,因为故障发生时需要做 Scale out 操作;多活复杂度最高,因为要实现多站点同时对外服务,需要流量调度、数据冲突解决等一系列操作。
容量方面:数据备份是单机房容量,冷备、温备、热备容量都受单机房或单地域局限;多活理论上可以实现机房水平扩展,因此容量最高。
切流信心方面:数据备份没有任何操作,所以切流信心为 NaN;冷备切流信心也非常低;温备略高,虽然没有流量,但有应用一直在运行;热备切流信心更高,全量且不需要额外操作;多活切流信心最大,多个站点对外同时部署,只需要做流量调度。
我们的需求为分钟级 RTP,因此只能选择热备和多活。另外,多活架构下多个站点同时对外服务,资源利用率更高,关键时切流信心更足,而且潜在容量更大,因此最终在实际应用中选择多活架构。
多活又分为异地多活和同城活。
同城多活机房 RT较小,所以数据库一般用主备避免数据一致性问题。其应用多活,本机房优先调用,也可能存在跨机房调用,比如本机房provider 健康比例值过低,调取对面的成功概率更大。故障时只需要做机房流量切零和数据库主备切换,若数据库没问题则不需要进行主备切换。
异地多活机房 RT 较大,不宜单写,尽量走本地数据库。但由于存在多点写,需要解决数据冲突问题。其应用多活,尽量使用本机房封闭调用,但也可能存在跨机房调用,取决于具体多活方案。故障时做机房流量切零,也需要解决数据冲突问题。
以上两个架构选型的核心要点在于是否需要应对城市级故障。
三、AppActive 异地多活方案
AppActive 提供多活方案的整体思路为对业务进行类型划分,并据此对数据中心进行类型划分。
如上图,可将业务分为三类:
全局业务:一般是强一致性业务,此类业务在中心单元读;
核心业务:做单元化拆分的业务,部分特定流量在特定单元写。
共享业务:被核心业务高频依赖的全局业务读服务,在中心单元写,在普通单元读。
有了业务定义,即可看到单元定义,中心单元是需要承载全体业务的单元,其他单元即普通单元。
AppActive 的核心理念是基于隔离的冗余。
数据在多个机房之间做了实时复制,这是 RPO 约等于 0 的核心要点。上图可见,流量从终端到达网关之前是乱的,有灰色,有橙色。到网关后,对流量进行分片,比如橙色流量打到左边机房,灰色流量打到右边机房,从网关到服务再到数据库,都符合此分片规则,即特定流量一定是在特定机房内完成整个流量请求的生命周期。这样做能带来以下几点好处:
第一点,整个请求生命周期在机房内完成,业务在机房内是独立的,不依赖于另一个机房。另一个机房下线后,此机房依然能够独立对外服务;
第二点,不存在跨机房请求,请求链路缩短,性能更好,用户体验更佳。
每一层做基于隔离的冗余时,都需要依赖多活规则。多活规则是一系列定义,比如机房属于哪个单元,流量如何染色,哪些流量属于哪些单元,以及服务类型定义、数据库定义等。多活规则通过多活Channel 下发到每个机房的应用。
请求进入机房后,第一跳是网关,当前网关支持 Nginx 和 Tengine。其改造要点有三:
①网关引入 AppActive 插件,并进行多单元部署。
②同一业务在不同单元的地址放入不同 Upstream 中,比如一般会将应用放在 Upstream 里。但由于是多机房部署,所以要做区分,流量才可打到不同机房。
③向网关推送多活规则。
改造后的效果如下:
日常态:不同标记或分片的流量分流到不同单元。
故障态:只需将切零多活规则推送给网关,网关即可将所有流量打入非故障单元,实现 failover 效果。
当前微服务支持 Dubbo 和 Spring Cloud 。
微服务改造要点有四:
①引入 AppActive 应用 SDK ,并对应用进行多单元部署。
②对各类型服务进行打标,分为中心服务、普通服务和单元服务,分别对应前文的全局业务、共享业务和核心业务。不同框架的打标方式不同,具体取决于微服务框架。
③仅当存在跨单元调用时,单元间进行服务同步,比如全级业务可能会存在跨单元调用。
④向应用推送多活规则。
改造后效果如下:
日常态:不同分片流量按照多活规则分流到不同单元。如果没有规则,则认为普通服务,按照本单元优先规则发起调用。
故障态:将切零多活规则推送给应用,Consumer 接收到流量后将请求全部打到非故障单元 Provider ,实现 failover 效果。
数据层当前支持 MySQL 。
核心改造要点有四:
①引用 AppActive应用 SDK 及其Driver ,然后将应用进行多单元部署。
②将不同类型数据库进行打标,分为普通数据库和单元数据库。
③在单元间进行数据同步。
④向应用推送多活规则。
改造后效果如下:
日常态:单元数据库接受多活规则中属于本单元的流量写请求,普通数据库接受所有请求。
故障态:切流过程中,因为数据可能存在同步延迟,如果直接将流量切过去,可能造成双写,产生脏数据。因此切流过程中要禁止数据库的读写,直到数据同步追平后才放开,避免脏数据。
方案实施后可以获得以下三个方面收益:
第一,容灾。方案可应对多种故障场景,比如公网网络故障、机房内部网关故障、业务应用、中间件故障、多个机房之间网络故障甚至机房整体故障。对于故障可实现分钟级 RTO ,业务恢复时间和具体故障恢复时间解耦。比如 AB 两个机房同时对外服务,B 机房挂了,此时将流量切走业务即可恢复,而机房可能还未恢复。
第二,容量,基于多活路由策略,机房之间不存在混乱的依赖关系,因而机房伸缩更简单,能够解决单机房容量不足的问题,比如机器数量、带宽容量和连接数。
第三,创新试验田。基于综合路由规则,可以实现完整的灰度策略。从网关到服务接口再到最后的数据库库表结构都可做灰度。其次,爆炸半径可控,因为始终只影响单元机房服务的一部分用户,可以实施完整的故障演练。此外,对于某些重点业务,可以使用独立机房承载,实现业务重保。
未来,我们期望AppActive 对市面上主流框架都进行支持,主要将从网关、应用和数据三个方面进行。网关方面包括 Nginx、Kong、Tengine;应用层包括 Spring Cloud 、Dubbo、Sofa,还有消息、数据,SDK、Agent 以及Mesh形态的支持都在规划范围内;数据方面,主要包括数据同步和注册中心同步。