Spring中使用分布式任务同步ShedLock
内容提要
本文介绍了使用ShedLock在Spring分布式系统中执行任务的方法,通过外部存储实现任务的同步执行,避免冲突和重复。文章提供了使用PostgreSQL作为外部存储的示例,并演示了创建锁表和配置Spring Boot项目的步骤。最后,介绍了ShedLock的使用方法和优势。
延伸解读
ShedLock 的“最多一次”语义与适用边界
ShedLock 保证计划任务“最多同时执行一次”,而非“恰好一次”。当某实例持有锁时,其他实例会直接跳过该次执行,不等待锁释放。因此它适合数据库清理、数据生成等允许偶尔跳过的任务;若业务要求每次触发都必须执行,则需额外补偿机制。
lockAtMostFor 与 lockAtLeastFor 的防护作用
lockAtMostFor 为锁设置最长持有时间,防止实例崩溃后锁被永久占用,示例中设为 50 秒。lockAtLeastFor 则确保锁至少保留一段时间,避免任务执行过快导致锁过早释放,同时减少实例间时钟不同步的影响。两者需根据任务实际耗时合理配置。
外部存储选型与数据库时间的重要性
ShedLock 依赖外部存储实现锁,支持 JDBC 关系数据库以及 Mongo、Redis、DynamoDB 等 NoSQL。示例使用 PostgreSQL 并创建 shedlock 表,配置中通过 usingDbTime() 使用数据库时间,有助于规避各实例本地时钟不一致带来的锁竞争问题。
Q&A
ShedLock 是什么?它解决了分布式系统中的什么问题?
ShedLock 是一个用于在分布式系统中协调任务执行的库,它确保计划任务最多同时执行一次。它通过外部存储实现锁定,避免多个实例同时运行同一任务导致的冲突或重复。
ShedLock 支持哪些类型的外部存储?
ShedLock 支持通过 JDBC 工作的关系数据库(如 PostgreSQL、MySQL、Oracle 等),也支持 NoSQL 数据库(如 Mongo、Redis、DynamoDB)以及许多其他数据库。
如何在 Spring Boot 项目中配置 ShedLock?
需要添加依赖(如 shedlock-spring 和 shedlock-provider-jdbc-template),然后创建一个配置类,使用 @EnableScheduling 和 @EnableSchedulerLock 注解,并定义一个 LockProvider bean,例如使用 JdbcTemplateLockProvider 配置数据源。
使用 ShedLock 时,锁表需要哪些字段?
锁表需要包含 name(锁的唯一标识符)、lock_until(锁的过期时间)、locked_at(锁的获取时间)和 locked_by(获取锁的实例标识)字段,其中 name 是主键。
ShedLock 如何确保任务在多个实例中只执行一次?
当一个实例执行任务时,会在数据库中插入一条锁记录,其他实例尝试执行时会发现锁已存在,从而跳过执行。任务完成后,锁记录会被更新,释放锁。
ShedLock 中的 lockAtMostFor 和 lockAtLeastFor 参数有什么作用?
lockAtMostFor 设置锁的最大持有时间,防止实例崩溃后锁被永久占用;lockAtLeastFor 设置锁的最小持有时间,避免任务执行过快导致锁过早释放,确保任务不会在短时间内重复执行。