共计 2275 个字符,预计需要花费 6 分钟才能阅读完成。
背景与痛点:为什么需要专业工作流引擎
在微服务架构下,一个业务流程往往需要跨多个服务协作完成。假设我们要实现一个电商订单流程,涉及库存锁定、支付处理、物流调度等步骤。如果直接用 RPC 或消息队列拼接,会遇到几个典型问题:

- 状态丢失:服务宕机时,无法确定流程执行到哪一步
- 错误恢复复杂:支付失败后需要自动解锁库存
- 横向扩展难:大促期间无法动态分配处理资源
我曾用数据库状态表 + 定时任务实现过这类流程,结果凌晨 3 点总是被告警叫醒——某条记录卡在 ” 处理中 ” 状态再也无法推进。这正是 Cadence 这类工作流引擎要解决的核心问题。
技术选型:Cadence 的独特定位
对比常见解决方案的架构特点:
| 引擎 | 状态管理 | 错误恢复机制 | 适用场景 |
|---|---|---|---|
| Airflow | 数据库存储 DAG | 手动重试 / 回填 | 定时批处理任务 |
| Temporal | 事件溯源 | 自动断点续传 | 长期运行业务流程 |
| Cadence | 决策状态分离 | 内置补偿工作流 | 金融级事务场景 |
Cadence 最大的特点是采用 决策器(Decider)和 活动工作器(Worker)分离的架构。就像建筑工地上的监理和工人:监理(Decider)掌握蓝图并指挥进度,工人(Worker)只负责具体施工。这种设计带来了两个关键优势:
- 决策器轻量无状态,可以任意扩展
- 工作器故障不会影响流程状态
核心实现:从代码看运行机制
工作流定义示例(Go 语言)
type OrderProcessingWorkflow struct {
// 工作流必须实现的接口方法
cadence.RegisterWorkflow(ProcessOrder)
}
func ProcessOrder(ctx cadence.Context, orderID string) error {
// 1. 设置执行选项(超时 / 重试策略)ao := cadence.ActivityOptions{
ScheduleToStartTimeout: time.Minute,
StartToCloseTimeout: time.Minute * 30,
RetryPolicy: &cadence.RetryPolicy{
InitialInterval: time.Second,
BackoffCoefficient: 2,
MaximumInterval: time.Minute,
},
}
ctx = cadence.WithActivityOptions(ctx, ao)
// 2. 执行活动序列
var status string
err := cadence.ExecuteActivity(ctx, LockInventory, orderID).Get(ctx, &status)
if err != nil {return fmt.Errorf("库存锁定失败: %v", err)
}
// 3. 补偿事务设计
defer func() {if err != nil && !cadence.IsCanceledError(err) {_ = cadence.ExecuteActivity(ctx, CompensateInventory, orderID)
}
}()
// 后续支付、物流等步骤...
return nil
}
活动实现示例
public class PaymentActivitiesImpl implements PaymentActivities {
@Override
public String processPayment(String orderId, BigDecimal amount) {
// 实际支付接口调用
PaymentGatewayClient client = new PaymentGatewayClient();
try {
// 关键:配置心跳检测防止超时
Activity.getExecutionContext().recordHeartbeat("processing");
return client.charge(orderId, amount);
} catch (TimeoutException e) {
// 建议:查询支付状态实现幂等
String status = client.queryStatus(orderId);
if ("SUCCESS".equals(status)) {return "already_paid";}
throw Activity.wrap(e);
}
}
}
生产环境优化策略
性能调优三板斧
- 分片策略:
- 按订单 ID 哈希分片(避免热点)
-
单个分片不超过 1000 活跃工作流
-
超时配置黄金法则:
- 活动超时 ≥ 最长可能执行时间 × 3
-
心跳间隔 ≤ 超时时间的 1 /3
-
历史记录清理:
cadence: history: retentionInDays: 7 # 生产环境建议 3 -30 天 maxAutoResetPoints: 20
容错设计模式
- 操作幂等:给每个活动注入唯一 bizId
- 补偿事务:在 defer 中注册回滚逻辑
- 最终一致性检查:定时校对系统状态
避坑指南:血泪经验总结
遇到这些问题时先检查这些配置:
- 心跳超时:
- 现象:活动频繁超时但服务正常
-
解决:调整
ScheduleToStartTimeout或网络延迟 -
历史记录爆炸:
- 现象:Cadence 服务 CPU 持续高位
-
解决:限制
maxAutoResetPoints并启用归档 -
幽灵工作流:
- 现象:已取消的流程仍在运行
- 解决:检查是否漏掉
ctx.Done()信号处理
延伸思考
- 如何设计跨集群的 Cadence 灾备方案?
- 对于秒杀场景,工作流引擎如何避免成为瓶颈?
- 当业务逻辑需要动态调整时,如何实现不停机的工作流版本迁移?
经过半年生产环境验证,我们基于 Cadence 的订单系统达到了 99.99% 的流程完成率。最关键的心得是:把业务逻辑的复杂度交给工作流引擎,让开发者专注业务价值本身。
正文完
发表至: 未分类
近两天内
