贴吧低代码高性能规则引擎设计

作者 | 贴吧UEG技术组

导读

本文首要介绍了规矩引擎的运用场景,引出贴吧规矩引擎。从组件、变量、规矩、处置四个模块介绍了规矩引擎的组成部分,一起对终究规矩文件的编译进程做了详细介绍。为了做到低代码,在规矩装备上做到渠道化,非研制同学即可完结。添加新的变量也只需求在变量渠道进行简略操作,无需额定的代码提交。别的结构层面支撑并行和异步的封装,在服务调用上也尽量做到削减代码,进步研制同学的功率。终究文章对贴吧规矩引擎做了总结,也供给了一些常见的运用场景和思路。

全文6951字,估计阅览时间18分钟。

01 布景

百度贴吧是一个具有10多年历史的UGC产品,在事务迭代中不免会有很多事务逻辑的代码,其间一部分事务逻辑用if-else等硬编码的办法开发,一部分引入了装备文件,经过装备文件的规矩去履行不同的事务逻辑。在某些运营活动或权益规矩中,需求频频添加或许更改一些规矩,这部分规矩经常变动的部分就需求规矩引擎来统一办理。

规矩引擎是一种专心于事务规矩的服务,它能够将事务规矩从代码中剥离出来,运用预先界说好的语义规范来完结这些剥离出来的事务规矩。规矩引擎经过接受输入的数据,进行事务规矩的评价,并做出事务决策。

因为规矩引擎将杂乱的事务逻辑从事务代码中剥离出来,所以能够明显下降事务逻辑完结难度;一起,剥离的事务规矩运用规矩引擎完结,这样能够使多变的事务规矩变的可维护,配合规矩引擎供给的杰出的事务规矩规划器,不必编码就能够快速完结杂乱的事务规矩,同样,即使是彻底不明白编程的运营或许产品人员,也能够运用图形化的界面来自界说规矩,完结代码一样的作用。

下面临一些需求运用规矩引擎的场景进行举例:

1、单规矩迭代

用户标签->包括A要害词->权益A

用户标签->包括A要害词->权益A

->包括B要害词->权益B

用户标签->身份豁免战略/机器账号->包括A要害词->权益A

->包括B要害词->权益B

用户标签->A模型成果大于1 ->豁C类用户->包括A要害词->权益C

可见跟着事务的发展,需求不断的调整权益规矩,这部分假如硬编码写死在代码中,需求频频上线,添加了作业量,而且跟着事务逻辑的增多,后期维护本钱增高。

2、持续接入新的才能

除了现在的字符串比较才能,一般的规矩引擎还会接入各式各样的模型才能,一般经过RPC的办法恳求不同的服务,跟着接入的服务越来越多,能够组合的规矩也是成倍的增长;

比方新接入图片模型识别后,一切图片识别的成果会过其他相关的模型,相关的模型调用逻辑就添加了一倍;

又如接入了某些模型,要根据模型的分数做相应的处理调整,需求频频的改动分值对应的处置手段,一起为了应对突发的场景,也需求频频的更改规矩。

这些操作假如没有一个主动化的规矩引擎,就需求把大量的规矩逻辑写在代码里,经过长时间的迭代,规矩变得十分臃肿,不管对后续的开发还是定位问题的功率都会带来问题。

02 贴吧规矩引擎组成部分

贴吧规矩引擎要做到规矩灵敏可配,无需研制介入,就需求尽可能的把包括判别逻辑的部分悉数下放到渠道,经过渠道的勾选对规矩进行完结。

贴吧低代码高性能规则引擎设计

上图为规矩引擎全体的模块区分,主要分为四部分:

  1. 组件服务:组件服务是对第三方服务的封装,比方调用图片模型服务、调用帖子特点等内容服务,一般是RPC调用;组件需求RD开发代码,但是贴吧规矩引擎的组件调用不掺杂业 务逻辑,仅仅是界说一个函数function,经过函数的入参调用第三方服务回来成果;

  2. 变量渠道:变量又称算子,是装备规矩的参数;变量分为事务调用时传的入参、运用组件回来的成果等。贴吧规矩引擎经过专用渠道办理变量,RD和PM均能够在渠道上装备变量;

  3. 规矩引擎:规矩引擎渠道涉及到了详细每一条规矩,经过图形化的界面生成规矩,该渠道不需求RD介入,经过渠道化的操作生成详细的规矩。

  4. 处置办法:该处置为RD定制化开发,针对帖子、用户或其他场景的召回处置处理。一般界说一个rpc恳求回调相关事务,处置办法因为是场景定制化的,所以这部分需求研制介入开发,但是处置办法更新的频率十分低,一般都是复用已有的才能。

