去哪儿营销实践-魔方营销画布
一、引言
1.1 营销配置系统现状
当前营销活动由apollo配置系统承载。apollo配置系统提供filter和trigger两大类组件,支持自由组合使用,灵活度比较高。但是,由于底层设计的一些局限性,在营销活动配置场景下存在明显不足,比如不支持流程分叉。另外,组件数量不断增长但又缺乏治理,低内聚高耦合的现状也导致了组件的复用性很低、配置容易出错。
在配置营销活动时,业务人员需要在多个组件间手动维护一致性,容易出错且效率低下。同时,apollo无法提供可视化的活动流程展示,导致配置过程不直观,排查问题困难。更重要的是,它不支持动态流程编排,难以满足营销活动中多阶段、多分支的复杂场景需求。
1.2 策略活动配置的特点
在现代数字化营销环境中,营销活动配置面临着多重挑战。营销活动具有强时效性,需要快速响应市场变化和业务需求,上线窗口极短。活动配置涉及多环节协同,从触发策略到最终触达用户,需要多个系统模块的紧密配合。不同业务场景对营销活动有着高度差异化,如新用户引导、老用户召回、节日促销等,不同活动(如拉新、促活)的策略、受众与权益组合千变万化,需要灵活的配置能力支持。随着业务规模扩大,营销活动还需要支持高并发和数据实时性要求,确保在海量用户参与时,策略能精准执行、权益能准确发放。
1.3 新的配置形式
为了解决上述问题,我们创新性地引入了画布配置形式。通过可视化、拖拽式的界面,将复杂的营销流程直观呈现。它将活动抽象为“触发策略”、“人群圈选”等独立节点,运营人员通过连线即可自由编排用户流转路径,形成端到端的营销工作流。这种形式极大降低了技术门槛,使业务人员能直接、快速地构建复杂活动,实现了业务逻辑的“所画即所得”。同时,画布的结构化表达也为流程的自动化执行与效果分析提供了坚实基础,从根本上提升了运营效率和敏捷性。
二、技术选型
在技术选型过程中,我们重点考虑了系统的可视化能力、扩展性和性能要求。
2.1 前端方案选型
为了高效实现本需求,流程图功能使用开源框架实现,让前端开发更注重业务逻辑本身,防止重复造轮子耽误时间。通过对目前较活跃的开源项目总结、调研后,得出如下表格:
【1】https://v0-charts.ant.design/demos/dagre-graph
【2】https://reactflow.dev/examples
【3】https://reactflow-cn.js.org/learn
【4】https://jsplumbtoolkit.com/
【5】https://ng.ant.design/experimental/graph/zh
【6】https://xflow.antv.vision/zh-CN/docs/tutorial/intro/about/
综上来看,xflow提供的流程图解决方案更贴合本次需求,通过xflow已有功能可省去大部分底层功能开发工时。
xflow 优点:
(1)开箱即用,使用实例就可以直接搭建出一个可用的流程图
(2)右侧编辑区 可定制化程度较高,二次开发后基本能满足需求(二次开发指开发、封装 表单部分)
(3)内部集成antd、react,技术栈符合需求
(4)1.0文档实例可用,介绍较全
2.2 后端方案选型
梳理了多个主流的Java开源编排引擎,它们各有侧重,在功能、性能和适用场景上有所不同。下面这个表格汇总了它们的核心特点。
BPMN 2.0 是一套完整的业务流程建模与执行标准。它通过统一的视觉语言和机器可读的格式,是现代业务流程自动化和工作流引擎技术的基石。支持 BPMN 2.0 的几款开源产品,其开源版本的功能受限,并且强依赖XML格式。
LiteFlow和Gobrs-Async则是另一类解决方案,它们侧重于流的执行,并且各有侧重点。LiteFlow侧重于逻辑驱动,提供基于复杂逻辑关系的执行方案,但并不适用于依赖网络IO的工作流。而Gobrs-Async本身是套异步任务编排框架,虽然有着优异的性能,但流程描述依赖字符串配置(比如AService->BService,CService),复杂流程的配置比较繁琐,难以维护和排错,学习门槛也比较高。对于营销业务来说,部分特性也不支持(需要二开)。
综上来看,市面上没有完全符合条件的轻量级开源产品,最接近的Gobrs-Async二开成本高、学习曲线较陡,并不是理想的解决方案。因此,我们决定自研一套适应营销场景的工作流引擎,基于Spring Ractor来实现异步非阻塞的高性能执行引擎。
2.3 对比n8n
n8n是一款开源的低代码/公平代码工作流自动化平台,其核心价值在于通过可视化界面连接不同的应用、服务和数据源,构建自动化流程。它允许用户在特定事件(如收到邮件或Webhook调用)触发后,自动在其他工具中执行预定操作(如发送消息或更新数据库)。
优点:n8n以其出色的灵活性著称,支持通过代码节点编写JavaScript或Python等自定义逻辑,并能通过自托管部署模式让企业对数据和合规性拥有完全控制权,这对于有严格安全要求的企业至关重要。
缺点:这款工具的学习曲线相对陡峭,对用户的技术背景有一定要求。此外,虽然其开源版免费,但一些高级功能受到限制,且自托管版本需要企业自行承担运维工作。
营销画布的使用群体是产品和运营同学,普遍没有技术背景。n8n适用于技术团队,并不适合直接提供给产运同学使用。当面对独特且复杂的业务流程时,标准化的节点可能无法完美适配,有时需要“削足适履”。另外,如果使用n8n构建工作流,也需要打通公司的整个技术栈,包括QMQ、监控等。
三、系统设计
画布的配置形式,对于营销业务来说,是个有向、非闭环的工作流,是一个有向无环图结构,但又因逻辑关系、串并行、优先级等业务逻辑,不能简单地使用常规的遍历算法执行工作流。
系统采用配置与执行分离的架构,配置服务负责画布元数据的存储、版本管理和发布流程,执行引擎负责解析画布配置,协调各阶段组件执行营销流程。
3.1 系统间交互
3.2 执行引擎
3.3 上下文管理
每个节点都有自己的数据,这些数据可以被其他任意节点所使用。为了管理数据间的依赖关系,我们将每个节点的数据都定义了元数据,在画布配置中明确引用依赖的数据。
除了节点数据,还有用户数据。用户数据在整个流程处理过程中非常重要,基本上是所有节点、上下游依赖的关键数据,因此作为一份通用数据保存在上下文中。
3.4 执行结果判定
通常,我们以流程的最后一个节点来判断最终的执行结果。当最后的执行节点是叶子节点时,流程处理结束,最后一个节点的“成功/失败”,等同于活动整体的“成功/失败”。而当最后的执行节点不是叶子节点时,分为以下几种情况:
节点执行失败,则流程结束,整个流程执行失败。
节点“暂停”,此时流程需要暂时挂起,上下文数据需要持久化,等流程恢复时加载上下文数据并继续执行。
但是,营销业务有着自己的特殊性。为了防止资损,只要给用户发放了权益或者触达了用户,即使最后的节点执行失败了,也应当认定为“执行成功”,这样才能避免重复发放权益或重复触达用户。
四、组件生态
营销画布的核心竞争力在于丰富的组件生态,覆盖营销活动的全生命周期。一个营销活动的处理流程通常为:策略触发 -> 人群圈选 -> 权益发放 -> 消息触达。因此,我们也将组件分为以下几个类别:
4.1 行为策略组件
4.2 逻辑分支组件
4.3 人群圈选组件
4.4 权益发放组件
4.5 用户触达组件
4.6 其他组件
五、创新之处
5.1 多阶段执行
通过行为策略类组件的组合,可以支持多阶段执行。各种各样的组合形式,可以衍生出五花八门的玩法,极大地拓展了营销创意的实现空间。当某个行为策略触发时,会判断关联行为策略是否满足条件。当不满足条件时,流程会暂时挂起,等待其他行为策略触发,直至所有行为策略条件都满足时,才会最终执行完整个流程。举例几个场景:
5.2 子流程嵌套
通过子流程嵌套,可以实现配置的最大化复用,以及业务的模块化拆解。现在,可以对一个庞大的活动进行拆解,将其模块化,每个模块对应一个子流程。这样既简化了配置管理,也有利于业务域划分,更便于统一整体的策略逻辑。子流程是基础的复用单元,它有三种形态:工作流、策略表格、数据表格。
5.3 表格形式
对于多维度的配置场景,工作流并不能很好地承载。比如需要多个策略因子进行组合,或者是给多张券配置金额、标题等。因此,我们提供了表格形式的配置,根据用途不同,又分为策略表格和数据表格两种类型。表格形式极大地降低了复杂营销策略的配置门槛,使业务人员能够自主完成精细化运营配置。
5.3.1 策略表格
一般,我们都会基于很多策略因子做策略,不同策略间关心的因子不同、策略间彼此也有优先关系。我们定义一个表格,表格的行代表因子,列代表策略,交点则为结果。为了方便操作,我们预设好因子的可选值,然后在策略列中下拉选择即可。结果也是一样,先预设好结果的可选值,然后下拉选择即可。策略可动态增删,也支持左右调整顺序(优先级),这样就能方便地进行策略调整了。如下表:
5.3.2 数据表格
对于偏展示层的文案来说,需要完整的二维表格来支撑,也是最普遍的表格形态。我们定义一个表格,表格的行代表属性,列代表业务key(比如券code),在单元格中填写业务key对应的属性值。跟策略表格一样,可以给属性设置“可选值”,这样就可以在单元格中下拉选择了,提高配置效率。如下表:
六、技术难点与实现
并发锁
在Reactor实现中,基本原则是异步非阻塞,执行线程可能会切换到其他线程。无论是本地锁还是分布式锁,一个基本的共同点是:锁必须由获取它的同一个“上下文”或“所有者”来释放。这个“所有者”的标识是关键,对于本地锁,这个“所有者”是线程。而对于分布式锁,这个“所有者”是自定义的一个唯一值,但公司的分布式锁组件lock-sedis却依赖了当前的threadId。
因此,我们需要不依赖当前线程的并发锁方案。对于本地锁,我们使用AtomicBoolean的compareAndSet加锁,在处理结束后手动置为false释放锁;对于分布式锁,我们使用redis的setnx命令加锁,锁的过期时间15s,启动心跳机制每隔5s更新过期时间,在处理结束后手动释放锁,并停止心跳机制。
并发处理
集线器和逻辑关系组件存在多次执行的场景,比如逻辑关系节点上游有10个节点,那么每个节点结束时都会进入逻辑关系节点。如果逻辑关系是“或”,则有任意一个节点执行成功时,不再关心其他节点的结果;反之,则有任意一个节点执行失败时,不再关心其他节点的结果。
在系统设计上,我们要求节点需要处理并发执行。在常规系统里,我们tryLock一段时间即可。但在异步非阻塞模式下,这种阻塞的操作会严重影响处理性能。而在tryLock时采用快速失败的话,又没有重试的机会了。我们分析上面的例子,虽然理论上会进入10次,但我们关心的并不是要执行10次,而是保证“最后一次”能被执行。因此,当发生并发时,不论锁竞争者有几个,我们只需要再“重试”一次即可。
//示例代码boolean lock = result.getWaitProcess().compareAndSet(true, false);if (!lock) {result.getWaitProcess().set(true); //waitProcess置为true,说明需要重试return Mono.empty();}do {...} while(isRepeat(result));private boolean isRepeat(result) {if (result.status == 'success') {return false;}boolean repeat = result.getWaitProcess().get();result.getWaitProcess().set(false)return repeat;}
七、落地效果
营销画布配置系统上线后,在多个维度取得了显著成效:
效率提升
配置效率:营销活动平均配置时间从1天缩短至1小时,提升90%+
人力投入:研发人员从繁琐的配置工作中释放,专注核心技术建设
业务价值
活动数量:系统支持100+ 营销活动稳定运行
订单提升:通过精细化流程优化,日新增订单量3000+
系统稳定性
可用性:系统达到99.95% 的可用性目标
性能表现:核心接口平均响应时间<50ms