应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

经常用Redis,这些坑你知道吗?

  文章转载自二马读书,作者二马读书
  作者简介:曾任职于阿里巴巴,每日优鲜等互联网公司,任技术总监,15年电商互联网经历。
  近些年,Redis凭借在性能、稳定性和高可扩展性上的卓越表现,基本上已经成了互联网行业缓存中间件的标配,甚至很多传统行业也在使用Redis。那么我们在使用Redis等缓存中间件时,要注意哪些问题呢?本文咱们就来聊聊,我们使用缓存中间件过程中曾经遇到的坑!
  缓存穿透
  先看一个常见的缓存使用方式。请求来了,先查缓存,缓存有值就直接返回;缓存没值,查数据库,然后把数据库的值存到缓存,再返回。
  假如缓存没查到某个值,查数据库也没这个值,也就是说要查的值根本不存在,这样就会导致每次对这个值的查询请求都会穿透到数据库。这就是所谓的缓存穿透。
  如何避免缓存穿透?
  如果从数据库中没查到值,可以在缓存中记录一个空值,来避免缓存穿透。并且要给这个空值设置一个较短的过期时间。
  比如说,我们经常会把用户信息缓存到Redis。如果调用方传了一个不存在的UserID,在缓存中就查不到这个用户信息,然后去DB也查不到。这样就会导致,每次根据这个UserID查用户信息,都会穿透到数据库,给数据库造成了压力。为了避免缓存穿透,当数据库查不到时,我们可以在缓存中记录一条空数据,比如userID做为key,空json做为值,如果程序获得这个空json,就按用户不存在处理。再给这个key设置一个很短的过期时间,比如30秒。
  缓存雪崩
  我们经常会遇到需要初始化缓存的情况。比如说用户系统重构,表结构发生了变化,缓存信息也要变,上线前需要初始化缓存,将用户信息批量存入缓存。假如我们给这些用户信息设置相同的过期时间,到过期时间点所有用户信息的缓存记录就会同时集中失效,导致大量请求瞬间打到数据库,数据库很可能会被搞挂。这种缓存集中失效,导致大量请求同时穿透到数据库的情况,就是所谓的雪崩效应。
  所以,当我们向缓存初始化数据时,要保证每个缓存记录过期时间的离散性。可以采用一个较大的固定值加上一个较小的随机值。比如过期时间可以是:10小时0到3600秒的随机值。
  缓存并发
  当系统并发很高,缓存数据尤其是热点数据过期后,可能会出现多个请求同时访问数据库并设置缓存的情况,不但给数据库带来压力,而且会有缓存频繁更新的问题。
  我们可以通过加锁来避免缓存并发问题。如果从缓存查不到数据,对查询数据加分布式锁,然后查数据库并把数据库查询结果放入缓存。其他线程等待锁释放后,直接从缓存取值。
  比如,电商系统会缓存商品SKU价格,一些热点商品的并发访问会非常高。当缓存过期失效后,访问请求从缓存查不到记录,此时可以用商品SKUID为Key加分布式锁,然后从数据库查询价格并把价格放入缓存,最后解锁。解锁后其他请求就可以从缓存直接取值了。从而避免了数据库的压力。
  分布式锁
  以我们之前做过的5人拼团为例。如果有用户参加团购,我们需要先校验参团人数是否达到了上限5人。如果没达到5人,用户才可以参团。伪代码如下:根据拼团ID获取目前参团成员数量intnumOfMemberspinTuanService。getNumOfMembersById(pinTuanID);if(numOfMembers5){pinTuanService。pintuan();执行,加入拼团,生单等逻辑}
  高并发场景下,上面的代码会有很严重的问题。如果某个团当前的参团人数是4,这时有两个用户同时参团,用户A和用户B的请求同时进入上面的代码块,A和B的请求同时执行到第2行代码,获取的numOfMembers都是4,表达式numOfMembers5成立,所以两个用户都能执行到第4行代码,就是说A用户和B用户都能成功参加拼团。于是,参团人数就超过了5人的上限。所以我们就需要加锁来避免这个问题。synchronized行吗?不行。因为我们的服务是多节点部署的,所以要加分布式锁。代码如下:
  booleanaquireddistributedLock。aquireLock(pinTuanID,3000);if(aquiredtrue){try{根据拼团ID获取目前参团成员数量intnumOfMemberspinTuanService。getNumOfMembersById(pinTuanID);if(numOfMembers5){pinTuanService。pintuan();执行,加入拼团,生单等逻辑}}finally{distributedLock。releaseLock(pinTuanID);}}
  这样就好多啦!接下来我们看看基于Redis分布式锁的实现,以及特别要注意的问题。一般我们会基于setnx实现Redis分布式锁。setnx命令可以检查key是否存在,如果key不存在,就在Redis中创建一个键值对(操作成功),如果key已经存在就放弃执行(操作失败)。
  先看一段基于Springboot实现的加锁和释放锁的代码:
  ComponentpublicclassDistributedLock{AutowiredprivateStringRedisTemplateredisTemplate;加锁lockKey,redis的keyexpireTime,过期时间,单位是毫秒注:setIfAbsent方法就使用了redis的setnxpublicbooleanaquireLock(StringlockKey,longexpireTime){longwaitTime0;booleansuccessredisTemplate。opsForValue()。setIfAbsent(lockKey,distributedLock,expireTime,TimeUnit。MILLISECONDS);if(successtrue){returnsuccess;}else{如果加锁失败,循环重试加锁while(success!truewaitTime5000L){successredisTemplate。opsForValue()。setIfAbsent(lockKey,distributedLock,expireTime,TimeUnit。MILLISECONDS);sleep100毫秒;waitTime100L;}}returnsuccess;}释放锁lockKey,redis的keypublicvoidreleaseLock(StringlockKey){redisTemplate。delete(lockKey);}}
  上面的代码。乍一看,好像没什么问题!加锁失败有循环重试加锁,过期时间设置了,而且也保证了创建KeyValue键值对和设置过期时间的原子性,这样当程序没有正常释放锁时,也能保证过期后锁自动释放(注意:redis较老的版本不支持setnx和设置过期时间的原子操作,不过可以利用Lua脚本来保证原子性)。
  我们再仔细思考一下,一般场景我们会对Key设置一个很短的过期时间,当一次操作因为网络等原因耗费了较长时间,操作还没完成key就过期失效了。这样会产生什么问题呢?我们还是以拼团为例加以说明,先看看下面这张图:
  如上图,用户A和用户B同时参加同一团,团ID为001,我们以团ID作为分布式锁的Key,distributedLock作为固定的Value,过期时间是5秒。A先获取分布式锁,但是由于网络等原因A的拼团操作在5秒内没完成,这时Key过期并从Redis清除掉,A的分布式锁失效。此时用户B拿到分布式锁,Key也同样是团ID001。在用户B的拼团逻辑执行完之前,用户A的逻辑先执行完了,紧接着A就把锁给释放了。不过A的锁早已经过期失效了,B持有锁的Key和A又完全一样,所以此时A释放的其实是B的锁。这样一来整个拼团还是有可能会超员。怎么解决呢?
  我们可以把分布式锁的Value设成可以区分的值,比如拼团的场景Value可以设置为userID,在释放锁的时候根据key和value来判断当前的锁是不是自己的,只有Redis中userID和自己的userID相同才释放锁。
  改进后的代码如下:
  ComponentpublicclassDistributedLock{AutowiredprivateStringRedisTemplateredisTemplate;加锁lockKey,redis的keyexpireTime,过期时间,单位是毫秒注:setIfAbsent方法就使用了redis的setnxpublicbooleanaquireLock(StringlockKey,StringuserID,longexpireTime){longwaitTime0;booleansuccessredisTemplate。opsForValue()。setIfAbsent(lockKey,userID,expireTime,TimeUnit。MILLISECONDS);if(successtrue){returnsuccess;}else{如果加锁失败,循环重试加锁while(success!truewaitTime5000L){successredisTemplate。opsForValue()。setIfAbsent(lockKey,userID,expireTime,TimeUnit。MILLISECONDS);sleep100毫秒;waitTime100L;}}returnsuccess;}释放锁lockKey,redis的keypublicvoidreleaseLock(StringlockKey,StringuserID){StringuserIDFromRedisredisTemplate。get(lockKey);if(userID。equals(userIDFromRedis)){redisTemplate。delete(lockKey);}}}
  还有一种场景需要考虑。当Redismaster发生故障,主备切换时往往会造成数据丢失,包括分布式锁的KeyValue也可能丢失。这样就会导致操作还没执行完,锁就被其他请求拿到了。Redis官方提供了Redlock算法,以及相应的开源实现Redisson。用到分布式锁的场景,大家可以直接使用Redisson,非常方便。如果系统对可靠性要求很高,如需用到分布式锁,建议使用Zookeeper,etcd等。
  OK,就分享到这。如果感觉本文对您有帮助,有劳点下在看,分享知识是美德哦

