百度搜索与推荐引擎的云原生改造
导读:从去年开始,百度 MEG(移动生态事业群)架构平台上的用户产品逐步进行云原生改造,如今已基本完成。现阶段更多关注动态弹性能力、动态管理机制的建设。我们邀请到来自百度推荐技术架构部的传玉老师, 跟大家聊聊百度搜索与推荐引擎云原生改造的阶段性策略,以及对未来发展的思考。
嘉宾简介 :传玉
2012 年起专注于搜索引擎与推荐引擎方向;2016 年开始负责自有的资源调度和容器编排系统的研发工作;2019 年开始负责部分通用基础组件的研发工作,并开始在 MEG 用户产品内部全面推进云原生架构改造。
01 核心关注两个“效率”,实现降本增效
“说云原生的目标是让整个开发上线应用的过程更简单,这一点我是同意的。百度的搜索与推荐引擎规模都非常庞大、业务极其复杂,尤其是搜索,有着 20 多年的历史,无法完全按照一套新的理念来设计逻辑。所以,我们在尝试云原生时,必须结合我们自己的基因和现状。”
云原生架构的主要价值在于效率的提升,包括资源利用效率和研发效率两个方面。
从资源利用效率上,期望通过容器化和动态资源调度实现在线服务的充分混布,让集群整体资源使用更加均衡,更加高效,从而降低整体的机器成本。此外,通过云平台实现高效率的资源化交付取代物理整机交付,提升资源的流转效率,让内部的资源能够更快速地流转到重点业务上,支持业务的快速发展。
在研发效率上,一方面通过微服务改造,解耦不同业务团队的迭代,减少团队间的互相影响,去提升业务迭代效率。另一方面期望把通用基础架构能力下沉到云原生基础设施上,提升新业务架构能力的基线水平。
例如一些局部故障容错能力,在一些业务线上类似的架构机制已经很成熟了,但对于新的业务线很难直接复用,往往还需要再踩坑,参照成熟业务线的经验,逐步建设,如果我们能把这些通用的能力以标准化和规范化的形式沉淀到云原生基础设施里,那创新业务线就能比较简单地复用,少走弯路,尽可能少欠技术债。
此外,云原生架构对研发效率上的提升,还体现在降低线上问题的处理以及维护上人力和时间。
通常业界有个说法:一个存储系统好不好用,关键看他的运维水平。
但实际上,不仅是存储系统,对于很多创新项目来讲,如果太多的人去支持维护线上服务的运行解决线上问题,那么投入研发上的人力就相对减少了,相应的发展速度可能就会受影响
通过一些云原生的基础设施,我们可以把各种常规的运维操作标准化和自动化,比如机器故障的自动维修,服务实例故障自动迁移,服务容量的自动化调整。一方面可以减少运维的人力成本,另一方面很多情况下自动化的系统能比人工做的更好。
“在之前,我们也是有自动化机制的。但应用云原生架构带来的好处,是让我们能够通过一个更规范、更标准、更可持续发展的路径,去做这些自动化的机制。就是把那个大量的人力从这种线上服务的维护中解放出来。在团队规模不变的情况下,维护人力减少了,能全力投入研发上的人力自然就多了,整体研发效率也就上来了。”
总体来说,云原生最大的意义在于提高效率,提高了整体研发的 baseline。
尤其是在做新产品时,能够省去购买资源的成本,在基础阶段也省去用太多的人力投入来保障产品上线顺利。成本越低、能做的创新就越多。这样就让每一个新产品都避免输在起跑线上。
02 规范服务设计标准,为云原生改造立好规矩
MEG 架构平台在 2019 年时已经全面云化。但是,多数服务的迁移仅仅是部署方式从物理机部署转变为 PaaS 平台容器内部署,并没有针对云环境以及云能力进行架构上的改造和升级来获得更大的成本和效率上的收益。基于这一问题,期望通过进一步规范 MEG 架构平台服务设计标准,实现从云化架构到云原生架构的转变。
“实现云原生化之前,我们已经具备一定的基础。首先是从整个组织上具备了微服务的思想;其次是从实践上制定了一系列微服务最佳实践的标准,建立了《MEG 用户产品架构云原生内部规范》;第三,我们已经有一系列公共的基础设施。”
传玉参考了业内广泛认可的云原生应用的特征,结合百度内部的先行实践,为了保证云原生架构落地的效率和效果,从以下三个方面来规范服务模块设计:
1、微服务化:每个服务粒度应该在限定的范围内;
2、容器化封装:一个服务的部署,应该只依赖基础架构以及本容器内的组件,而不应该依赖其他业务服务;
3、动态管理:每个服务应该可以动态调整部署,而不影响自身对外承诺的 SLA。
*各项规范的评估方式:
*业务整体评估方式:
1、未接入 PaaS 的服务,以不满足标准计算;
2、以服务为单位评估是否满足规范,只有当一个服务同时满足上述所有标准时,才认为一个服务是满足云原生架构规范的;
3、每个业务线以百分制计算云原生规范指数,计算方式为(符合规范的服务模块所占的 quota 总量 / 总 quota),使用 CPU quota/MEM quota,按比例低的计算;
4、各单项分数,仅作为内部指标参考, 用于分析瓶颈,推动落地。
03 划重点,云原生化的阶段性实现路径
从云化到云原生化,是一个非常复杂的过程。在制定了云原生改造规范后,陆续经历了 4 个阶段,分别是:微服务改造、容器化改造、动态管理、进阶云原生,而 MEG 的云原生化进程并未停止,而是朝着第 5 个阶段——声明式架构继续探索。
第一阶段:微服务改造
起初,百度 MEG 架构平台实现全面云化时,将所有的架构服务、资源都托管到内部的云平台上,但是当时仍遇到了对资源的利用问题。MEG 架构平台推行云原生的第一件事,就是要求所有的服务去做微服务改造,消灭巨型服务。
“这些巨型服务,会导致整体的资源分配容易出现碎片,比如某个服务占用一台机器 80%的资源,那剩下 20%很有可能分不出去,就会出现独占的现象,不能混布。还有一些服务在部署之前,要对整机的环境做一些修改。
因此,虽然当时所有的资源都托管在了云平台上,但我们在使用时仍然与直接使用机器差异不大,OP 投入了很多,整体线上资源利用率,包括资源的分配率,相对较低。”
微服务拆分之后,带来了几个变化:首先是性能提升。
虽然多了一些 RPC 的开销,但拆分之后,每一个服务都可以被针对性的优化,所有的扩缩容操作亦可只针对这一服务的逻辑进行。因此从整体成本、延迟等各方面使性能达到大幅提升。
其次是研发效率提升。
按原来的产品和策略的迭代,很多时候一个服务需要几百人共同进行,上线耗时长。但拆分之后,虽然多出几十个模块,但一个模块只需两三个人迭代即可,也可以随时随地上线。这对研发效率整体提升是很大的。
“比如说我们的 Feed 视频推荐服务,在拆分前是一个巨型服务,迭代频繁。单实例 450 CPU,100G 内存,单模块越 40+ 策略 RD 参与开发,每天上线 feature 10+个。所以在运营过程中产生了大量资源碎片、上线时间长、内存迭代困难。
我们做了 3 件事:
第一,按推荐业务逻辑,拆分为聚合和召回两层;
第二,召回层按召回算法区分,拆分为若干并行的召回服务,召回服务部分可丢;
第三,聚合层拆分为机器学习预估服务和聚合服务两块,机器学习服务使用 avx 指令集加速。”
Feed 视频推荐服务改造的成果是:
l 单个大模块拆分为 10+个小模块,最大的模块内存占用 < 40G.
l 整体 cpu 占用减少 23%,内存占用减少 84%
l 延迟降低 50+ms,稳定性从不足 99.9%提升到 99.97%
l 迭代效率大幅提升,彻底消除了搭车上线互相 block 的情况.
第二阶段:容器化改造
MEG 架构平台做容器化改造,就是要求所有的服务把它依赖的东西,都放到容器内。实现所有服务的一键式的部署,也就是自动化的部署。
可能现在的一些新兴的 互联网企业中并不存在这一的问题,因为大家很多服务本身就是基于 Docker 的。但百度搜索系统具有二十年历史,必须花时间去做这件事。这个过程中,一个典型是改造搜索的 BS 模块,它的年龄几乎和百度搜索一样大。
二十年前,百度架构师在设计 BS 时,考虑的是尽可能占满整机资源。
“那个时候 SSD 非常昂贵,所以设计 BS 时,就希望能把 SSD 用满,同时,为了方便,并没有全部显示申请,比如你声明了用 10G,而实际上却用了 60G。这在当时没什么问题,因为一台机器只有一个服务,使用资源时无论是显示还是隐式,都跟别人没关系。现在的磁盘硬件已经跟二十年前完全不同了,单个服务的计算量往往不足以占满征集整机资源,为了避免浪费,就需要把其他服务混布上去。这样一来,问题就出现了,就得改。”
第一件事,每个服务显式地声明自身需要占用的资源,改掉贪婪式抢占的策略。
把所有的资源放在他自己的容器里。也就是说,把 BS 从一个机器级的服务,变成了一个容器级的服务,不占用容器外资源。做到这一点,才能让容器编排系统的调度能力真正发挥作用。
第二件事是提升服务的部署效率。
有一些比较老的服务,可能部署的时候需要去拉很多额外的数据,甚至部署的时候还需要 op 去人工做一些机器的参数和配置调整。这都会导致部署没法自动化执行,或者部署的速度太慢。为了改善效率,需要把服务对于物理环境的依赖都消除,只依赖容器内的环境。此外,我们也需要做 P2P 的下载优化,和一些数据的实时化的改造,去优化服务启动的速度。
“我们之前曾经用过一个存储数据类的服务,逻辑上来说是能迁移的,但实际上一个实例的迁移大概耗费 8 小时。这种的可迁移性就没有太大意义。因为存储 数据服务受副本数/容量/并发数的限制,比如说一个集群有成百上千个实例,但最多一轮只能迁移几个, 然后迁移一轮的话,要耗费 8 个小时。那整个集群迁移的时间就会非常长。想进行内核升级、操作系统升级、故障维修等就会非常麻烦。因此,我们要做 P2P 分发优化,做数据下载和数据分发的优化,把部署速度提上去。”
第三阶段:动态管理
动态管理这件事,主要说的“动态”,比如线上服务是否能随时迁移、随时扩缩容。
它分为两个层面:
一方面从业务本身来看,动态管理要求所有的服务都具备一定程度的弹性和容错能力。
因为线上的实例但凡涉及到扩缩容或迁移,就会出现短时间内的重启或不可用。这就首先要求线上所有服务都具备一定的故障容忍能力。其次,服务需要具备自动的负载均衡的能力(最简单的方式就是使用 naming service 来访问服务),有新的实例加入,需要能自动去打散流量,有实例故障或者退场,也需要能及时屏蔽
另一方面从基础设施层面来看,既然所有的服务都能随时做迁移和扩缩容。
那我们就可以在服务的容量和流量上按需操作 实现自动化的按需分配。
“一旦某个业务要做一个运营活动,就需要临时做大量的扩容操作。这个过程在非云原生的模式下原来很麻烦,要先去找一批物理机,然后把服务部署到这批新机器上实现扩容,做完了活动以后再把服务下掉,之后再退出物理机,整个过程涉及到大量的人工操作,成本是比较高的。但在动态改造后,找物理机的操作就没有了。我们所有的服务在一个大的资源池里面。任意业务短时间内需要额外的资源,直接在里面扩缩容就好了。因为不同业务的需求时段也不同,还能错峰使用。
“再有就是资源使用的弹性上,比如说对于我自己的推荐系统来说,如果资源池里有额外的资源可用,这能让我的推荐系统 通过更多的复杂计算 来提供更好的用户体验。所以在没有运营活动时,我们用这部分闲置资源来提升推荐和检索效果。当有运营活动时,我们再把这份资源吐出来给运营活动。这样方便我们整体对资源进行平衡使用,而且这个过程应该是一个代价非常低的一个自动化的操作。”
第四阶段:进阶云原生
为了继续降低成本、提升效率,从 2021 年开始,MEG 架构平台的云原生改造,在动态管理的基础上增加了像 Serverless、Function as a Service 等进一步的操作。
在改造之前,整个系统的那个容量是基本固定的,一旦有突发流量就只能降级。通过 Serverless 机制,实时监控流量,发现异常就能在几分钟内自动完成扩容。
而 Function as a Service 的话,是让研发效率提升到极致的一个方向。它能让业务同学只关心自己想要实现的逻辑。至于在架构上怎么拆分微服务、怎么做流量的调控、怎么做做容量管理,全部交给底层的系统来执行。
第五阶段 声明式架构
传玉提到,其实在进阶云原生阶段做的一些事情,都在向着声明式架构靠拢。比如 Function as a Service 就是声明式架构中关键的一环,包括 Serverless 机制的实现,最终目标也是希望能把策略和架构彻底解耦。
“现在很多架构在设计的初期都是没什么太大的问题的。但随着业务发展,运行了一段时间后往往都需要重构,因为随着业务的变化,系统面临的业务场景已经不一样了。但架构的调整是非常复杂的,一般都会伤筋动骨,还会涉及到大量的业务策略逻辑迁移等。我们期望尽可能的把业务和架构拆分开,把业务逻辑和架构设计拆分开。这样业务描述逻辑时尽可能简单,我们的系统可以根据这些描述自动拆分 Function,再把这些 Function 发送到系统里去执行。”
如果能做到架构 &业务分离,那么 MEG 架构平台会变得非常灵活。
包括有哪些节点、执行哪些 Function、用这些 Function 怎么去做连接、怎么去做组合,全部交由自动的推导系统去实现。如此一来,我们的系统会变成声明式的,也就是说你在上面声明你的业务逻辑,它会自动推导出需要怎样的架构,自动去执行。
“这样这当然是一个最终的理想态。我们在实现的路上,还需要做很多很多事情。”
以上,是百度 MEG 架构平台完成云原生改造的一些关键路径。
在后续的分享中,传玉还会围绕服务治理、自动化、混沌工程等方面,重点聊聊过程中的一些问题和解决办法。
更多精彩内容欢迎关注百度开发者中心公众号。
评论