2.1 组件服务

规矩引擎一切装备的数据不可能都是上游参数传递,很多是经过调用第三方服务获取;比方经过帖子id获取的帖子详情数据,经过用户uid获取用户的扩展特点,这儿都需求调用第三方服务;

组件的开发十分简略,只需求声明一个函数,并完结其静态办法。为了后续的功能考虑,函数声明时能够指定sync(串行)、async(异步)、parallel(并行)三种履行办法,贴吧规矩引擎会在调度的时分依照类型,运用更高效的办法履行对应的办法。

贴吧低代码高性能规则引擎设计

图中给出了一个demo组件,能够看出组件是不重视事务的,能够自界说入参和回来值,详细调用函数的进口及参数也不需求额定重视,更契合lib库或许util办法的完结办法,这种组件的优点是开发简略,解耦事务逻辑,添加组件的复用性,一起也下降了研制同学的作业量。

别的关于mode的作业模式,分为以下三类,详细的完结都是结构完结,组件的开发方不需求重视:

  1. sync:同步调用,运用的时分串行履行,函数间是阻塞的;

  2. async:异步调用,界说function的时分分为before、after两组办法。Before阶段为建议rpc恳求,等候第三方服务回调后履行after办法,能够应对好耗时的服务接入。

  3. parallel:并行模式,归于同一层级的parallel 函数并行履行,相似于多线程或许golang的goroutine模式,现在贴吧的规矩引擎选用php开发,不具备多线程的相关才能,所以这儿并行是在before拼装rpc参数,经过curl_multi统一建议并行恳求,在after函数取到成果。

以上才能在规矩引擎结构上现已封装,组件的研制RD只需求重视PRC的完结即可,根据函数的界说结构完结并行或许异步的调用。

2.2 变量渠道

变量或许算子便是规矩引擎中做规矩判别运用的参数,比方用户名、帖子id、用户等级、帖子内容、模型识别的成果等,这部分的内容越多,规矩引擎能够创建规矩的『资料』越多;

变量的来源分为三个部分:

**(1)渠道预界说的变量:**比方一些常量数字或许特定字符串,这部分内容比较固定,变动较少。

**(2)事务入参:**事务在恳求规矩引擎的时分能够把尽可能多的参数变量传递过来,除了帖子、用户、吧相关的数据,还能够把用户ip、ua等各种数据同时传递,这些数据在变量的渠道化界面上能够做简略的筛选或许摘取,生成新的变量。

贴吧低代码高性能规则引擎设计

如图举例:input是一个完结的事务恳求的变量,取input中的title生成testTitle变量,这样就能够单独运用testTitle做一些规矩上的判别。

**(3)组件调用:**在组件的部分现已界说了详细的办法,该办法相似于lib库或许util,详细的恳求的进口在变量渠道完结,入参便是其他变量。

贴吧低代码高性能规则引擎设计

如图举例:testRPC是界说的组件,其间入参是testTitle变量,回来的大成果作为一个testRPC变量。

后边能够对testRPC变量做详细的拆分,比方testRPC中的data.score作为一个单独的变量,用score这个变量做后边的规矩界说。

全体来说,input是上游传过来的根底变量。对入参变量的收拾和过滤能够生成额定的根底变量;运用根底参数(比方帖子id),经过rpc调用,能够生成扩展的成果;对成果的提取能够生成额定的第二级变量;进一步对二级变量持续调用服务,能够生成更多的变量:比方经过图片模型成果过一些文本模型,但是跟着层级的变深,全体服务呈现多级依靠关系,这也添加了全体的体系耗时。

贴吧低代码高性能规则引擎设计

关于入参或许RPC恳求成果的处理,悉数能够在变量渠道上进行操作,变量渠道界说了规矩引擎能够运用的变量及详细的完结办法。因为变量渠道支撑编辑代码,所以一般的变量都能够直接在变量渠道编辑完结,而对相对杂乱的模型调用,则能够封装通用的util办法,之后在变量渠道直接运用这些办法。

2.3 规矩引擎渠道

组件是一个个简略的util静态办法,经过入参及调用组件生成扩展的变量;自此进行规矩判别的『资料』准备好了,接下来需求运用这些变量装备规矩,而中心的规矩引擎渠道便是运用这些变量,生成规矩。

