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;
	}
经验分享 程序员 微信小程序 职场和发展