Quartz集群模式可水平扩展,也可分布式调度,但需业务方在数据库中添加对应表,有强侵入性。于是探索分布式锁模式。
1 超时关单
通常做定时任务每2min检查前半小时的订单,将待支付订单列表查出,然后对订单中的商品进行库存的恢复,然后将该订单设置为无效。
Spring Schedule定时任务。
@Scheduled(cron = "0 */2 * * * ? ")
public void doTask() {
log.info("定时任务启动");
//执行关闭订单的操作
orderService.closeExpireUnpayOrders();
log.info("定时任务结束");
}
单服务器运行正常,考虑到高可用,业务量激增,架构演进成集群模式,在同一时刻有多个服务执行一个定时任务,可能导致业务紊乱。
2 解决方案
任务执行时,Redis分布式锁:
Explain@Scheduled(cron = "0 */2 * * * ? ")
public void doTask() {
log.info("定时任务启动");
String lockName = "closeExpireUnpayOrdersLock";
RedisLock redisLock = redisClient.getLock(lockName);
// 加锁,最多等3s,上锁后300s自动解锁
boolean locked = redisLock.tryLock(3, 300, TimeUnit.SECONDS);
if(!locked){
log.info("没有获得分布式锁:{}" , lockName);
return;
}
try{
//执行关闭订单的操作
orderService.closeExpireUnpayOrders();
} finally {
redisLock.unlock();
}
log.info("定时任务结束");
}
Redis读写性能极好,分布式锁也比Quartz数据库行级锁更轻量级。
小型项目定时任务框架(Quartz/Spring Schedule)和 分布式锁(redis/zookeeper)不错。
3 问题
- 定时任务在分布式场景下有空跑情况,而且任务也无法做到分片
- 想手工触发任务,须添加额外代码