Redis使用指南

原文链接

能坚持别人不能坚持的,才气拥有别人未曾拥有的。
关注编程大道民众号,让我们一同坚持心中所想,一起发展!!

设置过时时间、释放资源

使用Redis做K-V存储,一定要注意过时时间的把控,任何K-V的存储都要设置过时时间,不管多长时间。一样平常在封装Redis操作工具类时提供默认使用系统公共超时时间的操作API,制止新手在使用时不设置过时时间,导致内存的虚耗。另外,通过毗邻池 Jedis jedis = JedisPool.getResource(); 这样获取Redis毗邻最好使用try/finally块,并且在finally块中挪用 jedis.close(); 将毗邻归还给毗邻池,否则将会一直持有毗邻,很有可能导致在未来的某一时刻报拿不到毗邻的错。这也是之前某一个同事犯过的错导致生产bug!

缓存穿透

你以为Redis做缓存就万无一失吗?就单纯的遵照那种经典操作吗?(即:请求来了,先看缓存有没有,有直接返回,没有就查数据库,数据库有的话先存缓存,然后返回,数据库没有就返回空)这样就是Redis缓存的准确姿势吗?若是你这样做,很可能疏忽一点,那就是缓存穿透。如之前在项目中做的一个需求-页面广告可设置化自动上下线(我在之前专门写过一篇文章先容这个需求的一步步演进历程,对Redis新手很有辅助,感兴趣的可以去看看),简朴的提一下吧,就是好比在支付完成的页面人人都应该见过吧,好比支付完成后的效果页,可能会弹出来一个红包什么的,页面下方的广告位等,就是类似的这样一个需求。由于这个页面访问量很大,进这个页面就查这个广告位的数据,当运营最近不想设置广告了,这边查到的是不是就是是空啊?数据库也是空的,缓存也没有数据,那许多请求都来,这样就平白无故的造成了数据库的压力呀,何等的虚耗!若是是其余其他营业,黑客钻了空子,专门请求你系统基本不存在的数据,请求多了,都打到数据库,是很有可能把你数据库打死的。若是你在做需求的时刻没想到这一点,那后续出了问题,你就等着背锅了。

怎么制止呢?

好办,可以将数据库也不存在的数据存个null值或一个空json(总之你自己约定好就行),也给放到Redis里,设置个较短的过时时间,下次再来取的时刻看到是空就直接返回。另外,可以使用布隆过滤器做一层系统级的防护,专门去阻挡系统中基本不存在的key。

缓存雪崩

刚说完缓存穿透,再聊聊缓存雪崩。好比你将用户数据放到缓存里,当某一时刻这些数据全部都过时了,大量请求都过来,发现缓存无法掷中,不就都去数据库了吗,数据库一下子来这么多请求不就搞挂了吗?解决办法就是只管是key的过时时间分散开,不要集中。在一个牢固的过时时间上+一个随机值,好比你设置的过时时间是5小时,你可以加一个0-600秒的随机值。

缓存并发

缓存失效时多个请求同时请求同一个key,都发现缓存中空了,都去查数据库,这不是虚耗吗,正常一个去查就行了,查完放缓存其余请求直接从缓存拿就行了。这就是缓存并发问题。当请求异常的多的时刻,会对数据库造成很大的打击,也是有可能把数据库搞挂的吧?怎么解决,可以对更新缓存的操作加锁,使用synchronized吗?不行,由于生产上是分布式部署的,需要使用redis分布式锁。

例如,当缓存数据失效的时刻,某一线程使用资源ID作为key实验加分布式锁,加锁乐成的线程执行更新缓存的操作将查到的数据放入缓存缓存中,其他线程就可以直接使用缓存数据了。

分布式锁

正如上面所说,在集群部署的情形下synchronized就失效了,以是分布式锁就派上用场了。常见的分布式锁的实现方式有三种:基于数据库,基于Redis,基于Zookeeper。

Redis分布式锁需要特别注意的点就是锁的过时时间,如,使用redis的setnx下令,设置乐成即示意拿到锁,然后设置过时时间,下令执行失败的线程示意获取锁失败。一定要注意锁的过时时间的设置,有加锁的操作,也要有解锁的操作。如之前我们项目的一个临时性的一个组团赛跑的流动,10人成团赛跑PK的流动,在组团阶段,用户可以约请同伙加入自己的团。我们的团数据是存放在Redis中的,包罗每个团的人数。当用户提议入团操作时,后台逻辑会从redis取该团的现有成员数,若是小于10才气继续走下面的逻辑。当并发场景下,如团长分享给许多人入团约请,这些人的入团请求并发执行的情形下很有可能能造成组团人数跨越10人的情形。由于在并发场景下,执行获取当前团成员数的这行代码会被多个请求获取到,好比临界的时刻,团成员已经有了9个,同时来了俩入团请求,若是不加控制,同时执行读取现有团成员个数时都读到的是9,然后都执行入团操作,就会造成团成员跨越10人的bug。

