因为专注所以专业
助力成长与创新,汇集前沿程序开发观点

定时任务两台机器都在跑,月底对账单出了两份,分布式锁到底挡得住哪一段?

2026年11月2日 阅读:19

集群里同一个定时任务在两台以上机器同时触发,财务收到两份对账单,多数时候不是调度器坏了,而是“谁来触发”没收敛、任务本身又不幂等。按 2026 年常见交付经验,分布式锁主要挡并发触发,挡不住超时重投、人工补跑、历史数据重算,也挡不住推送、扣款这类外部副作用;对账、结算、发券这类入口,通常要把调度层收敛、执行层幂等键和每日核对告警分开看。

先分清触发重复还是执行重复

两条路径现象像,处置不同。触发重复属于调度层问题,同一触发时刻被多个实例领走;执行重复属于执行层问题,业务表同一业务日出现两条,调度日志里可能只有一个实例。判断顺序固定:先看调度日志,再看业务表,两边不一致时以业务表为准。

常见误判是:任务跑了 12 分钟、平台超时阈值设 10 分钟,被判失败后自动重投,第二次执行时第一次还没结束。加锁有效,但不调超时阈值,等于把重复推迟到锁过期之后。对账、结算、发券每执行一次会写外部可见结果,重复代价是人工冲正;只读聚合多跑一次通常可接受。先看副作用向内还是向外,再决定防重铺到哪一层。

  • 调度日志同一触发时间多个实例 ID:先查选主或分片。
  • 只有一个实例 ID,业务表同一业务日有两条:先查执行重试或人工补跑。
  • 任务耗时接近或超过平台超时阈值:先调阈值,再评估锁。
  • 任务内部分批调下游、某批失败后整体重跑:已成功批次会重复,按批次做幂等。

调度、执行、核对三层各挡什么

三层分别回答:同一时刻谁在跑、跑重复了会不会出错、出错了多久能发现。发生概率从前往后递减、单次修复成本递增,所以按副作用大小决定铺到哪一层;只做调度层,等于把风险押在锁的可靠性上。

  1. 调度层收敛:让同一任务同一时刻只有一个实例领到。可用调度平台分片或选主、单实例部署,或用数据库任务表抢占。锁要能续期,任务跑 20 分钟而锁 5 分钟到期,第二台就会进场。
  2. 执行层幂等:给任务一个业务幂等键,常见写法是“任务码 + 业务日期 + 单据号”,执行前先尝试插入执行记录,插入成功才继续。幂等键要带业务日期,否则第二天的正常执行会被前一天记录挡掉。
  3. 核对层兜底:每天比对源表与结果表的条数、金额合计,差异超过阈值就告警。告警要能定位到具体任务码和业务日,只报一句“对账不平”等于没报。

三层不必一次上齐。单实例部署、内部循环跑完的小系统,调度层已收敛,重点放执行层幂等;已接入调度平台的,先用平台自带分片和失败策略,再补核对告警。顺序上先保证结果可发现,再优化触发方式。

几种做法成本与失效点对比

选哪种做法,取决于现有基础设施和任务副作用等级。下面时间周期是按 2026 年常见项目交付节奏估算的经验区间,会随团队熟悉程度浮动,不建议直接当成排期承诺。

  • 单实例部署:任务拆独立部署单元,只有一份在跑。成本低,接入周期常见 1 天左右;失效点在该实例挂掉任务就停,适合能容忍延迟数小时的批处理。
  • 数据库任务表抢占:靠一行状态记录决定谁跑。成本低,周期常见 1~3 天;失效点是实例宕机后状态卡在“执行中”,要配超时回收。
  • Redis 分布式锁:加锁快、接入方便。周期常见 2~5 天(含续期、释放校验、异常处理);失效点在主从切换、锁租约到期、实例长时间停顿。
  • 调度平台分片:由平台决定任务分给谁。周期常见 1~3 天;失效点是分片规则写错会把同一批数据分给两个实例,仍要执行层兜底。
  • 业务唯一索引:离结果更贴近。周期视表数据量常见 1~3 天;失效点是只能挡能建唯一键的写入,挡不住推送、扣款这类外部调用。

交付现场:锁有了,任务还是跑两遍

在项目里常见的一种约束是:客户已有两台应用服务器,没有调度平台,排期只剩两周,预算也不支持再申请一套中间件。比较省事的做法是把任务拆成独立单实例部署;客户坚持不新增实例,就在数据库里用一行任务锁做抢占,并配 15 分钟超时回收。代价通常出在锁的细节上:第一版没做续期,任务跑过 10 分钟被第二台抢走,验收前返工加续期和释放校验,多花 1~2 天。这类返工在常见区间里就是 1~2 天,续期与释放校验建议上线前检查。

适用与不适用边界

需要防重的前提通常是两条同时成立:多实例部署,且任务有对外可见的副作用。只满足其中一条时,先做执行层幂等和核对告警,通常比上分布式锁划算;两条都不满足,一般什么都不用改。

  • 适合:多实例部署,且任务会推送、扣款、发券、改余额。
  • 适合:任务耗时接近调度周期或平台超时阈值,容易被重投。
  • 适合:后台提供补跑、重跑入口,人工操作和自动调度会撞车。
  • 不必上:单实例部署,且任务只做读聚合,重复执行不产生可见结果。
  • 不必上:任务本身天然幂等,例如按业务日期全量覆盖重算,跑一次和跑两次结果相同。
  • 不必上:加锁引入的运维成本(续期、主从切换、释放校验)明显高于重复一次的业务代价。

可独立摘录的一条边界是:当任务本身幂等时,防重锁带来的运维复杂度往往高于重复执行一次的代价,这类任务更适合把精力放在核对与告警上。

常见问题

只加一把 Redis 锁,能不能完全防住重复执行?

不能完全防住。锁主要覆盖并发触发,超时重投、人工补跑、下游失败重试会绕开锁,还需要业务幂等键和核对层配合。

锁的过期时间设多久合适?

经验区间是任务平均耗时的 1.5~2 倍并开启续期;宁可续期,也别设成很大的固定值,否则实例宕机后任务长时间没人接手。

任务超时被平台重新投递,算重复触发吗?

算。这类重复来自调度平台重试策略,可先调大超时阈值或关闭自动重投,改成告警后人工确认,再评估加锁。

业务表加了唯一索引,还要分布式锁吗?

唯一索引挡得住重复写入,挡不住重复推送和扣款。它适合放在执行层做兜底,不宜只靠它。

单机部署的定时任务也要做三层吗?

通常不用上分布式锁。单实例下调度层已收敛,把执行层幂等和核对告警做上即可,是否补业务键按副作用决定。


如果只排得下一轮改动,可以先按“有没有对外副作用”把定时任务分成两类:无副作用的维持现状,有副作用的先补业务幂等键和每日核对告警,调度层的选主与分片放到下一轮迭代。犀跃公司在交付中通常也按这个顺序推进,先把结果兜住再谈触发优化;反过来先上锁,容易在锁到期和主从切换时重新暴露同一个问题。

有类似的项目需求?
联系我们,获取一对一项目参考方案
获取方案
准备好开始了吗,
那就与我们取得联系吧!
13370032918
了解更多服务,随时联系我们
请填写您的需求
您希望我们为您提供什么服务呢
您的预算
联
系
微信二维码
扫码添加客服微信
专业对接各类技术问题
联系电话
13370032918 (金经理)
电话若占线或未接到、就加下微信
联系邮箱
349077570@qq.com
提交成功
感谢您的信任,我们会尽快与您联系!
为您推荐以下案例