决策引擎服务是风控系统的大脑,承载着风控策略编排和计算的任务,对决策的时耗和精度有着严格的要求,本文以决策流执行路径实现方案为切入点,一窥风控决策引擎高效的原理。
在上文 风控决策引擎——决策流构建实战 中详细介绍了风控决策引擎的发展历程,决策流的编排能力,满足了策略运营人员对当前风险场景下的防控策略足够灵活、高效的部署。
“灵活”往往意味着不可控,从多年的开发经验中来看,产品的功能在既定的范围内,基本不会出现不可控的问题(除非是 BUG)。像 SQL 查询语言,对数据分析人员来说非常的灵活,抽象的语法可以满足任何数据组装查询组装需求,但此时危机正在蔓延:随时可能出现一个慢查询导致性能问题!
**“灵活”和“高效”往往在程序内是互斥的,足够的灵活,往往是牺牲一定的效率得到的。**研发人员能做的,就是在两者中博弈,找到最佳平衡。
流程图看似简单,但是在实际执行程序执行过程中会遇到各种各样的问题和挑战,根因还是上下游业务对风控决策执行的耗时有严格的控制要求。
此阶段就像一个工作审批流,从开始节点一步一步的往下串行执行,直到终点。决策过程中,完全依赖节点路径的复杂度,假设一个节点的平均耗时为 100ms,那么如下红色执行路径需要耗时 500ms。
500ms 对风控来说是比较奢侈的,整个业务线一次请求耗时可能大半时间都被我们消耗掉了,这显然是不能接受的。可以想象,随着业务场景越来越复杂,策略人员对决策流的编排复杂度越来越高,导致整个决策流的决策路径越来越长,耗时呈线性增长,这种技术实现方案肯定是不能接受的。
总结:
活干不完,咱就堆人。同样的,一个线程干不完的,咱就堆线程并发计算。
本着空间换时间的思想,预先将决策流内的节点全部预加载完成,将结果缓存住,真正执行决策流的时候,请求缓存直接计算执行,大大节省了决策时间。
此时影响决策性能的卡点在最耗时的那个节点,只需集中人力解决掉这个节点的性能问题就能降低决策流执行时间了。
总结:
方案二除了不考虑成本问题外,最大的痛点在于依赖关系问题,这是致命的。此时需要在运行时动态分析决策流节点之间的依赖关系。
从图中可以看出,节点 C 依赖节点 A,节点 D 依赖节点 B,其它节点相互不依赖,那么此时可以通过依赖分析出节点与节点之间的分组关系,通过分组头结点先后顺序串行执行。
那么如何实现节点的依赖分析及先后执行顺序呢?
流程图本身可以就是一个 DAG(有向无环图),节点执行的先后顺序可以用 **BFS(广度优先遍历)**遍历出一维数组,然后遍历分析每个节点的入参和之前的节点的出参是否有关联,有关联的归并到之前节点组链表的“尾巴上”,否则即为不依赖,可并行执行。
此时整个决策流执行耗时情况如下:
决策流执行耗时 = 并行组1耗时 + 并行组2耗时 + ... + 并行组 N耗时
总结:
方案 2、3 都是全量并行加载各节点数据,对算力和成本的消耗是巨大的,实际在运行的过程中,公司在成本这块肯定是不能接受的,可能资损召回都不定能抵得上服务器和外部资源的开销。
通过分析决策流图,可以发现,分流节点的功能是排它,即决策数据流向只会选择一条路径执行,那么此时我们能在并行执行之前确认哪些路径在当次决策请求中不会经过,则可以排除掉不会经过路径上的节点,从而减少不必要的算力和成本。
排它网关剪枝如上图,优先找出排它网关节点 S1, S2,分析入参是否依赖上游节点,此时 S1 依赖节点 B,S2 无依赖,则可按照排它节点分组并发执行决策出排它路径,此时 S1 节点对应的节点 C 被“剪枝”,S2 节点对应的节点 G 被“剪枝”。
总结:
按照方案 4,已经解放了一大部分不会走到分支的算力,但是在正确的决策路径上,依然存在浪费,举例如上:
此时,需要标识出付费节点(或者任何需要控制资源的节点),改为懒加载模式,即在前置并发加载所有节点时剔除懒加载节点,在决策流路径真正执行到该节点时再去计算,确保调用了一定是有效的,此时,构建节点时需要区分设置节点类型是饿汉式 or 懒汉式。
总结:
本文梳理了决策引擎编排决策流过程中为了提高决策性能和节约成本上做出的一些列优化方案,针对不同的场景,可自由选择激进的方案 or 性能和成本兼顾的方案。
研发是站在产品规划的角度去思考实现方案的,脱离规划的设计再好,也不能真正的落地,谨记。
欢迎关注公众号:咕咕鸡技术专栏
个人技术博客:https://jifuwei.github.io/