你知道吗,Flutter内置了10多种Button控件

以是在入团请求的逻辑上,要加分布式锁,获取到锁才气执行后续逻辑。由于获取锁的操作是使用setnx下令,并没有守候锁的机制,我们需要在获取锁的逻辑加一个自旋,每隔一定时间实验一次获取,跨越一定时间后返回加锁失败。

public boolean tryLock(String lockKey,long expireTime){
    long waitTime = 0;
    //setIfAbsent使用的是redis的setnx方式
    boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey,"jingzouLock",
            expireTime,TimeUnit.MILLISECONDS);
    if(success==true){
        return success;
    }else{
        while(success==false && waitTime <50000L){
            success = redisTemplate.opsForValue().setIfAbsent(lockKey,"jingzouLock",
                    expireTime, TimeUnit.MILLISECONDS);
            try{
                Thread.sleep(100);
            }catch(Exception e){}
            waitTime+=100L;
        }
    }
    return success;
}

另外,还需要遵照“解铃还须系铃人”的原则,谁加的锁谁解,否则自己加的锁,被别人解了也是会造成问题的。例如,用户A,请求入团,拿到分布式锁,若是A由于某些原因在锁超时时间内没有执行完代码,锁就过时自动释放了,若是此时B请求加入同一个团,拿到了分布式锁,若是此时A请求执行完了,释放锁了,然则释放的是B的锁,这样也有可能造成团人数跨越10的bug。以是,设置分布式锁时的value可以设置成差别的值,如A请求是用户ID为12的用户,设置分布式锁的时刻就value就可以用这个唯一的元素,当解锁的时刻再验证value是12时才气执行解锁操作。

如上加锁代码,我们增添一个参数String value传入动态值,在上述场景中可以用用户ID,取代我们写死的”jingzouLock”。然后在释放锁的方式里,我们先判断value值,相同再执行删除。

public void releaseLock(String lockKey,String value){
    String valueInRedis = redisTemplate.get(lockKey);
    if(value.equals(valueInRedis)){
        redisTemplate.delete(lockKey);
    }
}

另有一种场景需要思量。当Redis master发生故障,主备切换时往往会造成数据丢失,包罗分布式锁的Key-Value。这样就会导致锁间接的被释放了,如果操作还没执行完,锁被其他请求拿到了,分布式锁就起不到作用了。

思量到这方面的问题,Redis官方提供了Redlock算法,以及响应的开源实现Redisson。用到分布式锁的场景,人人可以直接使用 Redisson,异常利便,后期可能会写一写Redisson的手艺干货。

原文地址:https://mp.weixin.qq.com/s/2sXEkRsrC9b9RBJns3fnnw

另外,若是系统对可靠性要求很高,如需用到分布式锁,建议使用分布式锁的另外实现方式,如:Zookeeper,etcd等。

好了,今天就分享到这。若是感受本文对您有辅助,有劳点下在看,把知识分享给更多的人哦

你可能感兴趣的文章:
《[需求设计]从一个小需求感受Redis的怪异魅力》
Hot
《【面试突击】— Redis篇》–Redis数据类型?适用于哪些场景?
《【面试突击】— Redis篇》–Redis的线程模子领会吗?为啥单线程效率还这么高?
《【面试突击】— Redis篇》– Redis的主从复制?哨兵机制?
《【面试突击】— Redis篇》– Redis哨兵原理及持久化机制
《【面试突击】— Redis篇》–Redis Cluster及缓存使用和架构设计的常见问题
《你真的领会Redis的公布订阅?》
《Redis缓存穿透,缓存击穿,缓存雪崩,热门Key》
《高并发场景下缓存+数据库双写不一致问题剖析与解决方案设计》
《什么?我往Redis里写的数据怎么没了?》
C
L
I
C
K
M
E

以为悦目,请点赞哦~

 

关注民众号 编程大道 ,第一时间获文章推送。

以为悦目,请 点赞、关注、转发 哦~

Redis使用指南

原创文章,作者:admin,如若转载,请注明出处:https://www.2lxm.com/archives/1177.html