热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Redis实现分布式锁(spring定时任务集群应用Redis分布式锁)

之前2片文章介绍了spring利用注解实现定时任务:https:blog.csdn.netQiaoRui_articledetails82999655spring定时

         之前2片文章介绍了

                spring利用注解实现定时任务:https://blog.csdn.net/QiaoRui_/article/details/82999655

                spring定时任务的动态修改:https://blog.csdn.net/QiaoRui_/article/details/83110794


描述:

             不管用不用动态执行,单机服务都是没有问题的,但是如果服务是集群模式下,那么一个任务在每台机器都会执行一次,这肯定不是我们需要的,我们要实现的是整个集群每次只有一个任务执行成功,但是spring对此并没有很好的支持,所以我们需要有一个统一的数据获取处,参考网上决定利用rides的一致性来实现,开始就参考网上利用setnx命令实现的,但是还是感觉不太完善,就去抛开定时任务,直接实现Redis分布式锁应该是最合适的,在定时任务业务处加锁,业务执行完解锁即可。

             此事例经过多个网站参考并自己实际操作是不存在任何问题,完全可以正常使用。


实现:


import redis.clients.jedis.JedisCluster;import java.util.Collections;/**** redis实现分布式锁,并释放锁*/
public class RedisTool {private static final String LOCK_SUCCESS = "OK";private static final String SET_IF_NOT_EXIST = "NX";private static final String SET_WITH_EXPIRE_TIME = "PX";private static final Long RELEASE_SUCCESS = 1L;/*** 尝试获取分布式锁* @param jedis Redis客户端* @param lockKey 锁* @param requestId 请求标识* @param expireTime 超期时间,毫秒* @return 是否获取成功*/public static boolean tryGetDistributedLock(JedisCluster jedis, String lockKey, String requestId, int expireTime) {/**设置锁并设置超时时间,lockKey表示Redis key,requestId表示Redis value,SET_IF_NOT_EXIST表示有值不进行设置(NX),* SET_WITH_EXPIRE_TIME表示是否设置超时时间(PX)设置,expireTime表示设置超时的毫秒值* */String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);if (LOCK_SUCCESS.equals(result)) {return true;}return false;}/*** 释放分布式锁* @param jedis Redis客户端* @param lockKey 锁* @param requestId 请求标识* @return 是否释放成功*/public static boolean releaseDistributedLock(JedisCluster jedis, String lockKey, String requestId) {/** 利用Lua脚本代码,首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)* eval命令执行Lua代码的时候,Lua代码将被当成一个命令去执行,并且直到eval命令执行完成,Redis才会执行其他命令,这样就不会出现上一个代码执行完挂了后边的出现问题,还是一致性的解决* */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(lockKey), Collections.singletonList(requestId));if (RELEASE_SUCCESS.equals(result)) {return true;}return false;}}

根据上篇博客的业务进行引用

package com.rails.travel.conf.task.myschedule;import com.rails.travel.common.FrameSpringBeanUtil;
import com.rails.travel.common.RedisTool;
import redis.clients.jedis.JedisCluster;import java.util.Date;public class MyRunnable3 implements Runnable {//因为是线程所以无法注入bean对象,只能通过这种方法去获取bean对象//FrameSpringBeanUtil工具类在另一篇博客:https://blog.csdn.net/QiaoRui_/article/details/83094960private JedisCluster jedisCluster = FrameSpringBeanUtil.getBean(JedisCluster.class);@Overridepublic void run() {//加锁,调用上边的工具类,参数具体看工具类说明boolean lock = RedisTool.tryGetDistributedLock(jedisCluster, MyRunnable3.class.toString(), MyRunnable3.class.toString(), 3000);//加锁成功则执行业务,不成功则不执行业务if (lock){//此处业务代码System.out.print("业务执行了3" + new Date());//业务执行完成解锁,如果在执行业务中或者是在解锁出现了异常,宕机等,锁会根据加锁时的key过期时间自己消除RedisTool.releaseDistributedLock(jedisCluster,MyRunnable3.class.toString(), MyRunnable3.class.toString());}}
}

说明:

            加锁解锁工具类直接是查看博客和官网等获取用的,博客必须看,可以完全明白实现原理及现在网上的错误做法的问题所在,我开始用的就是博客中提到的第一种错误方法

            博客:https://wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/#%E5%8F%82%E8%80%83%E9%98%85%E8%AF%BB

           Redis中文命令参考中在set命令最后也给出了同样的解决方式:http://doc.redisfans.com/string/set.html

           Redis官网关于分布式锁中也是这种方式包括推荐的GitHub实现也是这种方式:https://redis.io/topics/distlock


推荐阅读
author-avatar
那lady对我说12067358
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有