规矩引擎现在支撑的运算规矩:

  • 规矩运算符:现在支撑变量值与常量的比较,包括根本的>,<,>=,<=,==,!=多种比较办法;别的不仅能够直接运用变量,关于数组类型的变量,还能够直接运用了变量的计数count,关于string类型,能够运用变量的长度len做参数直接进行判别。

  • 词表比较:判别某个词是否在词表中是一个比较常用的规矩;规矩引擎渠道支撑本地词表与长途词表;长途词表为了处理词表量级太大的问题。

    字符与词表的比较包括准确匹配,包括、不包括、前缀匹配及后缀匹配几种办法,根本掩盖了常见的运用办法。

  • 粒度操控判别:为了判别某个调整在一段时间内的出现次数,渠道支撑装备变量的出现次数核算。

    关于某些运用频次较少的运算规矩,渠道不在功能上进行统一支撑,但是能够经过修正变量来支撑。比方想判别变量A的sin值大于Z,能够在变量渠道新装备一个变量B,它的定位为sin(A),然后在规矩引擎上运用B这个变量做判别,就处理了某些特别的核算办法。

    关于判别逻辑,现在支撑if条件判别,switch多分支判别,确认召回,确认豁免四种办法,根本包括了常用的判别逻辑。

贴吧低代码高性能规则引擎设计
△简略的战略装备demo

2.4 处置办法

处置办法是针对不同的事务场景召回的个性化处置逻辑,这部分需求RD开发代码,做个性化的处理;比方射中召回后回来true or false或许射中的规矩号或许回调特别标记。

处置办法添加的频率不会很高,根本固定对帖子、用户或许各个场景有1-2个处置办法即可,后续的多个规矩直接复用处置办法。

03 规矩引擎完结原理

规矩引擎终究生成是一个包括一切规矩逻辑的代码块,代码块在规矩引擎结构中运转;生成的代码块相似研制开发的代码:代码的逻辑依旧是界说变量、运用变量做条件判别(规矩)、射中召回的处置。

1. 变量

这部分比较简略了解,便是2.2部分;将一切界说的变量取出来,当然因为变量之间是递归依靠的,所以当变量中需求其他变量时,会递归获取内容,直到获取常量或没有依靠为止,终究倒序输出为代码片段。

2. 规矩文件生成

每一条规矩在存储上都是一个json串,存储办法为一个nodeTree。其间一个node节点存储了类型:判别节点、召回节点、豁免节点以及多组(switch)判别节点。其间召回节点和豁免节点是程序判别的停止位置,当履行到召回节点时会加载规矩引擎对应的处置办法。判别节点是整个规矩引擎的中心,包括对应的变量与比较办法。其间比较办法有数字比较、字符串比较及词表比较。比方内容中是否包括要害词“AB”,则在判别节点上选取内容变量,比较办法为词表包括,词表内容为“AB”。

在规矩文件的规划上,选用nodeTree的办法,既能便利后续扩展node的特点和类型,又经过父子节点树的办法多层级的表明杂乱的if、switch逻辑,层级能够无限深。

在新的规矩上线时,将nodeTree文件从数据库中悉数导出,生成悉数的规矩文件。规矩文件依靠的变量现已在变量文件中悉数界说好,剩余的作业便是将变量与规矩进行拼装,生成终究的可履行代码。

别的关于某些特别的需求,需求对白名单中的uid或许类型进行悉数战略豁免。关于此类需求能够修正一切的规矩,添加前置判别逻辑,但是此操作需求对现有的悉数规矩及增量规矩都修正,且在规矩履行中会添加额定的判别逻辑,添加全体规矩引擎的履行耗时,所以除了一般的规矩外,贴吧规矩引擎添加了大局规矩区。大局规矩区相当于一切规矩的前置条件,详细装备的规矩为一般的node判别节点,当大局的一切规矩判别均为true时才会依次履行详细的一般规矩,这样关于想大局豁免的需求,只需求简略装备大局规矩即可,不需求修正详细的详细规矩。

3. 生成可履行规矩文件

规矩引擎的前期编译作业需求生成能够履行的代码,这部分便是将图形化装备的规矩与变量进行组合,优化全体的代码履行逻辑,生成可履行的代码,将文件下发到一切的线上机器。

其间变量文件是能够履行的php语法,规矩为导出的json文件,需求将不同类型的文件进行组合,这儿需求将不同文件源转为同一种结构化数据。

关于原本是php语法的文件,贴吧规矩引擎选用ply和yacc进行词法和语法的解析,对php语法中array、函数、赋值、条件判别、运算符等进行提取,转为结构化的数据。

关于规矩文件,因为是预先界说好的json nodeTree,包括的格局是有限可枚举的,只要将每种类型与规矩映射为结构化的字段,就能够将规矩文件转位目标结构化数据。

之后便是可履行文件的生成进程,详细需求以下过程:

贴吧低代码高性能规则引擎设计

