最近在做集群的时候,多台服务器上都有Spring定时任务的代码。
如果不做处理的话,每台服务器上的定时任务都会执行,而实际只需要一台服务器上的定时任务执行就可以了。
我这里用的是Redis来保证这个一致性。
大致逻辑:
1.多台服务器定时任务同时触发。
2.在代码块中增加向Redis请求添加KEY的操作,添加成功则表示锁定,当前服务器执行定时任务。添加失败不执行定时任务。
3.执行完成之后释放锁。
java部分代码:
// 锁名称 String key = "ProductStatus"; // 获取锁 if(lock(key)) { // 当前服务器执行定时任务 } else { // 不执行 return; }
private boolean lock(String key) { String str = jedis.set(getKey(key), "1", "NX", "PX", 100); if("OK".equals(str)) { return true; } return false; }
释放锁,为了避免释放的过程失败,使用的是Redis脚本代码。
private boolean unlock(String key) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(getKey(key)), Collections.singletonList("1")); Long r = 1L; if(r.equals(result)) { return true; } return false; }
这里还需要注意的是,集群服务器的时间在部署的时候必须进行同步。
否则定时任务执行的时间会存在偏差。