redis 击穿、穿透、雪崩、setnx锁和LUA脚本

 

击穿:

高并发请求到达,刚好redis中的某个key过期,直接访问数据库。

解决:

setnx() ->锁,只有获得锁的去访问DB,然后放到redis。

1.get key   2. setnx  3-1。ok,去DB取。 3-2 .false,slepp ->

上面2引发问题:如果第一个人挂了,设置超时时间。

如果没挂,但是锁超时了。--》多线程,一个线程取DB,一个线程监控是否取回来,更新锁时间。

 

穿透:

访问根本不存在的数据,然后取数据取了。

解决:redis集成布隆过滤器。

带来问题,只能新增,不能修改、删除。当有很多数据需要新增时。

只能换个可以增加、删除的过滤器,例如布谷鸟。

 

雪崩:

大量访问到达,同时大量key失效。

什么时候会造成雪崩:

1. 和时点性无关。 可以通过设置随机时间解决

2. 零点,比如做活动过了24点失效。 解决:强依赖击穿方案。 或者在业务层进行延时,到零点了休眠一会。

 

redis 分布式锁

1.setnx

2.过期时间

3.多线程(守护线程)延长过期时间 

 

setnx带来的问题:

1.第一个抢到锁的人挂了,造成死锁。解决:增加过期时间

2.没挂,但是锁超时了。加锁的时候添加了过期时间,但是在数据库连接超时,导致业务处理的过程中超时,进而锁到期了。其余的线程也去加锁,依旧后续业务连数据库的过程中超时,导致锁超时。解决:守护线程,判断取数据的时候有没有完成,没有就更新锁的过期时间。

 

解决:

zookeeper 做分布式锁。

 

setnx锁 和 LUA脚本

由于setnx与setex是分步进行,那么我们将两步合成一步,放在同一个原子中即可

* 怎么一次性执行过一条命令而不会出现问题,采用Lua脚本

* Redis从2.6之后支持setnx、setex连用

lua脚本

local lockKey = KEYS[1]
local lockTime = KEYS[2]
local lockValue = KEYS[3]

-- setnx info
local result_1 = redis.call('SETNX', lockKey, lockValue)
if result_1 == 1
then
local result_2= redis.call('SETEX', lockKey,lockTime, lockValue)
return result_2
else
return 'faild'
end
static RedisTemplate redisTemplate;
    void setNx(){
        String threadName = Thread.currentThread().getName();
        Boolean isLocked = getLuaScript("lockRedis",threadName);
        String value = (String)redisTemplate.opsForValue().get("lockRedis");
        if(!isLocked){
            System.out.println(" 抢锁失败,当前值:" + value);
        }else{
            try {
                System.out.println(" 获取锁成功");
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                if(value.equals(threadName)){//如果锁的所有者是当前这个线程的,就释放
                    redisTemplate.delete("lockRedis");
                }
            }
        }
    }

    boolean getLuaScript(String key,String value){
        DefaultRedisScript<String> lockScript = new DefaultRedisScript<>();
        lockScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redisLock.lua")));
        lockScript.setResultType(String.class);
        List<Object> parList = new ArrayList<>();
        parList.add(key);
        parList.add(30);
        parList.add(value);
        String result = (String)redisTemplate.execute(lockScript,parList);
        if("ok".equals(result.toLowerCase())){
            return true;
        }
        return false;
    }

or

redisTemplate.opsForValue().setIfAbsent("key2","isvalue",30, TimeUnit.MICROSECONDS);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值