故事一个女儿追忆妈妈平凡而又伟大的一生75年前在一个农家四合院,一个女婴呱呱坠地,老来得女的老豹爷更是乐得合不上嘴,敲锣打鼓迎接小生命的到来。老豹爷是冯玉祥将军的部下,虽不算高权大贵,但也是有钱有势,出生在这……是的我,给我放这!工作被抢功,要不要自己讨回公道?等公交花了15分钟,你决定继续等下去,还是打车回去?大多数人都会选择继续等下去,原因是:1。舍不得已经投入了时间。2。打车成本更高。3。万一刚打上车,从后车窗看到公交车进……成长心理学给予孩子放松的成长空间凯迪拉克效应:顺应孩子的成长特点生活中,父母常常按照自己固有地认识和愿望去培养孩子,却忽视了孩子本身是一辆马力十足的轿车,而自己却正用两匹马的力量在拉着他前行。这就是著名……今天,我被一个铁杆粉丝的白发奶奶鞠躬感谢了题首:门诊日记系列:2021年10月24日,星期日,阴天,下午,专家门诊。门诊病例故事:下午,我的专家门诊,在老院区,一般病人不多,因为我也是一个本地不知名的……父母应如何教育子女?广州一小女孩被亲生妈妈两次扔进垃圾桶父母应如何教育子女?广州一小女孩被亲生妈妈两次扔进垃圾桶。近日,广州街头一小女孩站在垃圾桶里长达20余分钟。视频中身穿红色短袖的小女孩站在一个垃圾桶中一动不动,周围有几个……一部好的电影,永远是反战的战马这是一部带有文艺史诗风格的电影《战马》。斯皮尔伯格是个会讲故事的导演。英国乡野少年、皇家骑兵上尉、法国农场主祖孙,以及许许多多的交战双方士兵,因为一匹生命力顽强的战……奥运冠军有多幸福?奖金有多少?中国运动员奖励清单出炉我们看看各个国家对冠军的奖励。菲律宾金牌得主430万人民币2套住房终身免费航班菲律宾本周在东京夺得了有史以来的第一块金牌,使得菲律宾举重运动员希迪林迪亚兹成为该国第……不穿内衣,胸部会下垂?我敢说:在不用出门的周末,没有一个姑娘愿意穿上内衣。因为没有束缚的感觉,真的是太爽了!!!动图来源于soogif但在放飞自我的同时,又特别纠结和担心:不……中年妈妈养娃实录你我本无缘,全靠我砸钱文安语时来源凯叔讲故事这两天陈奕迅的采访上了热搜。他说自己今年已经很久没有工作了,全在吃老底,还得了挺严重的病荷包肝硬化和急性发钱寒。哈哈哈,看完真是笑……圣诞节快到了,大家肯定在为送礼物忙的焦头烂额,不知道送啥好嘞嘻嘻我写了一些圣诞礼物清单,可以给大家一些参考吖!笔记目录分为:1、超有圣诞气氛的零食类for:送对象,送同事同学2、圣诞高颜值礼盒类for:颜控女生们3、圣……比高考更重要的东西,你有意识到并且教育过孩子吗?上篇微头条讲到,高考对于一生来说,不一定是特别重要的事,我说还有比高考更重要的事,其中就有培养强而正面的感知力。感知力之所以重要,是因为,当一个状况出现的时候,不同的人对……酒局上一场权利的游戏,不会玩你就出局强者用逼人喝酒彰显权威和控制力,弱者用自虐式主动喝酒表白忠诚和服从。你看得到交换的酒杯,没看到交换的利益,你看得到干掉的白酒,看不到干掉的尊严。1hr早几年前,酒对……
除了遗传和疾病,导致孩子身材矮小的原因还有什么?基本上每个家长都希望自己的孩子能够拥有理想的身高。而现实生活中,却有这样一些孩子,因为个子矮小而常被小伙伴们取笑,生活在自卑的阴影中,他们变得内向、自闭。根据临床数据显示,大多……3克就能致婴幼儿死亡!网红玩具黑名单出炉,看完一身冷汗文CC爸妈公众号:CC爸妈ID:ccbama掐指一算,你家娃放寒假了吧?因为疫情的缘故,今年注定又是一个特殊年。国家领导人都就地过年了,咱老百姓是否也得响应下……原来,我们一直在伤害男孩有一种孩子叫别人家女儿。人家女儿整天吃了睡睡了吃,我家儿子一放下就哭,哭就哭会儿吧,可是歇斯底里嚎了半小时都不肯停;人家女儿坐在那一玩就两三个小时,我家儿子一刻不停、一不留神就……中年职场女性,人生可以格式化重来么?有可能成功吗?文明白姐蓉蓉姐至今不敢告诉老妈自己离职创业了,原因无他,因为看不到自家公司起死回生的可能,对父母没法交代。蓉蓉姐之前一直是别人家孩子的代表,在父母眼里她很乖很听话,……双胞胎兄弟,一个国外长大,一个国内长大,20年后差距明显文章纯属原创,版权归本作者所有,欢迎个人转发分享。孩子能给父母和家庭带来喜悦,双胞胎则是给了我们双重的惊喜和体验,对于父母和家庭来说还意味着双重的压力和疲累,需要我们付出……不加一滴水的蛋挞,补钙又补锌,比外面买的好吃N倍,一学就会南瓜除了口感较好,味道香甜以外,它的营养价值也非常高。南瓜含有丰富的维生素C、微量元素以及蛋白质等多种营养成分,特别要注意的是南瓜中含有大量的锌,这是参与人体核酸、蛋白质合成的……清华录取书还未捂热,入学资格就被取消,投机取巧终将自食其果导语:大部分考生,在上学期间,都曾有过考清华的想法,但是由于这所学校的招生名额有限,再加上录取分数也特别高,所以每年在高考当中,能够考入清华大学的学生都是寥寥无几的。因此……每一个人都是唯一的人类历史基因是群体动物,然后喜欢从众,把自己消失在人海中,在茫茫的人海中,你看不到他是最好的,这个在过去阶级斗争时代和计划经济时代体现的淋漓尽致。结合中国的传统文化和思想……孩子突然变得爱学习?当心!这很可能是个坑开学一个月以来北京市海淀区的学生家长张戒发觉自己刚上初二的孩子变得越来越爱学习了要了好几次零花钱买文具张戒后来才知道孩子买的是现在流行……如果你或者你的身边有人出现这几句口头禅,她可能已经患上抑郁症从农业社会走向工业社会,社会节奏的加快,必然伴随着焦虑,在我们的文化中,主要有四种逃避焦虑的方式。一、把焦虑合理化。二、否认焦虑。三、麻醉自己。四、回避一切可能导致焦虑的思想情……家长的五个舍得层次,父母的品格是孩子的起跑线同样的家庭环境和背景,会因为父母们不同的教育方式而培养出不同的孩子,家长的格局就是孩子未来世界的格局,今天我们就来看一看家长们的五个层次。舍得为孩子花钱舍得为孩子花时间舍得为思……读易说谦卦这才是最锐利的武器,家庭内外都无往不胜自信而高尚:谦逊是最锐利的武器据《韩诗外传》记载,周公曾告诫他的儿子伯禽说:《易》有一道,大足以守天下,中足以守其国家,小足以守其身,谦之谓也。可见,圣人在《大有卦……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网