2 分布式锁

Quartz集群模式可水平扩展,也可分布式调度,但需业务方在数据库中添加对应表,有强侵入性。

于是有人探索分布式锁模式。

2.1 超时关单

通常做定时任务每2min检查前半小时的订单,将待支付订单列表查出,然后对订单中的商品进行库存的恢复,然后将该订单设置为无效。

Spring Schedule定时任务。

@Scheduled(cron = "0 */2 * * * ? ")
public void doTask() {
   log.info("定时任务启动");
   //执行关闭订单的操作
   orderService.closeExpireUnpayOrders();
   log.info("定时任务结束");
 }

单服务器运行正常,考虑到高可用,业务量激增,架构演进成集群模式,在同一时刻有多个服务执行一个定时任务,可能导致业务紊乱。

2.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("定时任务结束");
}

1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.

Redis读写性能极好,分布式锁也比Quartz数据库行级锁更轻量级。

小型项目定时任务框架(Quartz/Spring Schedule)和 分布式锁(redis/zookeeper)不错。

2.3 问题

  • 定时任务在分布式场景下有空跑情况,而且任务也无法做到分片
  • 想手工触发任务,须添加额外代码