Files
zhuangang/topics/backend/data-pipeline/scenarios/third-party-sync.md
T

4.3 KiB
Raw Blame History

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
14

第三方平台订单同步:限流、断点续跑、迟到数据、对账和告警

业务背景与问题

公司为商家提供 SaaS 经营分析和 AI 报表助手,需要把商家在多个电商平台的订单同步过来。现状是一个简单的定时脚本,问题频发:

  1. 平台接口限流,高峰期大量 429,脚本直接失败;
  2. 脚本中途挂掉后从头再跑,产生重复订单;
  3. 少量订单状态和平台对不上(退款了这边还是已支付);
  4. 某次平台接口返回字段变更,脏数据写入了几个小时才被商家发现。

约束

  • 每个平台的限流规则不同,而且按“商家授权的应用”计算配额。
  • 上千个商家,每个商家每 10 分钟同步一次。
  • 平台没有提供变更推送,或者推送不可靠。

方案设计

  1. 任务拆分:调度器每 10 分钟为每个“商家 × 平台”生成一个同步任务,投递到队列;多个工作进程消费;同一个商家同一时间只运行一个任务(分布式锁或队列分区)。
  2. 限流:按“平台 + 应用”在 Redis 中做令牌桶,所有工作进程共享;429 按 Retry-After 退避。
  3. 断点续跑:每个任务有自己的水位线(updated_at + id),本页数据落库后才推进;重叠窗口回拉 5 分钟处理迟到数据;upsert 带版本比较。
  4. 数据质量:
    • 字段级校验(类型、枚举、金额范围),坏数据进死信表并带原始报文;
    • 批次级检查:坏数据比例、与上周同时段的数据量对比;
    • 不通过就停止该平台的同步并告警,避免继续写入脏数据。
  5. 对账:每天凌晨按商家拉取前一天的订单汇总(数量、金额、各状态数量)与本地比对,差异自动补拉并记录。
  6. 可观测:每个任务记录拉取数、写入数、死信数、重试次数、耗时;面板按平台展示;连续失败、死信突增、对账差异超阈值时告警。

关键代码

基于 Redis 的共享令牌桶(Lua 保证原子性):

-- KEYS[1]=桶的 key  ARGV: rate(每秒), capacity, now(毫秒)
local b = redis.call('HMGET', KEYS[1], 'tokens', 'ts')
local rate, cap, now = tonumber(ARGV[1]), tonumber(ARGV[2]), tonumber(ARGV[3])
local tokens = tonumber(b[1]) or cap
local ts = tonumber(b[2]) or now
tokens = math.min(cap, tokens + (now - ts) / 1000 * rate)
local ok = 0
if tokens >= 1 then tokens = tokens - 1; ok = 1 end
redis.call('HSET', KEYS[1], 'tokens', tokens, 'ts', now)
redis.call('PEXPIRE', KEYS[1], math.ceil(cap / rate * 1000) + 1000)
return ok

单进程版本的完整实现和测试:examples/incremental-sync。

取舍

选择 优点 缺点
队列 + 工作进程 + 共享限流(本方案) 可水平扩展、互不影响 需要队列和 Redis
单个定时脚本串行同步 简单 商家多了跑不完,一个失败影响全部
引入 Airflow 等编排平台 可视化、重跑方便 学习和运维成本,对小团队偏重

易错点

  • 限流计数放在进程内存中,多个工作进程加起来超过配额。
  • 同一商家的两个任务并发运行,水位线互相覆盖。
  • 平台字段变更时没有校验,脏数据持续写入。
  • 只有“任务失败”告警,没有“数据量异常”告警:任务成功但拉回 0 条同样是问题。

面试怎么讲

“我们对接了多个电商平台的订单。调度器为每个商家生成同步任务进队列,工作进程消费;限流用 Redis 令牌桶按平台和应用共享;每个任务有水位线,落库后才推进,回拉 5 分钟重叠窗口处理迟到数据,upsert 时比较更新时间防止旧数据覆盖。字段校验不过进死信,坏数据比例和数据量异常都会停止同步并告警。每天凌晨按汇总对账,差异自动补拉。”