关于搜索:百度垂类离线计算系统发展历程

18次阅读

共计 9088 个字符,预计需要花费 23 分钟才能阅读完成。

作者 | 弘远君

导读 

本文以百度垂类离线计算零碎的演进方向为主线,详细描述搜寻垂类离线计算零碎倒退过程中遇到的问题,以及对应的解决方案。架构演进过程中始终奉行“没有最好的架构,只有最合适的架构”的主旨,面对不同阶段遇到的问题,给出了适宜的解决方案。尤其是近 10 年来的超大规模零碎架构的降级,一方面须要思考零碎自身的通用性和适配性,以满足多个业务方的需要;另一方面须要联合零碎以后运行的特点,在易用性、稳定性、智能化等不同方面进行晋升。心愿读者能在理解零碎演进的过程中取得一些启发。

全文 9127 字,预计浏览工夫 23 分钟。

01 相干背景介绍

在过来,用户通过“百度一下”失去的搜寻后果是从互联网上抓取来的后果,也被称为“天然后果”。随着网络信息日益丰盛,天然后果不能无效满足用户需要。为了解决天然后果无奈满足搜寻需要的问题,提出了针对各个垂类深耕的搜寻后果的解决方案,一方面为用户带来的更优质的内容,让用户体验即搜即得的便捷,另一方面也能够帮忙优质内容生产者晋升访问量。

随着业务倒退,除了规范通用的业务解决需要变更之外,越来越多的业务有自定义代码的更新需要。通过自定义数据处理,一方面,产品负责同学能够将原始传入的数据依照业务需要进行定制化解决,将原始数据转化为最终搜寻的后果数据。另一方面,通用默认的一些性能机制限度了大量垂类的倒退,业务心愿引入更多的策略 模型逻辑 信号等解决以及打分机制,晋升排序召回的成果。

在这样的背景下,业务对于数据加工计算的框架引擎的需要越来越强烈,并且性能也逐步成为整个垂搜离线处理过程中不可或缺的一部分。

02 计算零碎演进过程

百度搜寻零碎离线数据处理从工夫线的倒退阶段来说一共经验如下几个阶段:

a. 原始离线解决零碎: 本阶段次要是实现业务 加工入口从 0 到 1 的构建。整体上还没有造成齐备的框架体系并且开发成本较高,并且所有业务逻辑混在一个公共服务中,不同数据通过不同配置调用不同的策略逻辑。

b. 业务离线解决架构: 本阶段初步造成一整套的业务服务 解决框架,有对立的服务框架和开发阶段,实现了云原生和服务隔离的模式。

c.Serverless 架构: 本阶段 业务的接入效率 上进一步提高,业务从治理服务面向转向治理业务 加工函数,业务只需注册函数就能够疾速测试上线,同时反对容器实例的主动伸缩,使得在业务的应用效率失去的极大晋升的同时相应资源老本急剧压缩。

d. 数据智能架构: 在原有服务部署的根底上同时实现了数据的治理,从函数治理进一步降级成为 需要治理,实现多语言服务框架反对的根底上,老本进一步压缩 & 效率晋升。

03 计算系统核心设计外围思路 & 外围实现

上面具体论述各个阶段的具体特点以及外围实现。

3.1 原始离线解决零碎

这套架构利用于 2018 以前,过后垂类的倒退整体属于起步阶段。该阶段业务次要的需要就是能够将原始的业务数据间接上线。架构的次要精力聚焦于通用业务能力的建设。随着业务的逐渐深耕,发现有大量的业务缓缓演变进去自定义加工的需要。

依据过后的业务需要,最终从原有的数据加工模块中衍生出 业务数据加工零碎 。以后阶段的数据加工解决形式是应用对立 Handler 解决形式,当然这个解决并非是必选项,少数业务依然不须要自定义加工解决。各业务之间也齐全 没有 数据 隔离 这种架构最外围的意义就是从无到有提供业务的自定义加工能力。如下图所示,此时计算零碎只蕴含计算引擎局部,其余零碎齐全没有建设。上面会对该零碎的局部细节进行具体阐明。

3.1.1 业务特点

这个期间的业务特点次要有两个:

  • 少数业务,外围诉求最次要的是通用能力的建设。
  • 个别业务,有大量简略的自定义加工解决的需要。

