Spring Boot Scheduler部署PCF双数据中心如何避免重复执行并实现容灾
可行解决方案整理
方案1:基于分布式锁实现(轻量化首选)
- 核心逻辑:所有实例启动调度前先争抢全局分布式锁,只有抢锁成功的实例可以执行调度任务,抢锁失败的实例跳过本次执行。锁需要设置合理的过期时间,避免实例宕机导致锁永久占用。
- 技术选型:
- 若已接入Redis:直接使用Redisson的
RLock可重入锁,适配300ms的高频调度场景,锁过期时间设置为1~2s即可,任务执行完成后主动释放锁,实例宕机后锁自动过期释放,另一数据中心的实例下一次调度即可抢锁执行。
示例伪代码:
@Scheduled(fixedDelay = 300) public void scheduledTask() { RLock lock = redissonClient.getLock("scheduler:task:lock"); try { // 尝试立刻抢锁,无等待,抢不到直接放弃本次执行 if (lock.tryLock(0, 1, TimeUnit.SECONDS)) { // 执行业务逻辑 } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }- 若已接入关系型数据库:使用数据库乐观锁或者
SELECT FOR UPDATE排他锁实现,创建一张调度锁表,存储锁名称、持有实例标识、过期时间,每次调度前尝试更新锁记录,更新成功则获得执行权。
- 若已接入Redis:直接使用Redisson的
- PCF适配:PCF服务市场原生支持Redis、MySQL等中间件实例,直接绑定到应用即可使用,无需额外部署组件。
方案2:基于Spring Cluster Scheduler实现
- 核心逻辑:Spring自带的集群调度能力,基于共享的持久化存储(JDBC、Redis)存储调度任务的执行状态,自动保证集群内只有一个实例执行任务,实例宕机自动触发故障转移,调度任务自动迁移到存活实例执行。
- 配置要点:
- 引入
spring-boot-starter-integration和对应存储的依赖 - 配置集群调度的共享数据源/Redis连接
- 调度任务添加
@DisallowConcurrentExecution注解防止并发执行
- 引入
- 优势:不需要自行实现锁逻辑,框架层面原生支持,故障转移逻辑经过生产验证。
方案3:基于PCF平台特性实现
- 核心逻辑:利用PCF的实例调度、健康检查和跨DC漂移能力控制调度任务的运行实例数
- 实现方式:
- 将调度任务和业务接口拆分,单独部署调度服务,该服务在PCF上的实例数设置为1,开启跨DC实例漂移能力,当当前实例所在DC宕机时,PCF会自动在另一个DC拉起新的实例
- 开启PCF的健康检查,实例宕机后平台自动在存活DC重建实例,最大中断时间取决于实例启动速度,适合对中断时间容忍度在秒级的场景
- 优势:不需要修改业务代码,完全依托平台能力实现,维护成本最低。
方案选型建议
- 如果调度任务执行逻辑敏感,不允许任何重复执行:优先选方案1的Redisson分布式锁实现,逻辑可控,适配300ms的高频调度场景
- 如果不想手写锁逻辑,已经部署共享存储组件:优先选方案2的Spring集群调度
- 如果不想改代码,对调度中断秒级延迟可接受:优先选方案3的PCF平台原生能力
内容的提问来源于stack exchange,提问作者Ankit
相关产品推荐
相关产品推荐

