1
Asimov01 2022-09-04 20:48:14 +08:00
已 star ,希望能继续完善下去,感谢分享。
|
2
Jooooooooo 2022-09-04 21:16:42 +08:00
分布式是咋做到的...
|
3
wolfie 2022-09-04 21:50:25 +08:00
正好周一看看
|
4
iluolSNS 2022-09-04 23:14:23 +08:00
@Jooooooooo 引入了 redis
|
5
Kipp 2022-09-05 00:17:42 +08:00 via iPhone
可以,学习一下
|
6
potatowish 2022-09-05 08:04:06 +08:00 via iPhone
感谢分享,这个我也写过,不过分布式锁是在定时任务开始前获取,结束后自动释放。你这种方式是通过 cron 表达式来计算需要加锁的时间。
我有个疑问,key 后面拼接了 nextTime ,如果有多个实例的启动时间不一致,那么都会获取到对应的分布式锁(计算得到的 nextTime 不一样),这样在一个实例的定时任务执行期间,其他实例也有可能启动定时任务。 |
7
dqzcwxb 2022-09-05 09:13:19 +08:00
@Jooooooooo #2 加了个分布式锁
|
8
gaobing OP 感谢以上各位的 star 。
@potatowish 多个实例的启动时间虽然不一样,但在一个定时任务的周期内,计算出来的 nextTime 其实是一样的。之所以加这种带 nextTime 周期的锁,是因为用不带 nextTime 分布式锁的话,一个实例执行完当前周期的定时任务后就会释放锁,别的实例因为线程池队列已满等一些原因的话,导致定时任务运行稍晚,此时分布式锁已经被释放,就会重复执行当前周期的定时任务。 |
9
pkwenda 2022-09-05 10:31:20 +08:00
理解 @potatowish 说的
https://github.com/gaoice/distributed-scheduling-spring-boot-starter/blob/a25406c6e291a3cf37fc9de9b8a125c2c79e41cb/src/main/java/com/gaoice/distributed/scheduling/aspect/ScheduledAspect.java#L44 这行代码的 key 充满了随机性,大概率都会获取到锁,6L 提到的启动时间,UTC 时间等等因素,如果该定时任务是 10s 一次甚至是 5s 一次,刚启动后和稳定后肯能可能比较好复现吧 |
10
gaobing OP @pkwenda key 不是随机的,同一个周期计算得到的是固定的值,这样通过 key 就保证了加的锁只锁定当前周期,不会因为时间的误差而影响到下个周期定时任务的执行,你可以执行下这段代码看下 nextTime 的计算结果:
```java @Test public void testNextTime() throws Exception { CronSequenceGenerator c = new CronSequenceGenerator("0/5 * * * * ?"); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss"); for (int i = 0; i < 100; i++) { Date now = new Date(); long nextTime = c.next(now).getTime(); System.out.println(format.format(now) + " 的 nextTime 为:" + nextTime); Thread.sleep(1000); } } ``` 我执行的结果: 2022-09-05 10:52:11.011 的 nextTime 为:1662346335000 2022-09-05 10:52:12.012 的 nextTime 为:1662346335000 2022-09-05 10:52:13.013 的 nextTime 为:1662346335000 2022-09-05 10:52:14.014 的 nextTime 为:1662346335000 2022-09-05 10:52:15.015 的 nextTime 为:1662346340000 2022-09-05 10:52:16.016 的 nextTime 为:1662346340000 2022-09-05 10:52:17.017 的 nextTime 为:1662346340000 2022-09-05 10:52:18.018 的 nextTime 为:1662346340000 2022-09-05 10:52:19.019 的 nextTime 为:1662346340000 2022-09-05 10:52:20.020 的 nextTime 为:1662346345000 2022-09-05 10:52:21.021 的 nextTime 为:1662346345000 2022-09-05 10:52:22.022 的 nextTime 为:1662346345000 2022-09-05 10:52:23.023 的 nextTime 为:1662346345000 2022-09-05 10:52:24.024 的 nextTime 为:1662346345000 2022-09-05 10:52:25.025 的 nextTime 为:1662346350000 2022-09-05 10:52:26.026 的 nextTime 为:1662346350000 2022-09-05 10:52:27.027 的 nextTime 为:1662346350000 |
11
heroconan 2022-09-05 11:43:00 +08:00
即使是在多个实例的系统时间存在误差的情况下,因为一个实例的定时任务从开始执行起到下次执行前锁都是被占据的,同一个定时任务的执行时间间隔一致,所以可以保证在一个执行周期内同一个定时任务是不会被执行多次。
一个简单示例: X 表示任务执行,-表示间隔 没有时间误差的情况,两个实例: X-----X-----X-----X-----X-----X-----X......... X-----X-----X-----X-----X-----X-----X........ 此时两个实例要去竞争锁 存在时间误差,两个实例 X-----X-----X-----X-----X-----X-----X......... X-----X-----X-----X-----X-----X-----X........ 此时第二个实例开始执行任务的时候发现锁已被占用,所以不会执行 |
12
heroconan 2022-09-05 11:44:22 +08:00
上面第二个示例被格式化了,所以补充一下
存在时间误差,两个实例 X-----X-----X-----X-----X-----X-----X......... ... [时间误差] X-----X-----X-----X-----X-----X-----X........ 此时第二个实例开始执行任务的时候发现锁已被占用,所以不会执行 |
13
wolfie 2022-09-07 10:13:27 +08:00
|
14
buster 2022-09-07 14:30:25 +08:00
咦,是增强版的 shedlock 么?
|
16
siweipancc 2022-09-08 10:53:54 +08:00 via iPhone
做过类似的代码,基本原理是替换掉默认的扫描后处理逻辑,redis 打执行时间戳避免时钟不同步问题。
后来不方便运行时维护,又改回去调度框架了 |
17
gaobing OP @siweipancc 是的,分场景。这个项目也不会去对标调度框架,而是解决对分布式定时任务的需求不复杂的场景,能够使用熟悉的 @Scheduled 注解快速实现需求。
|