美文网首页
使用Redis和Zookeeper实现分布式锁

使用Redis和Zookeeper实现分布式锁

作者: 孑一二 | 来源:发表于2019-09-26 09:44 被阅读0次

    介绍

    分布式锁
    一般用在分布式系统或者多个应用中,用来控制同一任务是否执行或者任务的执行顺序。在项目中,部署了多个tomcat应用,在执行定时任务时就会遇到同一任务可能执行多次的情况,我们可以借助分布式锁,保证在同一时间只有一个tomcat应用执行了定时任务。

    实现方式

    1.使用redis的setnx()和expire()
    2.使用redis的getset()
    3.使用zookeeper的创建节点node
    4.使用zookeeper的创建临时序列节点
    

    实际应用

    · 使用redis的setnx()和expire()来实现分布式锁

    setnx(key,value) 如果key不存在,设置为当前key的值为value;如果key存在,直接返回。
    expire()来设置超时时间
    
    ## 定义注解类
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Lockable{
        // redis缓存key
        String key();
        // redis缓存key中的数据
        String value() default "";
        // 过期时间(秒),默认为一分钟
        long expire() default 60;
    }
    
    ## 定时任务增加注解@Lockable
    @Lockable(key = "DistributedLock:dealExpireRecords")
     public void dealExpireRecords() {
     }
    
    ## 定义一个aop切面LockAspect
    ## 使用@Around处理所有注解为@Lockable的方法
    ## 通过连接点确认此注解是用在方法上
    ## 通过方法获取注解信息,使用setIfAbsent来判断是否获取分布式锁
    ## 如果没有获取分布式锁,直接返回;如果获取到分布式锁,通过expire设置过期时间,并调用指定方法
    
    @Component
    @Slf4j
    @Aspect
    public class LockAspect {
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        @Around("@annotation(com.records.aop.Lockable)")
        public Object distributeLock(ProceedingJoinPoint pjp) {
            Object resultObject = null;
    
            //确认此注解是用在方法上
            Signature signature = pjp.getSignature();
            if (!(signature instanceof MethodSignature)) {
                log.error("Lockable is method annotation!");
                return resultObject;
            }
    
            MethodSignature methodSignature = (MethodSignature) signature;
            Method targetMethod = methodSignature.getMethod();
    
            //获取注解信息
            Lockable lockable = targetMethod.getAnnotation(Lockable.class);
            String key = lockable.key();
            String value = lockable.value();
            long expire = lockable.expire();
    
            // 分布式锁,如果没有此key,设置此值并返回true;如果有此key,则返回false
            boolean result = redisTemplate.boundValueOps(key).setIfAbsent(value);
            if (!result) {
                //其他程序已经获取分布式锁
                return resultObject;
            }
    
            //设置过期时间,默认一分钟
            redisTemplate.boundValueOps(key).expire(expire, TimeUnit.SECONDS);
    
            try {
                resultObject = pjp.proceed(); //调用对应方法执行
            } 
            catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return resultObject;
        }
    }
    

    · 使用redis的getset()来实现分布式锁

    此方法使redisTemplate.boundValueOps(key).getAndSet(value)的方法
    如果返回空,表示获取了分布式锁
    如果返回不为空,表示分布式锁已经被其他程序占用
    

    · 使用zookeeper的创建节点node

    使用zookeeper创建节点node
    如果创建节点成功,表示获取了此分布式锁
    如果创建节点失败,表示此分布式锁已经被其他程序占用
    ## 多个程序同时创建一个节点node,只有一个能够创建成功
    

    · 使用zookeeper的创建临时序列节点

    使用zookeeper创建临时序列节点来实现分布式锁
    ## 适用于顺序执行的程序
    大体思路:
    创建临时序列节点,找出最小的序列节点,获取分布式锁
    程序执行完成之后此序列节点消失 ## 通过watch来监控节点的变化
    从剩下的节点的找到最小的序列节点,获取分布式锁,执行相应处理,依次类推...
    

    相关文章

      网友评论

          本文标题:使用Redis和Zookeeper实现分布式锁

          本文链接:https://www.haomeiwen.com/subject/jsohyctx.html