• 基于redis 实现分布式锁的方案


      在电商项目中,经常有秒杀这样的活动促销,在并发访问下,很容易出现上述问题。如果在库存操作上,加锁就可以避免库存卖超的问题。分布式锁使分布式系统之间同步访问共享资源的一种方式

    基于redis实现分布式锁的原理:

      redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。其次Redis提供一些命令SETNX,GETSET,这些命令是原子操作,利用这些特性,

    可以很充分的实现分布式锁。SETNX,GETSET 命令如下:

      SETNX key value
        功能:当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。

      GETSET key value
        功能:将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回null


     实现要点:
      1、避免死锁,必要的超时机制。设置时间戳,时间戳要精确到毫秒。如果获取锁失败,则说明锁被其他对象保持,检查其是否超时

      2、释放锁时,避免释放非自己获得的锁,释放锁时,可以做一个是否超时的检查,如果超时说明锁就无需释放了

      3、为了造成不必要的资源浪费,提高并发,最好在最小颗粒度上的块加锁

      4、为了降低redis 压力,获取锁尝试时,循环之间一定要做sleep操作

    参考源代码如下
    // redis client
    private Redistemplate tradeRedisTemplate

    private Boolean setNX(String key, String value){
       return redisConnection.setNX(key.bytes, value.bytes)   
    }

    private String getSet(String key, String value){
       byte[] result = redisConnection.getSet(key.bytes, value.bytes)
       return new String(result)
    }

    //释放锁  key 锁名称,time 超时时间
    public Void delDistributedLock(String key, Long time){
            String lastTimeS = tradeRedisTemplate.opsForValue().get(key)
            if(System.currentTimeMillis() - Long.parseLong(lastTimeS) < time){//避免删除非自己获取得到的锁
                tradeRedisTemplate.delete(key)
            }
    }

    //加锁 key 锁名称,time 超时时间
    public Boolean acquireDistributedLock(String key, Long time){
            if(setNX(key, Long.toString(System.currentTimeMillis()))){ //SETNX成功,则成功获取一个锁
                return true
            }else{
                //SETNX失败,说明锁仍然被其他对象保持,检查其是否已经超时
                String lastTimeS = tradeRedisTemplate.opsForValue().get(key)

                Long lastTime = Long.parseLong(lastTimeS)

                //超时
                if(System.currentTimeMillis() - lastTime > time){
                    String lastTimeRedis = getSet(key, Long.toString(System.currentTimeMillis()))
                    if(lastTimeRedis.equals(lastTimeS)){// 获取锁成功
                        return true
                    }
                    // 已被其他进程捷足先登了
                }
            }
            return false
    }


    参考资料:

    http://redis.io/commands/setnx
    http://www.blogjava.NET/caojianhua/archive/2013/01/28/394847.html

  • 相关阅读:
    Oulipo
    伊吹萃香 (Standard IO)
    雾雨魔理沙 (Standard IO)
    帕秋莉·诺蕾姬 (Standard IO)
    射命丸文 (Standard IO)
    家庭作业 (Standard IO)
    数字游戏 (Standard IO)
    asp.net后台正则表达式验证手机号码邮箱
    ASP.NET实现Cookie功能的三个基本操作(写入,读取,删除)
    C# DateTime 月第一天和最后一天 取法
  • 原文地址:https://www.cnblogs.com/wwg168/p/6227321.html
Copyright © 2020-2023  润新知