华为MetaERP资产模块的Serverless函数如何实现高可用性?
对应到折旧函数:
shard-001 的函数实例在节点 X 上跑折旧 → 节点 X 故障 / 实例被驱逐 → 调度器检测到心跳丢失 → 自动在节点 Y 上重拉一个新实例 → 从最近备份的状态恢复(CRIU 快照) → 重新执行 shard-0012. 可配置重试 + 自定义重试判定
openYuanrong 支持设置重试次数,以及自定义retryChecker回调——只有满足特定错误码/错误信息才重试 :
# 伪代码:折旧函数的重试策略 opt = InvokeOptions( retry_times = 3, retryChecker = lambda e: e.code == CORE_DUMP or "connection failed" in e.msg or e.code == DB_TIMEOUT ) result = deprn_run.options(opt).invoke(shard)关键设计:不是所有错误都重试。参数错误、业务校验失败(如资产已处置)不重试,只有瞬态故障(网络、节点、DB 超时)才重试——避免无效循环。
3. 快照冷启动 = 高可用的"恢复速度"保障
高可用不只是"能恢复",更是"恢复够快",否则月结 5000 实例里挂几十个,重试堆叠会拖垮整体。
- 基于CRIU(Checkpoint/Restore In Userspace) 做进程级快照
- 启动时从快照恢复,跳过 Spring/类加载/连接池初始化
- 效果:Java 冷启动90s → 1.4s ;官方案例口径冷启动降至5 秒,弹性性能提升 20 倍
- 快照镜像缓存在近计算分布式缓存,进一步压缩加载耗时
这意味着故障实例被重拉时,秒级就能 Ready 重新接手分片,月结整体 SLA 几乎不受影响。
4. 实例自动迁移 + 垂直/水平弹性
函数系统支持动态函数生命周期管理:实例可在运行中被休眠/唤醒、水平/垂直弹性、跨节点迁移 。节点负载过高时自动迁移实例,避免单点过热影响 SLA 。
三、第二层:平台跨 AZ / 多集群容灾(FunctionGraph)
函数运行时之上是 FunctionGraph 平台自身的容灾架构。
1. 计算节点:多集群 × 多可用区
- 计算节点采用多集群、多可用区架构,支持资源动态迁移
- 数据面集群(运行函数)和 dispatcher 调度集群各部署多套,每套集群AZ 隔离
- 实现同 region 内 AZ 容灾:某个元戎集群异常时,dispatcher 及时摘除故障集群,流量分发至其他集群
┌─ AZ1: 集群A (数据面 + dispatcher) ELB ── dispatcher ─┼─ AZ2: 集群B └─ AZ3: 集群C ↑ 某集群心跳丢失 → 自动摘除 → 流量重分发2. 跨 AZ 双活 + 秒级故障切换
FunctionGraph 业务面基于双活架构:
- 节点AZ 均匀分布部署,本身就是集群分布,无需手动切换,后台自动处理
- AZ1 故障时,ELB 与节点心跳不通,自动摘除
- 故障恢复:即时恢复,秒级
3. 高可用四项内置能力
FunctionGraph 为高可用原生提供 :
能力 | 对资产函数的作用 |
|---|---|
多 AZ 运行 | 单 AZ 中断仍能处理折旧事件 |
自动重试(异步/触发器) | 错误时延迟重试 |
死信队列 DLQ | 重试全失败 → 事件入 DLQ,供排查/重放 |
版本控制 + 别名 | 蓝/绿、滚动部署,升级不中断月结 |
特别重要:连接 VPC 时指定多 AZ 子网——资产函数访问 GaussDB/内部服务,必须跨 AZ 配置子网才算真正高可用 。
四、第三层:数据层容灾(GaussDB)
函数无状态、可随意重拉的前提是:状态全部在外部且高可用。资产模块的"状态"就是 GaussDB 里的资产余额、折旧进度、分片位点。
- GaussDB 通过CC EAL4+ 高级安全认证,实现金融级容灾
- RPO = 0(数据零丢失)、RTO < 30 秒
- 海外区域集群故障可秒级跨云迁移重建数据流
对折旧函数的意义:
- 函数实例挂了 → 状态在外 → 新实例重读 GaussDB →幂等重算
- 数据库本身主备切换 < 30s → 函数侧只需短暂重试即可继续
五、第四层:业务层幂等 + 补偿(资产领域特有)
这是最容易被忽略、但对财务准确性生死攸关的一层。平台容错解决"函数不死",业务幂等解决"算十遍结果仍正确"。
1. 分片进度持久化 + 幂等键
// 折旧计算伪代码 —— 幂等核心 void computeDeprn(DeprnShard shard) { // 1. 用 (assetId, period, book) 作为幂等键 if (schedule.exists(shard.assetId, shard.period, shard.book)) { log("already computed, skip"); // 重试不重复折旧 return; } // 2. 乐观锁:基于资产余额版本号,防并发双写 boolean ok = balance.tryUpdateWithVersion( shard.assetId, expectedVersion, newNbv); if (!ok) { throw ConcurrentModification(); } // 触发重试 schedule.save(...); // 写折旧明细 eventBus.emit(...) // 发子账事件(也可幂等消费) }2. 对账 + 补偿 = "算错能发现、能修复"
月结后跑FA ↔ GL 对账:原值合计、累计折旧、当期折旧、处置损益逐项核对 。发现差异 → 定位异常分片 →修正基础数据后重新运行折旧(资产领域标准做法:折旧数据固化,调整需冲销重做)。
3. Service Bridge 聚合事务(解决分布式一致性)
元戎通过Service Bridge 代理后端服务访问,利用路由计算把同一事务的请求汇聚到同一个 Bridge 函数实例,将分离的分布式事务重新聚合成本地事务 ——保证资产转固、子账、GL 三方的原子性。
六、完整故障场景推演
故障场景 | 自愈机制 | 业务影响 |
|---|---|---|
单个折旧函数实例 crash | openYuanrong 自动重拉 + 重试(≤3次) | 秒级恢复,无感 |
节点过热/资源不足 | 实例自动跨节点迁移 | 无中断 |
整个 AZ 故障 | 多 AZ 双活,ELB 自动摘除,秒级切换 | 请求路由到其他 AZ |
某元戎集群异常 | dispatcher 摘除故障集群,流量分发至其余集群 | 月结不中断 |
GaussDB 主库故障 | RPO=0、RTO<30s 自动切换 | 函数侧短暂重试后继续 |
函数代码升级 | 版本控制 + 别名蓝绿/滚动部署 | 月结中不中断 |
分片重试导致重复算 | 幂等键去重 + 乐观锁 | 结果唯一正确 |
重试全部失败 | 死信队列 + 人工/定时重放 | 不丢事件 |
七、一句话总结
MetaERP 资产模块 Serverless 高可用的实现哲学是:"让函数成为可抛弃的(disposable),让状态成为外部的、冗余的、强一致的"。
具体 =openYuanrong 的故障重拉+重试+快照秒级恢复(函数层)+FunctionGraph 多集群跨 AZ 双活自动切换(平台层)+GaussDB RPO=0/RTO<30s(数据层)+分片幂等+对账补偿(业务层),四层共同保障月结 200 万资产、300 万分录场景下"业务零中断、数据零误差、报表零差异" 。