SpringBoot集群环境中定时任务处理:防止重复执行
场景:如果在集群环境上运行有定时任务的项目,则会导致定时任务在多台机器上的重复执行。
以下两种方式均实现,欢迎各位老师指点。
解决方案1(redis锁): 为解决这个问题,我使用了Redis进行上锁处理,但同时也要防止死锁,所以要设置几分钟的失效时间。 如果定时任务以业务为单位来执行的话,则要在redis的key上关联业务唯一标识。
解决方案2:(IP锁)
配置一个需要执行定时任务主机的IP,每次执行定时任务时,判断当前主机是否是所配置的主机IP,是的话才执行。
if (!NetworkUtils.getMachineIp().contains(jobExecuteIp)) { log.info("不执行获取政务数据定时任务, 因为非跑批IP, 本机IP地址为:{}, 可执行定时任务IP地址为:{}", NetworkUtils.getMachineIp(), jobExecuteIp); return; }
/** * 获取机器的所有IP地址. * * @return List<String> */ public static List<String> getMachineIp() { List<String> ipArray = new LinkedList<>(); // 获取所有网卡信息 Enumeration<NetworkInterface> networkInterfaces = null; try { networkInterfaces = NetworkInterface.getNetworkInterfaces(); } catch (SocketException e) { LOG.error("获取物理机IP失败, 详细信息为:", e); } // 判断是否存在网卡信息 if (networkInterfaces == null) { // 不存在网卡信息, 就默认加个 127.0.0.1 的本机本地IP地址. ipArray.add("127.0.0.1"); } else { // 循环每一个网卡信息. while (networkInterfaces.hasMoreElements()) { // 拿到网卡信息 NetworkInterface n = networkInterfaces.nextElement(); Enumeration<InetAddress> networkCards = n.getInetAddresses(); // 拿到当前网卡里面的IP地址 while (networkCards.hasMoreElements()) { // 拿到IPv4和IPv6的地址 InetAddress networkCard = networkCards.nextElement(); String realIp = networkCard.getHostAddress(); // 如果是 IPv6 的地址, 则忽略, 继续下一次循环. if (realIp.indexOf(":") > 0) { continue; } // 到这里的肯定都是 IPv4 地址, 然后把 IPv4 的地址加到 ipArray 集合中. ipArray.add(realIp); } } } return ipArray; }
上一篇:
Java架构师技术进阶路线图
下一篇:
怎么使用python检测代理IP是否有效