所以这个工夫点的外围次要是为了解决业务加工入口的问题。

3.1.2 外围设计

初版本的离线架构模块非常简单,如下图所示蓝色局部。随着业务倒退,为了满足业务自定义加工的需要,引入红色数据通路,其中对立数据加工模块就是次要解决业务自定义加工逻辑。

如上图所示,灰色局部是业务外层接入的数据系统,最开始的时候只有 XML、POST 和 数据队列的这种模式。蓝色局部就是业务没有自定义时候原始的数据框架代码。红色局部就是为了针对业务自定义需要引入的框架模块:

用户数据代理:次要是为了适配业务数据接入形式,数据的协定打平,次要是不同用户协定的 RPC 做建库层的数据转化。

用户通用需要:次要是为用户共性需要做对立解决,会依据不同业务的不同配置做性能解决:比方业务图片视频的转化解决,业务用户版本治理解决以及用户的外围机制等。

对立数据加工模块:次要是为了对立用户数据的加工解决,次要是给所有接入的业务的数据提供了一个能够数据加工的入口。

3.2 业务解决架构

如上文所述 3.1 架构外围价值是自定义加工能力的从 0 到 1 的建设,然而随着业务的疾速倒退,越来越多的业务须要自定义加工能力。业务自定义加工的需要从原来个位数迅速收缩了 10 倍。因而,为了满足业务在自定义开发上易用性和稳定性的诉求,将原来 3.1 的中心化的解决模式降级成为 服务框架的模式。总体上来说,以后阶段的计算零碎建设曾经根本具备了服务层和业务层两层:

业务层:业务通过平台曾经基本上能够实现,根底的服务治理。

服务层:对计算引擎进行重构,让新的服务框架反对业务的高效开发。

上面会对该零碎的局部细节进行具体阐明。

3.2.1 业务特点

因为 3.1 中上一代零碎数十个业务自定义需要对立在同一个模块外面开发 & 对立线上运行,遇到了次要如下几方面问题:

效率:业务在雷同的模块外面开发,导致业务开发上线的过程中常常遇到抵触,以及上线排队的问题,导致整体失效周期比拟长。

稳定性:因为这种业务流量混合的模式隔离性比拟差,导致单个业务出问题,常常会影响所有的业务。

因而,架构构建出欠缺的服务框架,业务能够基于服务框架构建本人的业务代码,从效率和稳定性两个方面解决上述问题:

效率:服务开发上线的过程是齐全隔离的,业务在开发上线的过程中齐全没有业务阻塞,整体服务上线周期从天级缩短到小时级别。

稳定性:因为每个业务服务执行逻辑都有齐全独立的 app,导致业务的稳定性大大晋升,不会存在业务之间的相互影响。

3.2.3 外围设计

业务解决框架:建设一个数据处理框架,业务能够基于这个框架来实现本人的业务解决性能。

工作平台:每个工作注册、降级、治理都能够通过工作平台来进行治理。

对立网关:所有数据的对立入口,对立接管上游数据,并且做数据的转发和散发。

业务 APP:每个业务都有本人独立服务的 app,每个业务开发是基于框架的独立分支开发,上线是每个业务独自上线,业务解决的服务流量也都是齐全隔离的。

3.3 Serverless 架构

如上文中 3.2 表述曾经解决零碎隔离性的问题,业务疾速倒退从最开始的几十个,倒退到上百个业务利用。当业务倒退到井喷状态后,服务框架的模式曾经齐全不能满足业务的开发需要。

Serverless 架构如下图所示,此时计算零碎整体幅员曾经绝对欠缺,相比上一代计算架构,不仅仅业务层蕴含的全流程的优化,提供了残缺的工具性能;服务层充分考虑的架构的设计和复用,同时减少管制层减少智能调度的性能针对零碎流量进行资源的动静调度。

上面会对该零碎的局部细节进行具体阐明。

3.3.1 业务特点 & 解决问题

业务学习老本:大量的新业务接入须要进行开发,导致框架自身学习老本须要几天的工夫,新业务的接入和开发的工夫基本上都在周级别。

