id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week
| id |
title |
type |
domain |
stack |
tags |
level |
prerequisites |
est_hours |
related |
week |
| backend.data-pipeline.scenario.third-party-sync |
第三方平台订单同步:限流、断点续跑、迟到数据、对账和告警 |
scenario |
backend |
| data-pipeline |
| postgresql |
| redis |
| mq |
|
|
intermediate |
| backend.data-pipeline.reliability |
|
2.5 |
| backend.data-pipeline.interview |
| backend.redis.lock-ratelimit |
|
|
第三方平台订单同步:限流、断点续跑、迟到数据、对账和告警
业务背景与问题
公司为商家提供 SaaS 经营分析和 AI 报表助手,需要把商家在多个电商平台的订单同步过来。现状是一个简单的定时脚本,问题频发:
- 平台接口限流,高峰期大量 429,脚本直接失败;
- 脚本中途挂掉后从头再跑,产生重复订单;
- 少量订单状态和平台对不上(退款了这边还是已支付);
- 某次平台接口返回字段变更,脏数据写入了几个小时才被商家发现。
约束
- 每个平台的限流规则不同,而且按“商家授权的应用”计算配额。
- 上千个商家,每个商家每 10 分钟同步一次。
- 平台没有提供变更推送,或者推送不可靠。
方案设计
- 任务拆分:调度器每 10 分钟为每个“商家 × 平台”生成一个同步任务,投递到队列;多个工作进程消费;同一个商家同一时间只运行一个任务(分布式锁或队列分区)。
- 限流:按“平台 + 应用”在 Redis 中做令牌桶,所有工作进程共享;429 按
Retry-After 退避。
- 断点续跑:每个任务有自己的水位线(
updated_at + id),本页数据落库后才推进;重叠窗口回拉 5 分钟处理迟到数据;upsert 带版本比较。
- 数据质量:
- 字段级校验(类型、枚举、金额范围),坏数据进死信表并带原始报文;
- 批次级检查:坏数据比例、与上周同时段的数据量对比;
- 不通过就停止该平台的同步并告警,避免继续写入脏数据。
- 对账:每天凌晨按商家拉取前一天的订单汇总(数量、金额、各状态数量)与本地比对,差异自动补拉并记录。
- 可观测:每个任务记录拉取数、写入数、死信数、重试次数、耗时;面板按平台展示;连续失败、死信突增、对账差异超阈值时告警。
关键代码
基于 Redis 的共享令牌桶(Lua 保证原子性):
单进程版本的完整实现和测试:examples/incremental-sync。
取舍
| 选择 |
优点 |
缺点 |
| 队列 + 工作进程 + 共享限流(本方案) |
可水平扩展、互不影响 |
需要队列和 Redis |
| 单个定时脚本串行同步 |
简单 |
商家多了跑不完,一个失败影响全部 |
| 引入 Airflow 等编排平台 |
可视化、重跑方便 |
学习和运维成本,对小团队偏重 |
易错点
- 限流计数放在进程内存中,多个工作进程加起来超过配额。
- 同一商家的两个任务并发运行,水位线互相覆盖。
- 平台字段变更时没有校验,脏数据持续写入。
- 只有“任务失败”告警,没有“数据量异常”告警:任务成功但拉回 0 条同样是问题。
面试怎么讲
“我们对接了多个电商平台的订单。调度器为每个商家生成同步任务进队列,工作进程消费;限流用 Redis 令牌桶按平台和应用共享;每个任务有水位线,落库后才推进,回拉 5 分钟重叠窗口处理迟到数据,upsert 时比较更新时间防止旧数据覆盖。字段校验不过进死信,坏数据比例和数据量异常都会停止同步并告警。每天凌晨按汇总对账,差异自动补拉。”