ShedLock: 一个轻量级的定时任务协调组件
[TOC]
参考:
定时任务通常会遇到什么问题?
如果开发的服务需要水平部署实现负载均衡,那么定时任务就会同时在多个服务实例上运行,
那么一方面,可能由于定时任务的逻辑处理需要访问公共资源从而造成并发问题;
另一方面,就算没有并发问题,那么一个同样的任务多个服务实例同时执行,也会造成资源的浪费。
因此需要一种机制来保证多个服务实例之间的定时任务正常、合理地执行。
ShedLock 解决了什么问题?
ShedLock 就是一个锁,保证多个实例在同一时间只会执行一次通过一个 shared databases 来保证,比如 redis,mysql,zk 等
设计思路很简单:谁能拿到锁,谁就有资格执行
同类产品的比较
略。
Quartz
比较重量级,是处理定时任务的优秀框架
xxl-job
带管理页面,功能强大
使用
以 redis 为例,会存储一个分布式锁,键为:
它的值为:
ttl:(lockAtLeastFor 的值)
配置:
记一次遇到的 ShedLock 的一个 Bug
问题描述:
当时 spring 的一个定时任务一直没有执行
查询 lock 发现,存储的 lock 的 ttl 始终是 -1,也就是说变成了永久存储而不释放
解决方案
先手动删 lock,临时执行
shedlock-provider-redis-spring 升级到 3.0.0(2.1.0 就已经解决了)
复盘
这其实是一个非常经典的问题:也就是加锁、设置过期时间两步操作的原子性问题,这两个步骤在执行第一步之后由于某种原因(宕机等)中断了第二步操作,导致其值永远不会生效。
其实 redis 提供了原子性操作的功能,只是源代码没有用:
SET key value [EX seconds] [NX]
https://note.youdao.com/ynoteshare1/index.html?id=ca6fd7667cbf8a00564f73f25714b92f&type=note
源码:shedlock-provider-redis-spring-v0.18.2
不过另外一个provider:shedlock-provider-jedis v0.11.0
一开始就规避了这个问题:
源码分析
总体脉络
ShedLock 的源码相对简单,项目分层比较清晰,比较容易理解。
shedlock-core 包:抽象出了默认的接口、方法、SchedulerLock 注解,不过具体的实现在 provieders 里
providers 包:定义了不同的 shared databases 的实现:jdbcredisetc.
测试框架:mockito
各 provider 的实现
redis:
提供了一个有过期时间的分布式锁
jdbc:MariaDB、PostgreSQL、MySQL等等
创建一个用于存储 lock 的表,并插入一条关于锁的数据。
着重看一下 spring 的依赖: https://juejin.im/post/5eb166bc5188250bdf5c1ec6?utm_source=gold_browser_extension
版权声明: 本文为 InfoQ 作者【kk】的原创文章。
原文链接:【http://xie.infoq.cn/article/ca0dd0b69f202a17891e1b369】。
本文遵守【CC BY-NC】协议,转载请保留原文出处及本版权声明。
评论