资源如何节俭:大量的业务也带来 app 的高速收缩,原来接入的数百台机器曾经用满,到了资源瓶颈,以后的资源量无奈反对业务的疾速收缩。

3.3.3 外围设计

应用层:针对于根底服务架构,下面给业务凋谢的各种云服务,从业务的 接入、开发到前面的调试、测试,到服务上线后的监控。

服务层:这部分是整体架构的根底,应用层都是基于这里进行开发的,这部分是整个零碎的基石,属于整体零碎的外围框架。

调度层:通过依据流量模式的扩缩容,保障后续服务能够自动化的进行服务操作。

上面重点介绍一下 服务层的次要内容,对业务来说次要蕴含两局部:

极致形象的业务框架:是外围框架根底中的根底,提供新的开发范式同时,为后续智能调度奠定良好基础。

高度复用的根底服务:弱小丰盛的后端服务能力封装,反对业务低成本复用,升高开发成本同时晋升稳定性。同时零碎还提供弱小的编排能力,低成本反对业务从简略到简单的倒退。

极致形象的业务框架

业务框架作为 FaaS 层和业务代码的载体,是整个业务逻辑的代码框架。框架自身保护数据流语义,面向有向无环图(DAG)的数据流,调用业务函数代码。业务框架是面向有向无环图的数据流实时计算,基于公司根底的数据流框架反对齐备的流式计算语义,联合业务场景须要性能构建出业务框架:

如上图右边就是用户理论的执行代码,对于函数的接口定义:入参和返回值都是 Dict 类型。业务的代码逻辑间接在函数中实现,须要变更的数据,如上图所示业务在根目录下减少了一个工夫戳字段,而后把更新后的后果传递给上游。

业务端应用开发成本低的脚本语言进行开发(例如 Python),根底服务框架应用 C ++ 实现,联合数据压缩、批处理、数据预散发等机制,使得业务能够在简化服务框架开发同时优化服务运行性能。通过架构层面的优化策略来达到服务性能和开发成本的均衡。

高度复用的根底服务

业务依赖的后端服务,包含多媒体长留服务,数据存储服务,策略计算等十项服务能力,所有的服务架构的反对指标都是通过简略配置、大量代码的形式进行服务接入。

架构通用能力:包含索引解决(倒排、正排、向量索引),数据审核(政治敏感数据 / 色情数据辨认 & 过滤),多路散发、数据建库等能力。

与业务联结研发的能力:数据的低质过滤能力(实现数据荡涤 / 归一化 / 数据去重 / 类目拼接),数据多元交融,数据品质打分计算(品质打分 / 舞弊辨认 / 物料打分)。

基于公司弱小根底能力: 多媒体解决服务(外链转内链 /OCR/ 水印计算 / 反复图计算 / 主体辨认 / 视频转储等),自然语言解决服务,数据积淀服务。

反对的根底服务 (BaaS 服务) 次要是两个特点: 简略稳固 & 充沛集成公司内其余优质能力 。用户通过SDK 调用、算子复用和数据流复用 等形式间接进行能力复用,齐全不须要进行服务的部署和治理,服务易用性、稳定性由搜寻中台来解决。应用任何服务后端都能够收口在一个中央,防止业务频繁跟多个服务团队进行交换解决,极大升高业务应用老本。业务最开始接入通常只须要简略的多数性能(例如,批改局部字段的信息),少数业务间接用咱们提供的平台化的开发模板即可实现开发。然而随着业务的逐渐深耕,业务逐渐应用,业务会向简单逐渐过渡,例如搜寻中台某业务通过复用数十种能力的组合应用,建设出具备深度定制的数据系统。

3.4 数据智能架构

如上文中 3.3 表述曾经很大水平上解决业务接入效率的问题并且在资源的应用效率上实现依据流量的扩缩容实现的资源极大水平的节俭,业务的 app 的数量曾经倒退到上千个,业务对于效率、老本、服务质量提出来更高的要求。至此曾经构建出,从业务层、逻辑层、服务层、管制层的四层架构,实现离线计算零碎从指令式计算零碎到申明式计算零碎的彻底转变。

