复杂事件处理(Complex Event Processing,以下简称CEP)在闲鱼内得到了广泛应用,基于用户使用闲鱼的实时行为,为用户提供更加丰富的优质信息与服务。闲鱼技术公众号有介绍过CEP在服务端和客户端上的设计与实现。然而之前的设计方案都只适用于闲鱼App端内场景,针对端外投放拉新场景(例如用户访问了多个商品详情页之后给用户发放优惠引导用户下单)需要设计在纯前端环境执行的实时CEP框架。本文主要介绍了在前端实现CEP的相关设计与实现。
整个流程可以抽象为用户实时行为按照一系列规则匹配之后,以前台UI的方式对用户进行触达干预。对外投业务场景进行抽象,除了CEP基础能力之外,还有这三点关键设计目标:
将业务流程拆解为三部分,分别是用户实时行为采集、对实时行为按照规则复杂计算、以前端UI组件进行用户触达,对应三个核心模块:事件采集、复杂计算和用户触达。针对上述设计目标,为了实现触达实时,将对行为的复杂计算放到前端去执行;为了实现策略动态,设计了一个服务端运营平台管理所有策略,采集行为信息、复杂计算规则、触达组件信息都从服务端获取;为了实现多容器,将实时行为采集和UI组件触达进行标准设计,分不同容器环境实现。此外由于策略会存在跨页面的场景,底层会有数据同步模块同步行为数据和计算状态。下面分别对重要模块进行详细介绍。
事件采集模块将用户行为转化为标准事件。首先是用户行为无侵入采集,无侵入采集是为了解决两个问题,第一个是为了让业务开发接入更加简单,不需要手动调用采集代码;第二个是为了覆盖更多可能的采集点,利于后续策略动态下发。这里我们选用静态扫描代码的方式,在具有特定行为标示(例如onClick)的元素节点上注入采集参数,采集参数通过元素样式名称、组件名称、文件路径等信息生成,具有比较好的语义;并且和运行时无关,更利于扩展不同容器实现。
初期先定义了用户基础操作行为(enter、leave、scroll、appear、click),用户行为多样并且形态复杂,因此首先需要将用户行为做标准化处理。此外随着业务使用后续有一些业务模块也要事件形式进入计算,例如http请求返回的结果也会作为一个事件,因为这里设计了一个插件机制,能够让业务模块快速转化成标准行为。
目前社区前端复杂计算相关方案都比较简单,不适用于业务场景。自研上选择参考业界CEP标准实现,业界CEP设计主要源于这篇论文Efficient Pattern Matching over Event Streams,在这篇文章里介绍了CEP的核心是NFA(不确定的有限状态机),CEP的匹配过程就是NFA状态变化的过程。因此首先在前端实现了一个NFA类,实现这样一个状态机。
但是我们无法直接创建一个NFA去描述匹配规则,更习惯按照事件间关系与每个事件的匹配规则去定义,因此需要在上层封装一套API来创建NFA。这里参考了Flink CEP Pattern API的设计。通过next/followedBy/followedByAny/notNext/notFollowedBy等API来定义事件间关系,通过where/and/or等API来定义每个事件的匹配规则。通过Pattern定义会生成一个中间链表,生成NFA的过程就是反向解析这个链表。
前端做复杂计算我们总会担心性能是否有问题。以下面这个性能压测为例,有20个策略在做匹配的情况下,一次灌入200条行为数据,整体耗时在3.73s。虽然时间并不是特别长,但是由于浏览器运行机制,JS引擎线程在执行的情况下,UI渲染线程也会被挂起,在这3.73s内用户所有在页面上的操作都得不到响应,感觉就是“卡住了”。因此前端复杂计算性能优化更多需要考虑计算过程中不能影响用户体验。
对比目前业内的解法,Worker和Webassembly存在容器限制以及优化效果可能不明显。这里选用了一种时间切片的解法,整体思路和React Fiber机制比较类似。将复杂计算的大任务拆解为小任务执行,在小任务执行完之后,会适当让出JS主执行线程的控制权,让浏览器能够响应用户操作,保证用户操作不受影响。下面这张图是优化后的效果,可以看到每个任务执行之后有一段空闲。并且这个优化方式是纯JS层面的优化,不受单一容器的限制。
用户触达模块管理用户前台展示组件,出于对bundle大小的考虑,组件代码都通过动态加载的方式。由于需要针对不同容器实现,在上层统一标准组件的设计,包括统一组件API、输入数据源以及埋点信息等。组件相关设计最终会影响各容器实现成本和业务效果统计。
由于跨页面场景(例如访问了详情页又访问了这个卖家的闲鱼号)存在,而前端多个页面之间不具备通信能力,也不存在一个线程在后台一直处理业务逻辑,因此在行为数据以及计算状态的同步上需要依赖本地存储能力。前端本地存储都只支持Key/Value存储,能力相对较弱,频繁读写数据容易出错。因此在本地存储上层实现一层内存缓存,扩展了一些存储能力,每隔一段时间或者在一些时间节点上(例如离开页面)和本地存储同步,这样既保证了存储的灵活性,又实现了跨页面数据同步。
目前该前端CEP框架已投入线上业务使用,在阿里小程序、Weex、Web下都能良好运行,并且提供了一定的运营配置能力,在目前线上单一策略下整个流程可以在毫秒级内完成,后续在业务上会有更广泛的使用。
在技术细节以及业务易用性上,我们依然有很多可以完善的地方,后续的一些演进方向如下:
领取专属 10元无门槛券
私享最新 技术干货