网站首页 > java教程 正文
一、背景
在运营实时触达需求中,存在如下具有代表性的业务场景:
用户在X分钟内发生A行为次数大于等于Y次
用户在A行为前24小时内未发生B行为
用户在A行为后30分钟内未发生B行为
本文以该典型实时运营场景为例,围绕如何设计出可支撑业务需求高效、稳定运行的系统进行展开。
二、技术调研
规则引擎的必要性
提高灵活度需要从业务规则和系统代码解耦和入手,规则和代码耦合直接导致了重复代码增多、业务规则修改困难等问题。那如何将业务规则和系统代码解耦和呢?我们想到使用规则引擎解决这一问题。
规则引擎调研
在设计规则引擎前,我们对业界已有的规则引擎,主要包括Esper和Drools,进行了调研。
Esper
Esper设计目标为CEP的轻量级解决方案,可以方便的嵌入服务中,提供CEP功能。
优势
- 轻量级可嵌入开发,常用的CEP功能简单好用。
- EPL语法与SQL类似,学习成本较低。
劣势
- 单机全内存方案,需要整合其他分布式和存储。
- 以内存实现时间窗功能,无法支持较长跨度的时间窗。
- 无法有效支持定时触达(如用户在浏览发生后X分钟触达支付条件判断)。
Drools
Drools开始于规则引擎,后引入Drools Fusion模块提供CEP的功能。
优势
- 功能较为完善,具有如系统监控、操作平台等功能。
劣势
- 学习曲线陡峭,其引入的DRL语言较复杂,独立的系统很难进行二次开发。
- 以内存实现时间窗功能,无法支持较长跨度的时间窗。
- 无法有效支持定时触达(如用户在浏览发生后X分钟触达支付条件判断)。
由于业务规则对时间窗功能及定时触达功能有较强的依赖,综合以上两种规则引擎的优劣势,我们选用了相对SpEL更为轻量的表达式引擎Aviator,将流式数据处理及规则引擎集成至Storm中,由Storm保证系统在数据处理时的吞吐量,在系统处理资源出现瓶颈时,可在公司托管平台上调整Worker及Executor数量,降低系统水平扩展所需成本。
三、Aviator介绍
Aviator是一门高性能、轻量级的Java语言实现的表达式动态求值引擎。其设计目标是轻量级和高性能,相对于Groovy、JRuby的笨重,Aviator非常小,不过Aviator的语法受限,它并不是一门完整的语言,只是语言的一小部分集合。定位是介于Groovy这样重量级脚本语言和IKExpression这样轻量级表达式引擎之间。
Aviator的实现思路与其它轻量级的求值器不同,其它求值器是通过解释的方式运行,而Aviator是直接将表达式编译成Java字节码,交给JVM去执行。
功能
支持大部分运算操作符:算数运算符、关系运算符、逻辑操作符、正则表达式匹配操作符、三元表达式,支持操作符的优先级及括号的强制优先级
支持函数调用和自定义函数
自动类型转换,当执行操作时,会自动判断操作数类型并做相应的转换,无法转换就抛异常
支持传入变量,支持类似a.b.c的嵌套变量访问
限制:没有if else、do while等语句,没有赋值语句,没有位运算符;
使用场景
- 公式计算
- 动态脚本控制
- 规则判断以及规则引擎
如下: 将业务人员配置的规则转换成一个规则字符串,然后将该规则字符串保存进数据库中,当使用该规则时,只传递该规则所需要的参数,便可以直接计算出结果,开发人员无需再为这些规则编写任何代码。
public class AviatorRuleEngine {
// 规则可以保存在MySQL或Redis中
Map<Integer, String> ruleMap = new HashMap<>();
public AviatorRuleEngine() {
// 判断是不是资深顾客
ruleMap.put(1, "age >= 18 && sumConsume > 2000 && vip");
// 资深顾客要求修改
ruleMap.put(2, "age > 10 && sumConsume >= 8000 && vip && avgYearConsume >= 1000");
}
public static void main(String[] args) {
AviatorRuleEngine aviator = new AviatorRuleEngine();
// 选择规则,传入规则所需要的参数
log.info("公式1:" + aviator.getResult(1, 20, 3000, false));
log.info("公式2:" + aviator.getResult(2, 23, 8000, true, 2000));
}
public Object getResult(int ruleId, Object... args) {
String rule = ruleMap.get(ruleId);
return AviatorEvaluator.exec(rule, args);
}
}
输出结果:
公式1:false
公式2:true
四、技术方案
确定引入规则引擎后,围绕规则引擎的设计开发成为了系统建设的主要着力点。通过使用实时数据仓库中的用户实时行为数据,按业务运营活动规则,组合成有意义的复合事件,交由下游运营业务系统对事件的主体,也就是用户进行触达。将系统抽象为以下功能模块,如图所示:
总体来看,系统组成模块及功能如下:
- 规则引擎:集成于Storm拓扑中,执行运营活动条件转换成为的具体规则,作出对应响应。
- 时间窗模块:具有可选时间跨度的滑动时间窗功能,为规则判定提供时间窗因子。
- 定时触达模块:设定规则判定的执行时间,达到设定时间后,执行后续规则。
- 自定义函数:在Aviator表达式引擎基础函数之上,扩展规则引擎功能。
- 报警模块:定时检查系统处理的消息量,出现异常时为负责人发送报警信息。
- 规则配置控制台:提供配置页面,通过控制台新增场景及规则配置。
- 配置加载模块:定时加载活动规则等配置信息,供规则引擎使用。
其中,规则引擎由核心组件构成的最小功能集及扩展组件提供的扩展功能组成。由于规则引擎解耦了业务规则和系统代码,使得实时数据在处理时变的抽象,对数据监控、报警提出了更高的要求。下面我们将从规则引擎核心组件、规则引擎扩展组件、监控与报警三个方面分别进行介绍。
规则引擎核心组件
规则引擎核心组件为构成规则引擎的最小集合,用以支持完成基础规则判断。
规则引擎核心流程
引入规则引擎后,业务需求被转换为具体场景和规则进行执行,如图所示:
规则引擎在执行规则过程中,涉及以下数据模型:
- 场景:业务需求的抽象,一个业务需求对应一个场景,一个场景由若干规则组成。用不同的规则组成时序和依赖关系以实现完整的业务需求。
- 规则:规则由规则条件及因子组成,由路由至所属场景的事件触发,规则由规则条件、因子及规则响应组成。
- 规则条件:规则条件由因子构成,为一个布尔表达式。规则条件的执行结果直接决定是否执行规则响应。
- 因子:因子是规则条件的基础组成部分,按不同来源,划分为基础因子、时间窗因子和第三方因子。基础因子来源于事件,时间窗因子来源于时间窗模块获取的时间窗数据,第三方因子来源于第三方服务,如用户画像服务等。
- 规则响应:规则执行成功后的动作,如将复合事件下发给运营业务系统,或发送异步事件进行后续规则判断等。
- 事件:事件为系统的基础数据单元,划分为同步事件和异步事件两种类型。同步事件按规则路由后,不调用定时触达模块,顺序执行;异步事件调用定时触达模块,延后执行。
时间窗模块
时间窗模块是运营实时触达系统规则引擎中的重要构成部分,为规则引擎提供时间窗因子。时间窗因子可用于统计时间窗口内浏览行为发生的次数等,表中列举了在运营实时触达活动中需要支持的时间窗因子类型:
根据时间窗因子类型可以看出,时间窗因子有以下特点:
- 时间窗存储中需要以List形式保存时间窗详情数据,以分别支持聚合及详情需求。
- 时间窗因子需要天粒度持久化,并支持EXPIRE。
- 时间窗因子应用场景多,是许多规则的重要组成因子,服务承受的压力较大,响应时间需要在ms级别。
定时触达模块
定时触达模块支持为规则设定定时执行时间,延后某些规则的执行以满足运营活动规则。比如在用户在A行为后30分钟内未发生B行为条件中,需要在A行为发生X分钟后,对用户是否发生B行为进行判定,以排除用户自发产生B行为对活动效果造成的影响。
定时触达模块涉及的数据流图如图所示:
早期的业务需求对延迟时间要求较短,且活动总数量较小,通过维护纯内存DelayQueue的方式,支持定时触达需求。随着相关运营活动数量增多及定时触达时间的延长,纯内存方式对内存的占用量越来越大,且在系统重启后定时数据会全部丢失。在对解决方案进行优化时,了解到消息队列RocketMQ或RabbitMQ支持消息粒度延迟,非常贴合我们的使用场景,因此采用此特性,代替纯内存方式,实现定时触达模块。
监控与报警
对比离线数据,实时数据在使用过程中出现问题不易感知。由于系统针对的运营活动直接面向C端,在出现系统异常或数据质量异常时,如果没有及时发现,将会直接造成运营成本浪费,严重影响活动转化率等活动效果评估指标。针对系统稳定性问题,我们从监控与报警入手解决。
监控
利用公司数据平台现有产品,对系统处理的实时事件按其事件ID上报,以时间粒度聚合,数据上报后可实时查看各类事件量,通过消息量评估活动规则和活动效果是否正常。
报警
异常数据可以通过各类办公软件对应的机器人及时告警出来。
猜你喜欢
- 2024-10-25 Spring Boot 整合流程引擎 Flowable,so easy
- 2024-10-25 规则引擎重塑业务灵活性,但是你真的会用吗?
- 2024-10-25 Java表达式求值引擎Aviator(二)(java数学表达式解析)
- 2024-10-25 高德打车通用可编排订单状态机引擎设计
- 2024-10-25 NET RulesEngine(规则引擎)(规则引擎easy rule)
- 2024-10-25 25-规则引擎概述(使用规则引擎的优势)
- 2024-10-25 开启灵活开发编码模式:规则引擎drools——LHS部分
- 2024-10-25 21-规则引擎内容介绍(规则引擎使用案例场景)
- 2024-10-25 开源规则引擎LiteFlow:为低代码开发带来革命性的变革
- 2024-10-25 easyrules开发java程序(javaee应用开发)
你 发表评论:
欢迎- 最近发表
-
- 五,网络安全IDA Pro反汇编工具初识及逆向工程解密实战
- 「JAVA8」- Lambda 表达式(java lambda表达式原理)
- 深入探讨Java代码保护:虚拟机保护技术的新时代
- Nginx反向代理原理详解(图文全面总结)
- 逆向拆解日本IT,哪些Java技术栈薪资溢价高
- mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比
- Spring Boot集成ProGuard轻松实现Java 代码混淆, Java 应用固若金汤
- 从 Java 代码逆向工程生成 UML 类图和序列图
- 人与人相处:尊重是标配,靠谱是高配,厚道是顶配
- Windows系统安装日期如何修改(windows10怎么修改安装日期)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)