3.4.1 业务特点

  • 效率业务的迭代开发很多都是针对少数几个字段,然而以后业务同学依然须要理解服务全拓扑能力开发。
  • 随着业务简单深耕业务的开发迭代业务开发者呈现多语言开发状况来进步服务的开发和执行效率。
  • 业务如何实现新类目标疾速接入、在不理解全面的状况下疾速迭代。
  • 计算引擎执行效率更高,用更少的资源计算跑更多的服务资源。
  • 业务问题能不能疾速定位 & 发现以及问题的主动解决。

3.4.2 外围思路

从设计思路来看以后零碎架构是上一代架构的拓展:

  • 数据管理:出了原始服务治理外,引入数据全面治理,为列计算奠定根底。
  • 编排能力:将原来业务手动编排的函数能力扩大成为 需要申明式 主动编排的能力。
  • 服务解决:极致高效的服务解决能力,反对多种不同业务开发者的高效开发效率,将整体的计算从行计算转向列计算,进步整体的计算复用。
  • 控制能力:将原来主动伸缩的能力扩大成为 智能控制能力,做到问题的自动识别、主动散发、主动剖析 和 主动解决。

整体架构的设计核心理念大抵是 多层形象、分层复用

3.4.3 外围设计

以后阶段的外围设计曾经呈现出残缺的四层架构的形象能力:

应用层:业务间接可见的相干服务,包含业务从开始数据接入到服务运行的全周期各阶段各种利用。

逻辑层:也能够称之为编排层,负责将原始的业务需要表白转化成为线上实在运行的服务,业务通过 Codeless 平台化抉择勾选本人的性能汇合,以及对应数据映射关系进行提交,将用户提供的性能 & 数据的绑定关系转化为业务的自定义的性能 以及映射关系。

服务层:计算零碎的外围,业务理论计算运行在这层,次要蕴含计算引擎 和服务架构两局部。向上承接逻辑层的编排后果运行服务,向下提供根底信号作为管制层的输出。

管制层:蕴含智能调度和智能管制两局部:智能管制次要是通过主动承受业务指标数据进行智能管制保障服务稳固,而智能调度是除了依据数据流量进行进行主动伸缩以外还能够依据业务服务关系进行流量复用,缩小业务的反复计算。

上面咱们针对局部外围零碎(如上图蓝色局部)的设计作开展阐明。

需要表白逻辑

需要逻辑的表白的外围就是如何把用户原始的性能需要转化成真是线上服务的算子、配置、关系的表白。用户最原始的输出蕴含两局部:

业务数据:业务数据须要性能的最小单位进行切割,后续算子进行配置转化以及服务绑定的列式计算。这里说的有点绕口,其实实质上就是把业务数据的原始 Proto 或者数据 Schema 注册一下就能够。

性能汇合:性能汇合既能够用户间接应用的零碎提供的默认模版的性能汇合 也能够是用户通过平台自定义的汇合,值的留神的是每个性能都都有其指定的传入参数,比方图片计算,须要传入图片 URL,向量计算须要传入原始数据 & 向量参数等等。性能实现后也会有对应的输入后果业务能够指定。

获取实现用户的原始输出后,架构通过 两层逻辑映射 的形式,将原始用户需要转化成为线上服务部署信息:

需要表白服务 :用户的原始需要转化为 性能模版的组合。这个阶段会依据用户配置,将原始算子和数据进行绑定,原始用户形象的需要实例化成带数据的算子汇合。

需要编排服务:通过业务算子的自身的依赖关系和数据依赖的血缘关系进行表白组合,将带数据的算子构建出 N 个有向无环图。

整体需要表白都能够通过 Codeless 形式表白,通过形容性能汇合 ✖️ 数据汇合形容形式,加之两层逻辑映射的转化,这样就能够将原始用户 申明式 需要间接转化 线上服务关系和系统配置,并且服务的算子的拓扑关系齐全能够通过业务的数据关系表白自动化推导进去,实现了 95% 以上的性能能够齐全自动化配置实现,当然有个别服务无奈低成本转化表白的,也提供了人工接口。

计算引擎实现

计算引擎层的外围组件大抵分成两局部,图计算引擎 & 多语言算子的执行引擎。

图计算引擎:次要管制的业务拓扑的表白关系,通过有向无环图来表白。

算子执行引擎:次要管制业务实在业务函数的执行,不同语言有不同的函数实现,例如 Python、GoLang、C/C++ 都有本人的执行引擎。

