作者 | 弘远君

导读

本文以百度垂类离线核算体系的演进方向为主线,详细描绘查找垂类离线核算体系开展进程中遇到的问题,以及对应的处理方案。架构演进进程中一向奉行“没有最好的架构,只有最合适的架构”的宗旨,面临不同阶段遇到的问题,给出了适合的处理方案。尤其是近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图片和无用类优化实践