⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7401403660246614070 「爱学习的码农靖」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

前言

笔者在去年接手了公司的活动中台,其中【任务】,是活动当中必不可缺的玩法之一。

相信大家都在各种各样的互联网活动中体验过【任务】。

比如:

  • 打车软件去完成一笔订单可以给用户发一个奖品;
  • 如用户去申请白条的额度,就能给用户发放京豆;

从技术思维上,以上的流程,可以抽象成,用户完成某个动作,就给用户发放对应的奖品。

作为中台的任务系统,往往会对接上游N个业务方的不同任务,并且任务也会有不同的完成条件。

如:

电商业务:用户支付一笔3000元以上的订单,完成【订单任务】
商业化业务:用户完成一个app下载,且打开app浏览10秒,完成【app下载任务】
生活业务:用户完成一笔话费充值,且充值金额大于50元,完成【话费充值业务】

具体的流程图如下:

任务系统重构

可以看到,业务侧将消息通过RocketMQ的方式,通知至任务系统。

痛点解决-如何避免对接新的任务,改造代码

以上方式,会有一个实实在在的痛点:每次任务完成条件发生变更,就需要任务系统更改代码,现状需要一周的时间去对接一个新的任务。

举个例子,假如电商业务中,【订单任务】的完成条件从【3000元以上订单】调整为【5000元以上订单】,任务系统每次还得去调整代码,以支持【5000元以上订单】完成的条件。这种如此慢的迭代方式,显然是不够支持业务的发展速度。

所以任务系统的行动点就是:任务完成条件变动,做成可配置化,支持运营在后台管理系统随时调整任务的配置条件。

统一消息格式

其实仔细分析,任务完全可以抽象成为:针对某个行为, 判断行为中的条件是否满足运营配置的要求

但是系统的现状为,各个业务的消息体虽都是json格式,但格式都不一致,任务系统写了很多针对不同消息格式的定制化代码适配,其流程图如下:

统一消息格式的好处

因此我先要求业务方的mq格式消息体进行改造,按照任务系统的统一标准进行格式传递。

标准消息体格式如下
"userid": "",
"business": "",
"behavior": "" ,
"behaviorTime": "",
"extraData": {
}

userId是用户的id,business是该事件所属业务,behaviorTime是行为发生的时间, behavior就是用户具体的任务行为,比如【完成订单叫pay_order_success】, app下载叫【app_download】, 话费充值叫【tel_recharge】。

最为关键的是extraData, 这个字段是拓展字段,主要用于存放每个行为的附加条件,比如:

【完成订单】,该字段可以存放订单交易金额,是否首次下单,那么完成订单的完整消息为:

"userid": "12345", 
"business": "onlineShop",
"behavior": "pay_order_success" ,
"behaviorTime": "完成订单时间戳",
"extraData": {
"tradeTotalMoney": 500000,
"firstTime": true
}

以上完成消息对应的中文含义为:用户12345, 在某个时间,完成了【电商业务】中的【下单成功】行为,行为的附加属性为:【交易金额大于5000元,用户本次是首次交易】。

之后,所有对接任务系统的任务,业务方必须按照我的要求,来传递消息。

做好了任务消息的标准化,就开始下一步优化:如何将完成条件进行抽象,做成可配置化管理?

完成条件可配置化

想把任务完成的配置完全交给运营,首先需要有个类似下面这种配置的管理后台,为简单的画一下管理后台的原型。

任务系统重构-后台管理示意图

灵魂画家。。。总而言之,就是把任务的完成条件开放至运营,并支持可配。

根据我从业经验,这种规则支持配置的场景,便是【规则引擎】的最佳使用场景。结合项目组的现状,我决定使用阿里的QLExpress, 并进行重构。

QLEpress介绍如下:

https://github.com/alibaba/QLExpress  
由阿里的电商业务规则、表达式(布尔组合)、特殊数学公式计算(高精度)、语法分析、脚本二次定制等强需求而设计的一门动态脚本引擎解析工具。
在阿里集团有很强的影响力,同时为了自身不断优化、发扬开源贡献精神,于2012年开源

引入了规则引擎后,在判断任务完成的代码时候,其实就是对QlExpress的脚本进行判断,任务的完成条件可以表现为一串脚本命令,如:

tradeTotalMoney >= 300000 && firstTime = true

在执行完成任务代码的时候,任务系统会将【任务消息体】中的extraData,构造成一个HashMap, 传入到QLEpress的api中。

"userid": "12345", 
"business": "onlineShop",
"behavior": "pay_order_success" ,
"behaviorTime": "完成订单时间戳",
"extraData": {
"tradeTotalMoney": 500000,
"firstTime": true
}

使用QLEpress的api,express就是【脚本命令】, context是一个Map,对于任务系统来说,就会把extraData传入函数中。

Object r = runner.execute(express, context, null, true, false);

对于QLEpress来说也很简单,就是做了Map对象中的key替换的动作,实际上就是执行以下的这段代码:

Object r = 500000  >= 300000 && true = true

其系统流程图如下:

任务系统重构-系统交互流程

假如运营现在想把任务系统中【完成订单】的完成条件中的订单交易金额5000改成3000,也很简单了,只需通过后台管理系统更改配置就能实现任务的调整。

后台系统新增条件的可配置化。

你以为以上就是最终方案了么,对接新的任务就不用开发了么?

其实不然,细心的读者会发现,后台系统如果要新增 【任务完成行为】 和【完成条件】,后台管理系统还是得开发代码。比如:需要新增一个【加入购物车】的任务,还是需要后台系统开发。

所以,我们的下一步优化策略,是将【任务完成行为】和 【完成条件】做成配置化,后台动态读取数据库的配置进行显示,其流程如下:

任务系统重构-支持元数据配置

这里我把属于【规则引擎】的内容抽象成一个系统,让这个系统去对规则领域的内容进行管理。

其实12步,“引入【规则引擎系统提供的sdk】,执行规则引擎代码”,有两种方案,也可以由任务系统在交互的过程中,传入参数,去调用【规则引擎系统】提供的RPC接口,但考虑到增加了一层网络开销,且规则引擎执行的场景也相对简单,不会对规则引擎的代码进行过多调整,所以采取的是引入sdk的方式,通过本地代码执行去减少不必要的网络开销。

结论

经过规则引擎的重构后,再对接新的任务,只需通过开发1分钟在后台配置元数据,即可完成新的任务对接,比起之前动辄一周的新任务对接,大大提高了效率。

笔者也通过这次改造获得了公司的好绩效,并将这种规则引擎的能力,提供给其它系统使用,真正实现了开发驱动业务。

文章目录
  1. 1. 前言
  2. 2. 痛点解决-如何避免对接新的任务,改造代码
    1. 2.0.1. 统一消息格式
    2. 2.0.2. 完成条件可配置化
    3. 2.0.3. 后台系统新增条件的可配置化。
  • 3. 结论