过去6年,达达集团秉承“万千好物 即时可得”的初心和愿景,不断迭代和升级技术能力,持续提升履约效率和服务体验。为保障系统持续稳定和业务不间断地高效运行, 我们在数据库高可用架构升级、数据库垂直/水平拆分、 微服务治理及可观测性、容量弹性和多活容灾等方面进行了不断实践并取得一定成果。
本文主要分享达达在双云双活容灾能力建议方面的实践和经验。
首先,介绍一下高可用(High Availability)和容灾(Disaster Recovery),两者相互联系、相互补充,但也有明显区别:
由此,我们可以看出,高可用往往是指本地的高可用系统或架构,表示在任一服务器出现故障时,应用程序或系统能迅速切换到其他服务器上运行的能力;而容灾是指异地(同城或者异地)的冷备/热备/双活系统,表示在大规模集群或云级别灾难发生时,数据、应用和业务在灾备数据中心的恢复能力。容灾通常可以从网络接入、应用治理、主机、数据存储等层面去实施,业界如大型银行的“两地三中心”同城双活+异地灾备、蚂蚁金服的“三地五中心”异地多活、饿了么的北京上海双机房“异地双活”都是典型的容灾架构方案。
从支付宝527大规模宕机事故、携程528数据库全线崩溃、AWS北京光缆被挖断、腾讯云硬盘故障、谷歌云K8s服务(GKE)宕机19小时不可用、微盟删库事件,再到近期的华为云香港机房因制冷设备故障导致整个机房崩溃,无论是天灾,还是人祸,居安思危并建立容灾能力对一个企业的重要性是不言而喻的。
达达在2017-2018年饱受网络故障之苦,如云网关组件故障、NAT网关故障、单运营商线路网络连接故障等,这些问题往往让我们束手无策。为规避单云灾难级风险,我们在调研并比较业界容灾方案后,最终选择双云架构做同城双活的探索。
双活一期主要是围绕服务双云部署、业务分流和接口功能/性能等方面的探索验证。
双云双活一期方案主要有以下几个方面:
在双云双活一期中,双云共用原有生产Consul集群,J云的服务节点处于单独拉取的链路而非base基础链路,确保部署在J云的核心服务间调用在J云内部闭环。
在双云双活一期架构中,J云侧核心服务的订运单主流程功能验证通过,但也遇到棘手问题。
由于只有部分核心服务部署在J云,其依赖的Redis、DB、队列和其他服务等仍需要跨云读写访问,跨云专线的3-4ms时延在多次跨机房请求下将延迟问题彻底放大,例如U云侧一个发单接口响应时间约在200ms,而在J云侧需要500ms+,这个响应时间对业务而言是无法接受的。
跨云专线的网络波动和3-4ms时延,这会造成跨云使用LAN Gossip协议通信的同一个Consul集群发生紊乱情况。我们曾遇到过J云侧Consul节点将U云侧正常节点投票下线 继而影响U云生产集群的问题,也遇到过这种紊乱情况下,J云的节点会疯狂地消息广播投票确认并导致专线带宽急剧上升。基础架构团队针对这些问题专门优化了Consul Gossip协议以降低对网络延迟的敏感度。
双云双活一期的流量分发方案可指定到域名+按百分比分发流量+默认负载均衡轮训后端,这样虽然可以灰度验证业务功能,但开启双活流量城市的骑士前后两次请求如果流向不同云,接口响应时延差别较大,相应体验上会有较大差异。
实际结果证明,按以上所描述的一期方案来实施的双云双活,没有办法达到预期结果,特别是比较大地影响了用户体验,更无法支持诸如抢单这类实时性较高的场景。达达的双活一期最终也以失败告终。
针对同城双活一期遇到的跨机房调用时延问题、跨云网络波动可能引发Consul集群紊乱,以及业务流量精准分发一致性体验等问题,我们进行了深度思考,形成了服务间交互单云内内敛、数据库双云双向复制、流量总控精细化配置三大核心点,并且结合业务场景依据数据访问频次、时延要求和数据一致性要求等维度,我们对数据和关联服务进行了梳理和RCG模型分级。
此外,我们还在双云统一配置中心、服务一致性部署和发布、系统可观测性、工具系统主备、容量规划和成本控制方面做了相应功能迭代和能力建设。
双云双活二期的架构图如下所示
双活一期遇到的跨机房调用时延问题及跨云网络波动可能引发Consul集群紊乱,这让我们更清楚地认识到服务间请求单云内内敛的重要性,对 Consul LAN Gossip与WAN Gossip协议适用不同场景的理解。
因此,双活二期,我们采用了Consul多数据中心方案,官方示意图如下:
每个云有各自的Consul Server集群,consul client默认以LAN Gossip协议join到所在云的Consul Server,不同云之间Consul Server通过WAN Gossip协议join到一起。在达达内部,每个服务会默认携带一个Sidecar并join到所在云的Consul集群, Mysql和Redis也同样以consul client方式join到所在云的Consul集群,这样通过Consul多DC架构和Consul服务发现,我们实现了服务间交互、服务与绝大多数数据源间交互在单云内内敛,也尽可能规避了一期遇到的问题。
为实现RZone模型的DB本地读写,且在数据库水平项目没有大规模开展的情况下,我们调整了双云两侧数据库的自增步长为2,即auto_increment_increment=2,主键也做奇偶数区分,即U云侧主键是奇数,J云侧主键是偶数。
为实现双A数据库双云双向稳定同步,我们采用了阿里开源的分布式数据库同步系统Otter,其架构图如下:
生产环境中,我们通过Otter不同的Channel管理不同双A数据库的双向同步
如下是生产环境Otter同步列表的TOPN
目前,数据库双向复制时延平均0.9s,最大时延为2.2s(瞬间)
我们利用OpenResty根据请求头/体中/CityId/TransporterID/ShopID及域名+URI以精准分流。
如下图,相比一期我们可以做到,针对pop.imdada.cn的某两个具体的和订单相关的URI,对城市ID 313和146 流量分发到J云,其余城市或pop其他接口默认分发到U云(默认主IDC)。
同时,我们也做到骑士ID对齐城市ID,即如果某个骑士属于这个城市,而且这个城市针对该骑士对应的业务也开启了双活流量,那么该骑士的每次请求都会走到J云。
参考业务双活解决方案,并结合业务场景依据数据访问频次、时延要求和数据一致性要求等纬度,我们对数据和关联服务进行了梳理和RCG模型分级,如下
主要有以下几个方面的工具系统改造支持并适配双活
通常建立双活会使云资源成本接近等量的增加,我们也面临同样的困难,如何做好成本控制,我们的答案是从容器规划和弹性扩缩容方面下功夫。
在业务流量总量一定的情况下,流量在双云间调配,意味了双云无状态服务的负载也在随之变化。鉴于此,我们基于K8s HPA算法自研了Auto Scaling自动扩缩容系统支持双活架构下的容量弹性,通过实时收集业务系统的多种metrics指标,实现了双云依据各自业务负载实时调节所需资源。
这样,我们在保障业务系统双云稳定性的同时,又做到了成本有效节约。
目前落地配业务已稳定运行在双云之上,并且达达也具备了以城市为粒度任意在指定云间切换业务处理量的能力。不仅具有了抗IDC级别故障的能力,也达到了按业务和地域灵活灰度切换的预期。
未来需要在业务入层增加更多的Sharding Key(城市ID/骑士ID/商家ID/订运单ID等),引入API Router以便于其他业务更好地在双活架构下流量分发到准确的云或机房;兜底Job改造为Pulsar延迟消息并在各个云内执行,以避免因数据库双向同步时延且Job单边运行造成业务上数据的错乱;业务监控特别是单量的监控水位,需要能及时对齐流量切换比例;账户服务目前是默认在U云的全局服务,拟采用TiDB方案以适配双活架构;最后,双活需要对齐数据库水平拆分,流量切换从CityID维度变化为ShardingID维度便于流量调配和管理。
回顾双云双活两期,我们希望尽可能借助架构和运维的方式来解决同城双活中遇到的问题,尽量对业务透明,减少业务改造成本,同时以落地配业务作为同城双云双活架构的业务试点,以减少全局风险。同时,我们希望积累相关经验,为后续开展单元化和多云多活打好基础。双云双活的建设是一项复杂的系统工程,需要有点、线、面、体的维度思考和前瞻规划。在这里特别感谢云平台各团队、落地配研发团队、物流平台团队)、落地配运营团队对双活项目的大力支持。
领取专属 10元无门槛券
私享最新 技术干货