上面针对两局部进行认真阐明

  • 图计算引擎实现:实现的外围性能就是实现反对表白有向无环图的框架,应用 C ++ 实现的,图下图局部中,蓝色局部就是有向无环图的框架实现,当然咱们这个框架的底层实现反对了多种数据的表白:
  • 本地队列表白:如图左下角局部表白的就是一个简略的拓扑表白,拓扑关系是通过本地的无锁队列进行串联的,每个队列上面挂载一个业务算子,业务算子解决实现数据后,算子拓扑配置管理散发到上游的本地队列中,如果是最初一个算子,数据后果全副解决实现后输入到近程队列 Producer 中。左侧这边是框架外部的通用性能:

线程治理:每个业务算子默认都是多线程的散发模式(如果业务算子只反对单线程,能够把线程数设置成 1)。

散发模式:数据生产散发模式默认是轮询散发,固定 KEY 散发(实现保序)以及按生产能力散发。

数据压缩:这个默认反对常见数据压缩办法,是可选的吞吐优化伎俩,反对 LZ4、Gzip、Snappy 等常见压缩算法。

  • 近程队列表白:每个蓝色大框示意一个具体实例,实例之间应用近程队列交互,如果每个实例外面只有一个业务算子,这种的交互方式相似于近程队列的表达方式。
  • 混合形式表白:更多应用形式是混合应用,一个巨型拓扑会拆分成多个子拓扑,每个子拓扑应用本地队列的形式进行表白,而子拓扑之间应用近程队列的形式进行表白。
  • 多语言引擎执行层:语言执行层整体框架整体依据不同的语言有不同实现模式,大体上分成三局部:编译型、解释型、原生 C ++。

解释型:最典型的就是 Python 实现形式,这种形式也是过来同学最喜爱用的开发语言之一。图上图最下面,右边灰色局部是 C ++ 开发的局部,最左边黄色局部是业务代码,两头这部分就是 C ++ 转 Python 的交互引擎调用。这种形式的实质就 C ++ 的开发引擎应用 PyBind 实现指定接口服务解释器,依据指定的数据序列化和反序列化形式进行操作,在函数调用时再实时转化为 python 的 Dict。

编译型:典型是 Golang 的应用形式。与 Python 的实现相似,右边灰色局部是 C ++ 开发的局部,最左边黄色局部是 Golang 业务代码,两头是 C ++ 转 Golang 的交互引擎。Golang 的实现相比 Python 的形式有点简单,实质是通过原生 CGO 作为用户接口,为了对立用户接口层,其实分成两局部:左半局部是间接跟 C ++ 交互,间接用 C ++ 实现负责把原生 C ++ 转化为根底的 C 类型的函数指针进行调用。右半局部应用 Golang 实现负责把原生序列化好的函数反序列化成业务构造体,而后再进行真正调用。

原生 C ++:这里很多人可能感觉奇怪,C++ 不是也是编译型的么,曾经有编译型的实现模式何必画龙点睛,减少这么一种实现模式,其实实质不然,golang 尽管是编译型语言,底层框架的实现因为尽量思考通用性,数据传递的过程中势必须要进行序列化和反序列操作,而在原生的 C ++ 的实现过程中咱们在实现的过程齐全摒弃所有的序列化和反序列操作,数据在本地队列中的传递齐全是业务的数据指针(而非序列化数据),而每个业务算子在解决数据过程中,间接依据原始的数据指针通过反射机制(实现形式有很多最简略的 map)能够间接获取对应列的数据项,整个过程无锁的超高效率。这里的外围优化思路 数据链式解决 过程。拉链上的每个算子,都共享同一个输出和输入。 每个算子,其实就是一个接口雷同的函数,这样就能够随便地调整函数指针的组合,造成不同的解决链。比方:一个申请走 A 模型排序,一个申请要走 B 模型排序,他们能够共享前序的算子,只在最初一个算子有所不同。在链式解决根底上,算子也能够是继承同一基类接口的派生类,或者 lambda 表达式。联合工厂模式等一些编程技巧,解决链的调整能够配置化、动态化、脚本化。实测执行业务单算子一般的纯数据项带分支的多节点的拓扑计算单机 (单线程 / 算子) 能够达到数十万的解决能力。

