在前段时间,作业帮基础架构负责人董晓聪在 ArchSummit 架构师峰会上介绍了多云多活架构探索话题,引起了现场观众的热议,大家对作业帮多云架构方案选型、技术体系各层建设很感兴趣,现场听众和董晓聪积极互动交流。
以下是演讲实录,介绍作业帮为什么要进行多云架构探索,多云架构模式的选择,以及架构的各个层次建设实践经验。
作业帮成立于 2015 年,是一家致力于用科技手段助力普惠教育的公司。公司主要大的业务板块可以分成两块,一块是作业帮 App,是一款面向于 K12 的学习辅助工具平台,是一款典型的流量互联网的产品。另一块是作业帮直播课,典型的产业互联网的产品,涵盖了教育的诸多链条,如教研、教务、教学、辅导等。除此之外,公司在智能硬件等一些其他方面也有一些积极的探索和布局。
了解完作业帮业务特点,我们再来看作业帮的技术现状。作业帮的技术状况可以归纳为两点,规模化和复杂化。规模化是指作业帮的线上服务数量比较多,有数千个。这么多的服务又对应数万的服务实例,这么多的服务实例是跑在数十万的计算核心之上,整体的规模相对是比较大。
复杂化这块是指作业帮的技术栈比较的多元。在虚机架构时代,在线业务以 PHP 为主要的语言,通过云原生改造,开始以 Golang 为主要的开发语言。但是除了这两门语言,像 Python、NodeJS、Java、C++以及 Lua 等语言在一些场景里面也有广泛的分布,整体的技术栈特别的多元。
作业帮从创立之初就 base 在云之上,也充分享受了云计算的红利。但是随着业务的发展,我们慢慢遇到了单云架构的瓶颈,它主要集中在稳定性和成本这两方面。先来讲一下稳定性,这么多年随着国内云厂商技术的不断地发展,其稳定性可以达到很高的水平,但仍会出现一些零星的故障,这些故障对企业的经营会造成一定的影响,而作业帮对稳定性要求是比较高的,在我看来甚至可以用苛刻来形容。我之前在传统的互联网以及互联网金融行业都有待过,在我看来作业帮对稳定性的要求是最高的。
为什么会这样?我总结如下的原因,就是我们原来在传统的互联网,虽然一直在强调用户体验至上,但我们实际上离用户是比较远的,用户在我们眼里更多还是 UV、PV 这样的数字。而在线教育不一样,我们的辅导老师通过实时音视频的技术和用户是面对面的在一起,用户的任何问题可以更直接真切地反馈到我们这边来。再有教育是对连贯性要求比较高的场景,我们的服务时间又聚焦在每天的一两个小时里面,任意分钟级别的故障都可能会对学生的学业造成巨大的影响,所以我们对稳定性的要求只能更高,单机群多实例、单云多可用区远远无法满足我们对稳定性的追求。
再来讲一下成本这个方面,云服务成本在各大互联网公司里面也是居于成本支出的 top。尤其是近几年,这个问题就会更加凸显出来。相信不少管理者,大家在近半年到一年里面都会面临的这样选择,你到底是去优化服务器还是去缩减人头。相信大家的选择更多还是想通过用技术的方案去进行降本,而在云服务这里,企业想持续的享受到物美价廉的服务,就需要有两家及以上的供应商。基于以上这些原因,所以作业帮开始探索多云架构。
那么什么是多云架构?我们可以这样来定义,如果一家企业它使用了两家及以上的 IaaS 或 PaaS 的供应商,我们就可以称它的架构为多云架构。广义来看,混合云也是属于多云的范畴。多云架构有什么优势?除了我们前面讲到的稳定性和成本优势外,还有数据主权、特殊服务访问的优势。
数据主权就是企业为了保护不同用户群体的数据安全而做的多云选择,后面也会有详细示例的讲解。然后再就是特殊服务访问,这个比较好理解,每个云上都会有一些比较优势的服务,比如像阿里云的 Hologres,在大数据实时计算这里就是一款有竞争力的一款产品。以上就是多云的一些优势,那么多云的它的构建的模式是单一的吗?是固定的吗?我们通过跟多家云厂商、企业的交流,发现多云的模式可以定义为如下几种。
第一种的话就是主备模式,我们能看到左侧这边是互联网的通用架构。用户的流量通过 DNS 的调度,到达云机房的网络接入层,再路由到对应的服务。再经过一系列微服务的调用,最终会落到对数据存储的请求。选择主备模式,就是企业将数据库备份以及对象存储的归档,开始存储到另外一家云上,可能还会有一些基于此的衍生计算。选择主备模式最直接的好处就是,当原有的云机房出现了不可恢复的故障的时候,企业不至于血本无归,至少数据是可以恢复的。
第二个是弹性模式,这个模式是企业往前又更进了一步,不光是把一些数据存储放到另外一家云上,也开始把一些核心服务部署在另外一家云上。在这种模式下,通过 DNS 流量调度就可实现流量的调度。主要的应用场景是什么呢?互联网业务都有明显的波峰跟波谷,波峰的资源使用量可能是波谷的一倍、两倍、数倍,甚至是几个数量级的差异。而企业一直在为波峰买单,并不划算。这个时候有一家新的云厂商愿意以比较合适的价格来去承担部分弹性的流量。比如像峰值 30% 的容量,这样原机房只需要去维持 70% 的容量,整体的资源利用率就可以得到极大的提升。再有就是通过弹性云可以承担一部分非预期的流量,更好地为业务保驾护航。
再有就是业务切分的模式,大多数公司会有统一的部门来去承接基础设施,但是有些公司因为经营考虑,使用了事业部或者是子公司的模式。在这种模式下,子公司又会因为商务策略的考虑,去选择不同的云厂商。不同业务使用的是不同域名,通过 DNS 调度就可以将其路由到不同的云机房,以此实现流量的分发。在这种模式下,虽然企业应用了多云,但是之前期望的稳定性的收益就相对较少了。在这种模式下,不同云上的服务跟数据是不一样的,只有把所有云上的数据跟服务集中在一起才是完整的一份。
下面讲一下数据主权模式,前面讲了它的定义,现在再来举下具体的例子。相信大家都或多或少接触过一些出海的业务。当这些出海业务做得比较大之后,就会受到当地的政府的数据合规的一些要求,比如像欧盟、美国,它都会要求企业必须把用户的核心数据存储在本国,这样的话就会导致数据出现了分区,更有甚者对企业所使用的云厂商也有一定要求,以此形成了数据主权的多云。在一些私有化交付的项目里面,也会出现一些类似的情景。在数据主权多云模式下,每个云上的服务是一模一样的,表结构也都是一样的,但数据是有不同的,只有所有云上的数据组合起来才是企业完整的数据。
最后讲一下多活模式,通过 DNS 的流量分配,将不同比例的流量分配到不同的云机房。在每云机房里面,实现所有服务的对等部署以及流量的完整的闭环。当某个云出现故障的时候,企业只需要通过 DNS 把用户流量调度走即可。
多活模式是稳定性跟成本最理想的方案,那企业应该在所有的场景下都去选择这种方案吗?其实并不是,像多活这个模式,其实是有技术挑战的,它的技术挑战主要集中在稳定性、成本和效率。说到这里大家也可能比较奇怪,刚才我们提到了多活模式是稳定性跟成本的最优选择,为什么它会又会有稳定性跟成本的问题呢?首先我们要明确一个原则,就是复杂性不会平白无故的消失,而只是被转移了。
多活架构能够带来这么多的好处,在于它对架构本身的要求特别高,单云的等量部署以及服务闭环还是很难实现的事情。如果个企业只有几十个服务或者小几百个服务的话,通过人工的方式还是可以达成的。如果企业的服务数量比较多,大几百个,上几千个,落地的难度就会很大。大家可以想象一下,在几千个服务的情况下,核心链路就会涉及到几十、上百个的服务,而在这些服务当中只要有任意服务,只做了单云部署而没有做多云部署,那么就会导致多云架构的稳定性可能还不如单云架构。最坏情况下整体的故障率不是每个云故障率的乘积,而是每个云的故障率的之和。再有就是多云之间架设的网络,肯定没有云厂商 region 与 region 之间的网络质量更高,所以数据脑裂的可能性也会是加剧。
正是由于稳定性达不到很高的标准,所以业务方就只能去加大冗余。在原来单云架构下,服务只需要部署 100%的容量。在采用多云架构后,每个云应该有 50%或者 60%的容量,但是因为稳定性做不到,所以业务就会在每个云上加大冗余,如部署 80% 的容量。这样整体的资源使用量就会较之前多出不少,造成成本的浪费。
效率方面,多活模式就是要把不同云的管控面拉齐。虽然云厂商的提供的 IaaS 能力看上去一样,如 LB、Nat、VPC、EIP 等等,但实际上还是有功能差异的。为了实现相同效果,可能一个云上只需要一款产品即可,而另外云需要两个产品结合才能去实现类似的效果。多云管控平台就要对上游屏蔽这种差异。为了实现不同云服务的等量部署,完整闭环,很多特化服务就不再能使用了。再有就是商务谈判和云服务运维也会随着云厂商的增加而同比增加。
虽然有这些困难,但作业帮还是坚定的选择走多活多云的路线。我们整体的架构全貌可以归纳为以下。大的架构层次可以分为应用层和资源层。
资源层的话包含计算、存储、网络。以 Docker + K8s 为代表的容器技术,通过容器镜像、作业编排、作业调度、资源管理,实现底层资源对上层应用的透明。上层的应用层又可以分成基础组件和业务应用。基础组件包括各种数据存储、网关、消息队列、大数据、安全等组件。上层的业务应用想要跑得更快,还需要一层服务治理的体系,整体的服务治理体系以服务的注册发现为基础,包含服务通信、服务观测以及流量管控。在作业帮的多云架构里面,每一层次每一实体都会有涉及,今天只选取一些相对比较重点的,跟大家一起分享,它们分别是资源层的网络以及基础组件中的数据存储,还有东西向流量治理。
网络是多云互联互通的基础。作业帮早期也走了一些弯路,最终我们选择了多云组网的方案。链路层面有多方面冗余。我们在不同方位接入两家专线供应商。一边是在亦庄方位接入,而另一边是在顺义方位连通。在这两条链路上,我们通过 BGP+ECMP 实现了链路的负载均衡,以及当单条线路出现故障的时候,可以实现秒级别的自动切换。在这样的网络架构中只有专线供应商和云厂商的网络设备,我们缺乏感知和管控的能力。所以我们在专线供应商的接入处租用了 CPE 设备,实现更好的感知和管控。这个 CPE 设备在云故障演练、跨云流量排查等方面发挥的重要作用。
提到数据存储,就不能不说经典的 CAP 理论。讲的是在分布式系统中一致性、可用性和分区容错这些能力不能同时具备。要么不接收分区容错,退化为单机系统,选择 CA。要么,追求强一致性,选择 CP。要么保证服务可用,选择 AP。那么在企业具体业务场景中我们是应该进行怎样的选择呢。
结合 MySQL 的经典主从架构来介绍一下,像 Redis ES 也是是类似的方案。业务应用不是直接去访问数据存储的 cluster 节点,而是通过数据存储的 Proxy 中间件去进行访问。通过数据存储的 Proxy 有如下优势?可以对上游屏蔽底下的细节,提升了易用性、扩展性以及稳定性。在数据存储的中间件中有较为丰富的路由策略,对于写流量,都是路由到主库。对于读请求,会根据底下从节点的负载情况、主从延时情况进行流量的分发。当主从延时超过一定程度的时候,会把这个从节点从 proxy 中摘除。除了上述数据链路中的保证外,还会有 HA 的一套方案去检测主节点,以实现故障时的自动切换。
在这样相同的架构模式下,也会因为业务的不同选择而呈现出不同的 CAP 的选型。对于交易的核心链路,它对一致性要求比较高,很多读请求不能接受延时,所以业务上进行强制读主,保证一致性和可用性。在这种情况下,事实上已经退化成主备的模式,也就是 CA 的模式。而大多数业务都要追求可用性,选择 AP 的模式,以作业帮 APP 的批改场景为例,有两块核心的数据,一块是用户批改的历史记录,另一块是题库的数据。用户的批改记录在客户端上有一定的缓存。而题库数据是通过生产工艺生产出来的,本身就不是那么的实时。所以这样的业务场景中,如果主库出现了故障,或者是主从间出现了同步延时,在一两个小时的况下,从库完全不需要摘除,照样可以给业务给用户提供较稳定的服务。
上面讲的这些选型更多还是在系统的故障时候的自动选择,在真正出现故障的时候,我们还会通过人工介入去缩短故障影响时间。当从库出现问题的情况,将流量调度到主库所在的云上。而当主库所在的云出现故障的话,先将从库进行提主,然后再进行流量的切换,虽然可能会带来一部分用户数据的不一致,但可以为绝大多数用户提供正常服务。
再来讲一下单元化的架构,整体的架构和上面提到的类似,不一样点是在这单元里面,读写请求都是闭环的,不会去跨单元请求。如果只是这样,每个单元就只有自己的数据了。再通过 DTS 就可以把其他单元的差量数据同步过来,这样每个单元就具备全量的数据。多数公司在做单元化的时候,会优先选择 Passport 这样的业务。因为 Passport 有这么几点好处:
一、它是所有用户产品业务的基础,其他业务想要去做单元化都会对 Passport 有依赖。
二、Passport 天然可按照用户 ID 进行切分。
三、Passport 的提交并发量比较低,不管是用户登陆还是信息修改都不是高频操作。
所以哪怕按照地域去进行单元化问题也不大,也不会产生冲突。而作业帮选择的场景不同,我们选择了直播课课堂和运维平台两个场景。直播课堂是天然按照业务单元进行切分的。在单个课堂内,师生之间是需要做强互动,但在不同课堂间不需要有在线的交互,只需要有离线的大数据统一的汇总分析即可。
再有一块就是运维平台,我们通过单元化来提升整体的稳定性。当我们出现单云故障的时候,我们要通过 DNS 或者自研 DoH 去调度流量调度 。由于域名众多,我们使用自建的预案平台进行操作。预案平台除了和云厂商 API 交互外,还有自身的权威数据。如果这个数据存储选择了主从的架构,当真正出现故障的时候,故障止损还要先依赖于 DBA 进行预案平台的主从切换,然后才能够去执行预案,这样就就串行依赖了,故障恢复的时间就会被大大的拉长。所以在这块我们通过单元化的方案,每一边都是可以进行预案操作的,大大缩短了故障的影响时间。
最后介绍下东西向流量治理,这块也是最复杂的,多数公司的技术选型也是从这里开始出现差异的。作业帮在虚机架构的时候就开始探索多云架构,将核心服务部署到另一家云厂商上。但存在较多问题,如服务很难做到对等的部署,虚机的部署成本较高,维护成本,如调整容量等成本也较高。所以运维和研发较难维持下去。再者,有部分服务只能单例部署。服务无法做到对等部署后,流量自然做不到单云闭环。除了部署的问题外,以下问题也是阻碍流量闭环的原因。如服务注册发现机制的不统一,作业帮有名字服务,但因为多语言栈支持的不够友好,如 NodeJS、Python 等语言就直接选择 DNS+LB 的方式来进行负载均衡,绕过统一的注册发现机制。
在流量治理这块还面临一个问题,一方面我们是希望跨云流量能从架构层面被严格约束起来,但另一方面,因为上述诸多问题,又要具备临时或永久的灵活跨云调度能力。一定程度上是矛盾的。在部署和流量治理上均不到完美的情况下,多数企业会选择通过演练,以 QA 的验收来达成多云多活的效果。作业帮早期也是选择的这条方案。但实践了几次后发现这条道路很难走通。通过全公司级别的演练来发现核心链路中的跨云问题,成本过高。而且业务是在不断迭代的,解决了这块,又会引入新的问题,墒增的问题无法避免。即使可控制到单部门的演练,问题依旧存在。
作业帮针对这块设计了一套理想方案,我们将一个云上的应用分成两部分,一部分是互通区域,另一部分是受限区域。两者的不同在于,互通区域中的应用可以做跨云通信,而受限区的服务不可以,只能通过互通区域中转。将业务应用都放置到受限区域,互通区域都是基础架构提供或者认证的组件。这样就可以实现灵活性和严格性的兼容。以业务服务 RPC 调用为例子,两个云上的业务服务无法直接通信,而是需要在云上的东西向网关配置发现规则,才能实现通信。在此架构下,我们允许允许一定程度的不对等部署、跨云流量但一切都要在基础架构框架内,可感知、可管控。
好的服务注册发现机制的选择可以大幅度避免跨云的流量,当这个问题量级缩小一到两个数量级后,我们治理的难度也会大幅到下降。治理的第一步就是能够度量这些跨云的流量。由于 PHP、Golang 都是走标准框架的,我们早期通过服务 RPC 配置来度量。但对于小众语言栈和不规范的服务通信方式就无能为力了。我们在多云专线间上线 CPE 后,通过 CPE 这个管控面就可以获取五元组数据。但由于容器 Pod IP 是变化的,对于分析 IP 具体是哪一个服务有一定困难。所以我们结合上了 EBPF 。作业帮上线容器集群的所有机器内核更新到 5.10 及以上,利用 EBPF 的特性,我们可以获取所有网络包的信息,再结合 etcd 当中的服务注册信息,就可以反解出服务名。通过多维度数据组合,就能最大程度上度量出跨云的流量。
跨云治理是一个较漫长的工作,需要有完备的平台支撑,避免一次性的任务。所以我们也开发了对应的平台,向研发开放,方便其自行优化。而基础架构关注 top 的跨云流量治理进度。当跨云流量治理到一个相对较低的水平后,就要将大坝合拢,做常态化断网。从 CPE 上做 ACL 策略,禁止容器应用网段的通信。对于长尾的虚机服务,在其入向的安全组做流量拦截。在这种网络架构下,业务的跨云流量就只能通过我们指定的通路,东西向网关来流转了。墒增的问题得到根本性的治理。
最后就是这套架构的持续运营了,对于短时间无法改造完的,我们持续跟进其进度,逐步将其从跨云白名单剔除。对于业务临时的需求,明确原由后,添加临时的白名单。完成这种架构后,作业帮仍会进行周期的断网演练,但不再需要一个月那么频繁,半年进行一次即可,主要用来发现架构的隐藏问题以及预案的执行流程。以上的话就是作业帮多云架构的整体建设,我们又是如何将建设的成果应用于具体的实战当中。首先就是我们多云的迁移能力得到了大幅度的提升。在刨除冷启动外,几千个服务,包括对应的数据存储,我们可在 3 个月之内迁移到一朵新的云上。具体迁移的 SOP 可以划分为以下几点。
第一块的话就是冷启动,我们要在数据面以及控制面上跟新的云厂商去磨合标准,具体选择哪几款主力机型?作业帮对 K8s、内核、Serverless 都有一些自己的一些要求,需要云厂商进行一定的适配。在控制面上,除了对接管控 API 外,很重要的一块就是账单 API 的对接,不然这后续对账的成本就会居高不下。接下来就开始服务的部署。整个服务部署的流量也是按照 IaaS、PaaS、SaaS 逐层开展。先去规划好对应的网络、VPC,设置对应的 LB、NAT 等,准备好相关的机器,然后进行数据存储的迁移,因为数据的规模较大,整个同步的周期也较长。在数据同步快接近尾声的时候开始去进行其他组件部署,不管是 K8s 的各种插件、网关、消息队列等等。完成这些之后开始进行业务服务的部署。
这一切准备好后,就要开始进行流量的迁移了。首先验证的自测流量,既要通过功能测试,也要保证通过性能压测,保障新云服务的稳定性。下一步就是通过 DoH/DNS 等机制逐步放量,1%、10%、20%等等。最终完成预期流量迁移。这一切完成后,两边运行一段时间后,就要开始进行收尾治理,将老云当中的冗余流量逐步下掉。至此才算是迁云完满达成。上面讲的是迁移一朵新云的 SOP,我们更多时候是做不同云上的流量调度,这个的话基本上几天就可以完成。正是因为有了这样的能力,所以作业帮才可以持续地享受到物美价廉的云服务。
再来介绍下单云故障演练。只有在演练中能达标,面对真正故障时才能更有底气。故障模拟要尽量的真实,单云故障就要做到既不能接收到南北向的用户流量,也无法东西向和其他云进行通信。为了避免影响用户,我们将南北向用户的模拟限定在工区。在云机房 1 的接入层拒止作业帮工区的流量,这样就可以模拟出用户无法访问云机房 1。然后在 CPE 添加 ACL 策略,拒止云机房 1 和云机房 2 的通信,这样就模拟出东西向的故障。这里还有一个待完善点,我们只是把应用层的东西向流量禁止了,数据存储间的流量还是先豁免了,主从间仍可以同步。不然就会带来脑裂的问题。为了一次故障演练,修复上千个集群的数据成本还是太高。
整个故障注入的操作和生效时间控制在 5min 内。完成之后开启第二步,执行预案。通过预案平台将作业帮的流量全都指向到云机房 2。预案平台有不同机房的入口地址,数据存储也选择的单元化模式,这样运维不需要前置环节就可以直接操作预案。5 分钟内完成业务域名的切流。10 分钟内实现 P90 流量的收敛。测试就可以开始进行功能回归了,主要针对 F0、F1 功能,一般 1-2 小时就可以完成,研发在过程中关注相关报警。当顺利完成一边云的验证后,再重复整个流程,模拟云机房 2 故障的情况。通过故障的演练,有效保障我们的 SLA,系统的稳定性得到大幅度提升。时至今日,作业帮的多云架构仍在持续迭代当中。我们下一步的展望主要聚焦在以下几个方面:
单元化的进一步深入。当主库所在的云出现故障时,还需要进行数据存储的提主操作,这个操作本身较重。而单元化是更优的解法。阿里这块的建设还是走的比较前沿,交易链路中库存数据也实现了单元化改造。
不断精细化控制爆炸半径,让故障演练更加的真实,将数据存储也能参与进来。应用服务可以按照部门来快速展开。
服务感知体系的单元化改造。这个在真正故障的时候至关重要,当前监控已实现了分区,链路追踪、日志等也在规划当中。
【活动推荐】
7 月 21 - 22 日,ArchSummit(深圳站)全球架构师峰会,将在深圳·博林天瑞喜来登酒店举办,会议将围绕架构技术实践展开分享,例如:智能化数据治理、可持续软件、DataOps、Data Fabric 等高效数据开发与服务模式、Mesh 技术实践案例、QUIC 传输和架构优化、跨境数据安全与合规等。
现在购票,享八折优惠,立减 ¥1760,咨询购票可联系:18514549229
评论