当前位置: 首页 > 科技观察

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

时间:2023-03-21 18:36:33 科技观察

1.背景百度贴吧是一款拥有10多年历史的UGC产品。业务迭代中难免会有大量的业务逻辑代码,其中有一些是用if-else等硬编码的,在开发的形式上,引入部分配置文件,执行不同的业务逻辑通过配置文件的规则。在一些经营活动或股权规则中,有些规则需要经常添加或更改,而这些规则中经常更改的部分需要规则引擎统一管理。规则引擎是一种专注于业务规则的服务。它可以将业务规则从代码中分离出来,并使用预定义的语义规范来实现这些剥离的业务规则。规则引擎评估业务规则并通过接受输入数据做出业务决策。由于规则引擎将复杂的业务逻辑从业务代码中分离出来,可以显着降低业务逻辑的实现难度;同时,剥离后的业务规则使用规则引擎实现,可以让多变的业务规则变得可维护,配合规则引擎提供的优秀的业务规则设计器,无需编码即可快速实现复杂的业务规则。同样,即使是完全不懂编程的运营人员或产品人员,也可以使用图形界面自定义规则,实现相同的代码。影响。以下是一些需要使用规则引擎的场景示例:1.单次规则迭代用户标签->包含A关键字->受益A用户标签->包含A关键字->受益A->包含B关键字->权限B用户标签->身份免除策略/机器账号->包含A关键字->权限A->包含B关键字->权限B用户标签->A模型结果大于1->免除类型C用户->包含关键字A->权益C可见,随着业务的发展,权益规则需要不断调整。如果这部分硬编码在代码中,需要频繁上线,增加了工作量,而且随着业务逻辑的增加,后期维护成本增加。2.不断接入新的能力除了目前的字符串比较能力,通用规则引擎还会接入各种模型能力,一般会以RPC的形式请求不同的服务,随着接入的服务越来越多,你可以获取的规则也越来越多combine,可以组合的规则越多。例如,识别一个新连接的图像模型后,所有图像识别的结果都会通过其他相关模型,相关模型调用逻辑会加倍;有些模型需要根据模型的分数进行处理和调整。需要根据分数经常更换相应的治疗方法。同时,为了应对突发情况,也需要经常更改规则。这些操作如果没有自动化的规则引擎,需要在代码中编写大量的规则逻辑。经过长时间的迭代,规则变得非常臃肿,无论是对后续开发还是定位问题的效率都会带来问题。2.贴吧规则引擎的组件为了使贴吧规则引擎的规则灵活可配置,不需要研发介入,需要尽可能将包括判断逻辑在内的所有部分委托给平台,并且通过检查平台来执行规则。上图展示了规则引擎的整体模块划分,主要分为四个部分:组件服务:组件服务是对第三方服务的封装,比如调用图片模型服务,调用post属性等内容服务,一般是RPC调用;组件需要RD开发代码,但是贴吧规则引擎的组件调用并没有混合业务逻辑,只是定义一个function函数,通过函数的入参调用第三方服务返回结果;变量平台:变量,又称运算符,是配置规则的参数;变量分为业务调用传入的输入参数、使用组件返回的结果等。贴吧规则引擎通过专用平台管理变量。RD和PM都可以在平台配置变量;规则引擎:规则引擎平台涉及每条具体的规则,通过图形化界面生成规则。该平台不需要RD干预。优化操作生成特定规则。处置方式:该处置是RD的定制化开发,针对帖子、用户或其他场景的召回进行处理。一般会定义一个rpc请求来回调相关业务。因为处理方式是针对场景定制的,所以这部分需要研发介入开发。但是处理方法的更新频率很低,一般都是复用已有的能力。2.1组件服务规则引擎的所有配置数据都不能通过上游参数传递,很多是通过调用第三方服务获取的;比如通过帖子id获取的帖子详情数据,通过用户uid获取用户的扩展属性,这里需要调用第一个三方服务;组件开发非常简单,只需声明一个函数并实现其静态方法即可。为了后续的性能考虑,可以在声明函数时指定sync(串行)、async(异步)、parallel(并行)三种执行模式。贴吧规则引擎在调度时会根据类型更高效的执行相应的功能。方法。图中显示了一个演示组件。可以看出组件不关注业务,可以自定义输入参数和返回值。具体调用函数的入口和参数不需要关注,更符合lib库或util方法的实现。该组件的优点是易于开发,解耦业务逻辑,增加组件的复用性,减少研发同学的工作量。另外,模式的工作方式分为以下三类。具体实现为框架实现,组件开发者无需关注:sync:同步调用,使用时串行执行,函数间阻塞;async:异步调用和定义一个函数时,分为两组方法:before和after。Before阶段发起RPC请求,等待第三方服务回调后执行after方法,可以应对耗时的服务访问。并行:并行模式。属于同一层级的并行函数并行执行,类似于多线程或者golanggoroutine模式。目前贴吧的规则引擎是用php开发的,不具备多线程的相关能力,所以这里的parallel就是在before组装rpc参数,通过curl_multi发起并行请求,在after函数中得到结果。以上能力已经封装在规则引擎框架中,组件的研发只需要专注于PRC的实现,根据函数的定义框架实现并行或异步调用。2.2变量平台变量或运算符是规则引擎中用于规则判断的参数,如用户名、帖子id、用户级别、帖子内容、模型识别结果等,这部分内容越多,规则引擎可以创建规则“材料”越多;变量的来源分为三部分:(1)平台预定义变量:比如一些常量或者特定的字符串,这部分内容比较固定,变化较少。(2)业务入参:业务向规则引擎请求时,可以传递尽可能多的参数变量。除了post、user、bar相关数据外,还可以传递用户ip、ua等各种数据。这些数据可以在变量平台接口上进行简单的过滤或提取,生成新的变量。比如如图:input是一个完成的业务请求的变量,取input中的title生成testTitle变量,这样就可以单独使用testTitle做一些规则判断。(3)组件调用:在组件部分定义了具体的方法。这个方法类似于lib库或者util。具体请求入口在变量平台上实现,入参为其他变量。如示例所示:testRPC为定义组件,其中入参为testTitle变量,返回的大结果作为testRPC变量。您可以稍后拆分testRPC变量。例如testRPC中的data.score作为一个单独的变量,score变量用来定义如下规则。总的来说,输入是上游传递的基本变量。输入变量的排序和过滤可以产生额外的基础变量;使用基本参数(如postid),通过rpc调用,可以生成扩展结果;结果的提取可以产生额外的二级变量;furtherLevel变量继续调用服务,可以产生更多的变量:比如一些文本模型通过图像模型传递,但是随着层级越来越深,整体服务呈现多级依赖,也增加了整体系统时间消耗。对于入参或RPC请求结果的处理,所有的操作都可以在变量平台上进行。变量平台定义了规则引擎可以使用的变量和具体的实现方式。因为变量平台支持代码编辑,一般的变量可以直接在变量平台上编辑,对于比较复杂的模型调用,可以封装通用的util方法,然后这些方法直接在变量平台上使用。2.3规则引擎平台组件是一个简单的util静态方法,通过传入参数调用组件生成扩展变量;至此,规则判断的“素材”准备好了,接下来就需要使用这些变量来配置规则,而核心的规则引擎平台就是使用这些变量来生成规则。规则引擎目前支持的运算规则:规则运算符:目前支持变量值和常量的比较,包括基本的>、<、>=、<=、==、!=多种比较方式;另外,不仅可以直接使用变量,对于数组类型的变量,也可以直接使用变量的count,对于string类型,可以直接使用变量len的长度作为参数直接判断。词汇比较:判断一个词是否在词汇表中是常用的规则;规则引擎平台支持本地词表和远程词表;远程词汇是为了解决词汇量过大的问题。字符和词汇的比较包括精确匹配,包括但不包括前缀匹配和后缀匹配,基本涵盖了常用的使用方法。粒度控制判断:为了判断某个调整在一定时间内出现的次数,平台支持对配置变量出现次数的统计。对于一些使用频率较低的计算规则,平台在功能上不提供统一支持,但可以通过修改变量的方式支持。比如要判断变量A的sin值是否大于Z,可以在变量平台配置一个新的变量B,定位为sin(A),然后用变量B进行判断在规则引擎上,它解决了一些特殊的计算方式。判断逻辑目前支持if条件判断、switch多分支判断、召回确认、豁免确认四种方式,基本涵盖了常用的判断逻辑。△简单策略配置demo2.4处置方式处置方式是针对不同业务场景召回的个性化处置逻辑。该部分需要RD开发代码进行个性化加工;例如,在命中召回数或回调特殊标记后返回true或false或命中规则。添加处理方法的频率不会很高。基本上,帖子、用户或者每个场景都有1-2种处理方式。多个后续规则直接复用处理方法。3.规则引擎实现原理规则引擎的最终生成是一个包含所有规则逻辑的代码块,代码块运行在规则引擎框架中;生成的代码块和R&D开发的代码类似:代码的逻辑还是定义变量,用变量做Condition判断(rule),hitrecall处置。1.变量部分比较好理解,就是2.2部分;取出所有定义的变量,当然,因为变量是递归依赖的,所以当变量中需要其他变量时,会递归获取内容,直到常量或者没有依赖为止,最后输出的是代码片段以相反的顺序。2.规则文件的生成每条规则都以nodeTree的形式存储为一个json字符串。其中一个节点节点存储类型:判断节点、召回节点、免责节点、多组(切换)判断节点。其中召回节点和免除节点是程序判断的终止位置。执行召回节点时,会加载规则引擎相应的处置方法。判断节点是整个规则引擎的核心,包括相应的变量和比较方法。比较方法包括数字比较、字符串比较和词汇比较。例如内容是否包含关键词“AB”,在判断节点上选择内容变量,比较方式为词表包含,词表内容为“AB”。在规则文件的设计中,采用了nodeTree的方法,这样既可以方便后续扩展节点属性和类型,又可以通过父子节点树在多层次表达复杂的if和switch逻辑,层次可以无限深。当一条新规则上线时,从数据库中导出所有的nodeTree文件,生成所有的规则文件。规则文件所依赖的变量已经在变量文件中全部定义好了,剩下的工作就是将变量和规则进行组装,生成最终的可执行代码。另外,对于一些特殊的需求,需要对白名单中的所有uid或者type进行豁免。对于这样的需求,可以修改所有的规则,增加预判断逻辑,但是这个操作需要修改所有已有的规则和增量规则,在规则执行的时候会增加额外的判断逻辑,增加整体的规则引擎。执行是比较耗时的,所以贴吧规则引擎除了普通规则外,还增加了全局规则区。全局规则区相当于所有规则的前置条件。具体配置规则为普通节点判断节点。当所有的全局规则判断都为真时,将依次执行具体的普通规则。这样对于全局豁免的需求,只需要简单配置全局规则即可,不需要修改具体的细则。3.生成可执行规则文件规则引擎的预编译工作需要生成可执行代码。这部分是结合图形化配置的规则和变量,优化整体代码执行逻辑,生成可执行代码,并将转换后的文件发送给所有在线机器。其中,变量文件是可执行的php语法,规则是导出的json文件。需要组合不同类型的文件。这里需要将不同的文件源转换成相同的结构化数据。对于原本是php语法的文件,贴吧规则引擎利用ply和yacc进行词法和语法分析,将php语法中的数组、函数、赋值、条件判断、运算符等提取出来,转化为结构化数据。对于规则文件,因为是预定义的jsonnodeTree,所以包含的格式是有限的,可枚举的。只要将每个类型和规则映射到一个结构化字段,就可以将规则文件转置为目标结构化数据。之后就是可执行文件的生成过程,需要以下步骤:语法树扩展:通过递归调用,扩展函数嵌套。例如,res=funA(funB($params))被扩展为tmp1=funB($params);res=funA(tmp1);展开后将高阶函数展开为普通函数,便于后续优化处理。接下来是语句优化部分:自动为不同变量的同名部分加上_n后缀,避免变量相互覆盖;遍历全局规则中使用的变量,如果有变量没有使用过,则将其从全局代码中移除;for定义了多次重复的函数调用,只保留一份进行整体去重;并行或异步方法的功能组被拆分为真正可执行的静态方法。经过以上步骤,初步整理优化了最终要生成的规则文件。组件服务中提到了异步函数async;对于一些非常耗时的模型服务,异步函数的作用是触发调用结束,等待第三方服务的回调。对于使用异步函数的情况,至少应该拆分成两步。第一步发起触发器,第二步接收模型回调,将这一步的结果作为变量。所有依赖这个变量的规则只能放在第二步。实施。如果有函数依赖第二步的结果,则步数会继续增加。函数取一个变量的异步结果,发起服务请求,第三步回调接收结果;异步函数扩展的作用是将所有异步函数没有依赖的请求方法统一放在一起,并行请求,通过回调触发第二步的规则逻辑。这样,贴吧规则引擎就可以轻松接入耗时的模型服务。除了异步函数,还有一种并行调用的方式。由于规则引擎使用PHP语言选择,其他语言没有方便的多线程或协程调用方式,没有依赖的函数不支持并行调用。因此在规则引擎的设计中,使用curl_multil并行rpc调用服务来减少耗时次数。目前,耗时函数一般会请求数据库服务或第三方服务。这里所有的数据库和第三方调用都以http协议的形式进行封装,通过policy文件调用上的before方法整理参数,并通过类似curl_multil的方法并行调用服务,执行after方法每个函数在得到结果后,将函数对应的变量组织起来,使得无依赖的调用并行处理,整体时间消耗减少。并行函数合并是框架级别的自动合并。规则引擎开发者只需要简单定义before和after方法,编译阶段会自动执行所有不依赖的functionbefore方法组装rpc请求。如果前阶段有函数依赖其他服务的结果,那么这批函数会进行二次发起请求,即没有依赖的函数先发起并行请求,依赖的函数会先发起并行请求第一批结果会发起第二个并行请求,以此类推,最大限度地利用并行调用。在最终生成的可执行文件中,基本的最小单元由四组字段组成:name、func、param、cond。如果cond判断条件为真,则name通过函数和入参执行对应的方法,并输出一个值;这个值是其他单元的条件变量或函数输入参数,所以从上到下依次执行,完成所有规则的执行。仍然以上面的demo策略为例:最终生成四组单位,基本格式如下:如图所示,根据上面的规则,只需要四组基本单位,每组通过函数计算结果,下一组的条件取决于如果结果的值达到“召回”逻辑,则表示规则命中,返回对应的规则编号及其处置方法,并执行对应的根据处理方法在框架中的逻辑。每条规则均由上述基本单元组成。最后将nodeTree中的所有规则生成为基本单元,并将文件发送给所有运行的机器。至此,规则文件的输出和规则上线已经完成。4.总结贴吧的图形化界面规则引擎非常方便非技术同学配置业务规则,所有冗余的业务逻辑都托管在规则引擎平台上。无需开发代码即可上线或修改规则。此外,在框架层面封装了异步、并行等复杂逻辑。研发同学只需根据模板修改简单的参数排序和返回数据排序即可完成并行或异步操作,减少规则引擎的执行时间。.对于变量结果的转换,也可以使用变量管理平台,在平台上进行简单的修改即可完成一些基本的排序逻辑,大大减少了代码开发量。通过规则引擎,可以在运营活动中灵活配置抽奖规则,配置用户身份权限、商品价格等包含复杂业务逻辑判断的部分,将规则抽象出来,解放研发同学的人力。定位方便后续维护。