通过新计算引擎的实现从应用上齐全兼容上一代计算零碎的应用形式,将不常应用的性能做精简,同时优化简单拓扑执行形式,通过架构层也业务层解耦,反对多语言高效执行形式,对于老业务平迁的数据框架均匀计算效率进步5~10 倍,同时业务因为针对性建设业务框架业务开发效率进一步晋升。

智能管制实现

自动化问题剖析引擎是整个智能控制系统的大脑。它上游接管观测提供的原始数据,进行主动的剖析决策后,通过零碎提供的自愈能力解决。自动化问题剖析引擎的外围思路: 只有历史上呈现过的问题,RD 同学能找到问题和解决方案,就能够转化为零碎规定和后置函数梳理。那当下一次遇到问题则无需人工干预。规定引擎的外围剖析过程是 2 段式的:

阶段 1 : 传统配置化的规定引擎的配置(上图中右上角黄色局部),配置多个采集指标项的逻辑关系(与或交非),这里次要是针对问题的根底剖析性能, 断定规定是否触发。

阶段 2 : 基于这个根底剖析的后果,进行后置 Function 的执行剖析,这个次要是针对简单问题的剖析补充,最终执行引擎依据这个返回后果进行函数执行。

上面针对问题剖析引擎的执行后果如下:

  • 前提: 开发者须要配置好解决逻辑规定(以及规定依赖的数据项,必填)& 回调函数(选填)。
  • 数据解析器: 数据解析器次要承当的数据的原始抽取的工作,一共分成如下 3 步:

a. 配置解析: 逻辑执行依据开发者配置的数据信息解析;

b. 数据抽取: 依据解析进去的配置通过数据接口进行获取,能够从对立接口依据配置的信息从不同的介质充抽取所需要的信息;

c. 数据归一化: 将不同介质的原始数据归一化成为对立的数据格式供规定管理器应用。

  • 规定管理器: 规定管理器次要承当外围的逻辑剖析工作,一共分成如下几步:

a. 规定解析: 依据开发者配置的规定逻辑,将原始配置信息,解释成原始的规定树。

b. 执行计算: 依据数据解析器提供的数据后果和配置的函数规定别离执行计算。执行计算过程中最重要的就是根底分析器,整体提供了 5 大根底能力,数十种常见的逻辑计算来辅助规定配置。

c. 规定逻辑运算: 依据下层解析进去的规定树 和 每个数据项执行实现的计算结果进行逻辑运算,并依据执行的后果确定是否进行高级数据分析器,如果判断后果为真则依据所配置的后置函数进行解决。

  • 高级数据分析器: 如图所示有两种模式,对于简略根底剖析能够判断后果的,间接给默认的处理函数进行数据拓传;对于简略逻辑规定无奈精确表白的,开发者能够自定义后置剖析函数,函数会将原始数据和根底计算的计算结果作为参数传进去,开发者只须要通过解决后的数据形容分明剖析逻辑即可。
  • 动作执行器: 就是这个分析器的真正的执行引擎,依据规定运算的后果中蕴含的参数进行动静调整。

通过 智能控制系统的建设,月级别剖析解决上万的异样问题,主动复原的比例占总数的 95% 以上,绝大多数的问题几分钟内实现主动复原,外围故障同比缩小 60%(因为预处理避免一般问题好转成重大问题)。

04 论断以及瞻望

本文全篇以离线计算零碎的倒退为主线,贯通全文解说遇到的问题以及解决方案。尤其是以后新一代架构外围就是以数据 + 性能为外围的申明式的设计,配合高效计算引擎、配合智能化的设计,把整体的离线计算零碎的高度做了进一步晋升。设计中其实还是尽管解决了过来的很多问题,然而依然有不欠缺的中央,当然以后的成果还远没有达到最终的现实状态,局部零碎性能有待持续性的打磨降级。

——END——

举荐浏览

度加剪辑 App 的 MMKV 利用优化实际

百度工程师浅析解码策略

百度工程师浅析强化学

浅谈对立权限治理服务的设计与开发

百度 APP iOS 端包体积 50M 优化实际(五) HEIC 图片和无用类优化实际

正文完
 0