语法树打开:经过递归调用,将函数嵌套打开。比方res = funA(funB(params))打开为tmp1=funB(params))打开为 tmp1 = funB(params);res = funA(tmp1);打开后将高阶函数打开成一般函数,便利后续的优化处理。

接下来便是句子优化部分:

将不同变量重名的部分主动添加_n后缀,防止变量的彼此掩盖;遍历全体规矩中运用的变量,假如存在变量从未运用过,从全体代码中去除;关于界说了多遍重复的函数调用,全体去重只保留一份;对并行或许异步办法的函数组拆分红真正可履行的静态办法。经过以上过程,对即将生成的终究规矩文件进行了初步的收拾及优化。

在组件服务中提到了异步函数async;关于某些耗时十分高的模型服务,异步函数的作用是触发调用后完毕,等候第三方服务回调。

关于运用异步函数的状况,至少拆分红两步,第一步建议触发,第二步收到模型回调,取到该过程的成果作为变量,一切依靠该变量的规矩只能放到第二步履行。假如有函数依靠第二步的成果,则过程会持续添加,该函数取某变量的异步成果,建议服务恳求,第三步回调收到成果;异步函数打开的作用是将一切无依靠的异步函数恳求办法统一放在一起,并行恳求,经过回调触发履行第二步的规矩逻辑。这样贴吧规矩引擎能够很便利的接入高耗时的模型服务。

除了异步函数,还存在一种parallel并行调用的办法。因为规矩引擎选用php的言语选型,没有其他言语便利的多线程或许协程调用办法,关于无依靠的函数不能支撑并行调用,所以在规矩引擎的规划上经过curl_multil并行rpc调用服务的办法来削减耗时。

现在比较耗时的函数一般是恳求数据库服务或许第三方服务,这儿将数据库及第三方的调用悉数封装为http协议的办法,在战略文件调用上经过before办法收拾入参,经过相似curl_multil的办法并行调用服务,取到成果后履行各自函数的after办法,收拾函数对应的变量,这样就将无依靠关系的调用进行了并行处理,全体下降了耗时。并行函数兼并便是结构层面做的主动化兼并,规矩引擎的研制同学只需求简略界说before和after办法,编译阶段就会主动将一切无依靠的函数before办法履行,拼装rpc恳求。假如某些函数在before阶段依靠其他服务的成果,那么这批函数将在第2次建议恳求,即无任何依靠的函数先建议并行恳求,依靠第一批成果的函数再建议第2次并行恳求,以此类推,最大极限的运用并行调用的办法。

贴吧低代码高性能规则引擎设计

终究生成的可履行的文件,根本的最小单元为name、func、param、cond四组字段组成。假如cond判别条件为真,则name经过函数和入参数履行对应办法,产出值;该值又是其他单元的条件变量或许函数入参,这样由上到下依次履行,完结了一切规矩的履行。

依然以上述demo战略为例:

贴吧低代码高性能规则引擎设计

终究生成了四组单元,根本格局如下:

贴吧低代码高性能规则引擎设计

如图所示,根据上述的规矩,只需求四组根本单元,每一组经过函数核算成果,下一组的条件依靠成果的值,假如走到“召回”逻辑,则进行表明规矩射中,回来对应的规矩号及其处置办法,结构中根据处置办法履行对应的逻辑。

每一个规矩都是上述根本单元组成,终究将nodeTree中的悉数规矩生成根本单元,文件下发到一切运转的机器上,至此完结了规矩文件的产出与规矩上线。

04 总结

贴吧规矩引擎调配图形化的界面,十分便利非技术同学装备事务规矩,将冗余的事务逻辑悉数保管在规矩引擎渠道上,无需代码开发,即可上线或许修正规矩。

别的结构层面将异步、并行等杂乱逻辑进行了封装,研制同学调用新的模型只需求依照模版修正简略的参数收拾及回来数据收拾,即可完结并行或许异步的操作,削减规矩引擎的履行耗时。关于变量成果的转换,也能够经过变量办理渠道,在渠道上简略的修正即可完结一些根本的收拾逻辑,大大削减代码的开发量。

经过规矩引擎,能够灵敏装备运营活动中的抽奖规矩、用户身份权益装备、商品价格等包括杂乱事务逻辑判别的部分,将规矩抽象出来,解放研制同学的人力,一起规矩在渠道上能够便利查找和定位,便利后续的维护。

——END——

引荐阅览

浅谈权限体系在多利熊事务应用

分布式体系要害途径推迟剖析实践

百度工程师教你玩转规划模式(装修器模式)

百度工程师带你体验引擎中的nodejs

揭秘百度智能测验在测验定位范畴实践

百度工程师带你探秘C++内存办理(ptmalloc篇)