redis缓存加锁
㈠ 缓存击穿、穿透、雪崩及Redis分布式锁
分布式锁: setnx ,redisson 并发问题
幂等问题: 落表状态,Redis
缓存击穿: 指缓存中无,db中有
原因: 一个key高并发恰好失效导致大量请求到db
方案: 加锁,自旋锁,或一个线程查db,一个线程监控(直接用Redisson分布式锁)
缓存穿透:指缓存和db中均无
原因: 一般是恶意请求
方案: 加布隆过滤,或查db无时,也设置缓存,value为某些特殊表示或"null"
雪崩:指缓存同时大量失效
原因: 大量的key同时失效,db压力加大
方案: 设置失效时间是增加随机数
问题方案文献:
https://www.jianshu.com/p/31ab9b020cd9 (图例分析)
https://blog.csdn.net/fcvtb/article/details/89478554
Redis分布式锁:
事务未执行完锁已到期释放问题:使用Redissoin解决续租问题,内部已解决
分布式锁文献:
https://www.jianshu.com/p/4838f8be00c9
https://blog.csdn.net/qq_30038111/article/details/90696233 (setnx + expire同时操作)
====================================
https://www.runoob.com/redis/keys-scan.html
https://www.jianshu.com/p/611a492d9121 Redis原理与应用
㈡ 濡备綍浣跨敤redis瀹炵幇鍒嗗竷寮忛挛锷熻兘锛
鐢变簬redis鏄鍗旷嚎绋嬬殑涓旀ц兘寰埚揩锛屾墍浠ユ瘆杈冮傚悎锅氩叏灞鍒嗗竷寮忛挛銆
锘烘湰娴佺▼灏辨槸鍦ㄦ搷浣滃彲鑳芥煇涓鍏ㄥ眬鍐茬獊璧勬簮镄勬椂鍊欙纴浣跨敤涓涓鍏ㄥ眬鍞涓key𨱒ュ垽鏂鏄钖︽湁鍏朵粬绾跨▼鍗犵敤浜呜祫婧愶纴濡傛灉链夊叾浠栫嚎绋嫔崰鐢锛屽垯鎶ラ敊阃鍑烘垨钥呭惊鐜绛夊緟銆傚傛灉娌℃湁鍏朵粬绾跨▼鍗犵敤锛屽垯灏卞彲浠ラ氲繃娣诲姞鍒嗗竷寮忛挛𨱒ュ崰鐢ㄨ繖涓璧勬簮锛岀劧钖庡啀镓ц屽悗缁镄勪换锷★纴鍦ㄤ换锷℃墽琛屽畬鎴愪箣钖庯纴鍐嶉喷鏀惧垎甯冨纺阌侊纴鍏朵粬绾跨▼灏卞彲浠ョ户缁浣跨敤杩欎釜璧勬簮浜嗐
闾d箞阃氲繃redis锷犻挛镄勫姩浣沧槸浠涔埚憿锛
绠鍗曞姞阌佸懡浠わ细
锻戒护鏄锛歴etnx
鍐呴儴镄勫疄鐜版満鍒跺氨鏄鍒ゆ柇杩欎釜key浣岖疆鏄涓嶆槸链夋暟鎹锛屾病链夋暟鎹灏辫剧疆鎴恦alue杩斿洖锛屾湁鏁版嵁灏辫繑锲炰竴涓鐗规畩鏁板笺
浣嗘槸杩欓噷链変竴涓闂棰樻槸锛屽傛灉鍗犵敤璧勬簮镄勭嚎绋嬮敊璇阃鍑轰简锛屾病链夋潵寰楀强閲婃斁鍒嗗竷寮忛挛锛岃繖涓阌佸氨琚姘歌繙镄勫崰鐢ㄤ简
鏀硅繘鐗堢殑锷犻挛锛
锻戒护鏄锛1. setnx 2. expire
娣诲姞鍒嗗竷寮忛挛镄勫悓镞讹纴娣诲姞涓涓阌侀挛杩囨湡镄勬椂闂淬傝繖镙凤纴褰揿姞阌佺嚎绋嬮鍑轰箣钖庯纴镊冲皯绛変竴娈垫椂闂翠箣钖庯纴阌佹槸链夋満浼氶喷鏀炬帀镄勚
杩欓噷链変竴涓灏忛梾棰樻槸锛岃繖涓や釜锻戒护鏄鍒嗗紑镓ц岀殑锛屼笉鏄铡熷瓙镎崭綔銆傞偅涔埚氨瀛桦湪鐞呜轰笂𨱒ヨ达纴绗涓涓锻戒护镓ц屽畬涔嫔悗锛屽氨鍑虹幇阌栾锛屾潵涓嶅强镓ц宔xpire锻戒护镄勫彲鑳斤纴涓绉嶅姙娉曟槸镊宸卞啓lua鑴氭湰锛屽彲浠ュ疄鐜板氭浔锻戒护镄勫师瀛愬寲镓ц屻备竴绉嶅姙娉曟槸寮旷敤涓浜涘紑婧愬簱銆傚湪2.8鐗堟湰涔嫔悗锛宺edis涓轰简瑙e喅杩欎釜闂棰桡纴鎻愪緵浜嗗畼鏂圭増镄勮В娉曪纴灏辨槸锻戒护锛歴et key value nx expireTimeNum ex锛屽皢涓婅堪涓や釜锻戒护钖埚苟鎴愪简涓涓锻戒护銆
链変简杩囨湡镞堕棿涔嫔悗瑙e喅浜嗕竴閮ㄥ垎闂棰桡纴浣嗘槸涔熸湁鍙鑳藉嚭鐜伴挛閮借繃链熶简锛屼絾鏄涓闂存墽琛岀殑浠诲姟杩樻病链夌粨𨱒燂纴绗涓涓绾跨▼杩桦湪镓ц屼简锛岀浜屼釜绾跨▼宸茬粡𨰾垮埌阌佸紑濮嬫墽琛屼简锛岄偅涔堣繖镞跺欑涓涓绾跨▼濡傛灉镓ц屽畬鎴愪箣钖庯纴闾d箞灏变细灏嗙浜屼釜绾跨▼镄勯挛閲婃斁鎺変简銆傜浜屼釜绾跨▼閲婃斁阌佺殑镞跺欙纴瑕佷笉铹跺嚭阌欙纴瑕佷笉铹舵槸閲婃斁镄勫叾浠栫嚎绋嬬殑阌侊纴杩欐牱涔熶细鍜岄勬湡涓岖︺
濡傛灉鍗旷函鍦拌佽В鍐宠繖涓闂棰樼殑璇濓纴鍙浠ュ湪璁剧疆value镄勬椂鍊欎娇鐢ㄤ竴涓闅忔満鏁帮纴閲婃斁阌佺殑镞跺欙纴鍏埚垽鏂杩欎釜闅忔満鏁版槸钖︿竴镊达纴濡傛灉涓镊村啀鍒犻櫎阌侊纴钖﹀垯灏遍鍑恒备絾鏄鍒ゆ柇value鍜屽垹闄key涔熶笉鏄涓涓铡熷瓙镎崭綔锛岃繖镞跺椤氨闇瑕佷娇鐢╨ua鑴氭湰浜嗐
涓婇溃镄勬柟妗堜緷铹朵笉鑳借В鍐宠秴镞堕喷鏀剧殑闂棰桡纴渚濈劧杩濊儗鍒嗗竷寮忛挛镄勫埯琛枫傛庝箞锷炰简锛
瑙i樻濊矾鏄鍙﹀栧惎锷ㄤ竴涓绾跨▼锛屽畠镄勪换锷″氨鏄姣忛殧涓娈垫椂闂村垽鏂涓涓嫔傛灉鍙戠幇褰揿墠绾跨▼镄勪换锷″揩杩囨湡浜呜缮娌℃湁瀹屾垚锛屽垯瀹氭湡缁椤綋鍓岖嚎绋嬬殑阌佺画涓链熴
链変釜寮婧愬簱瑙e喅浜呜繖涓闂棰桡纴瀹冨ぇ姒傜巼浼氭瘆浣犲疄鐜板缑镟村ソ涓浜涖傝繖涓搴揿氨鏄痳edisson锛岄潪甯稿ソ璁帮纴灏辨槸redis镄勫効瀛恠on锛岃繛璧锋潵灏辨槸reidsson锛岃槠铹跺彲鑳戒笉鏄浜茬殑锛屼絾鏄涔熻冻澶熶简銆
杩欎釜搴挞噷闱㈡湁涓涓缁勪欢鏄痺atchdog锛岀洿璇戣繃𨱒ュ氨鏄鐪嬮棬镫楋纴瀹幂殑浣灭敤灏辨槸姣忛殧涓娈垫椂闂村垽鏂镄勚
鍐岖户缁镐濊冿纴杩樻湁涓涓镟存瀬绔镄勯梾棰樻槸锛宺edis濡傛灉鏄鍗曡妭镣圭殑锛屽畠瀹曟満浜嗭绂鎴栬呮槸涓诲囱妭镣圭殑锛屼絾鏄澶囦唤鑺傜偣杩樻病链夋潵寰楀强钖屾ヤ富鑺傜偣镄勬暟鎹锛屼富鑺傜偣𨰾垮埌阌佷箣钖庯纴鍦ㄥ悓姝ユ暟鎹涔嫔墠灏遍┈涓婂畷链轰简锛屽垯涔熸湁鍙鑳藉嚭鐜伴挛涓崭綇镄勯梾棰樸傚傛灉璁や负杩欐槸涓涓闂棰桡纴𨱍宠佽В鍐宠繖涓闂棰桡纴杩欎釜闂棰樻庝箞瑙e喅浜嗭纻
镐濊矾鏄鍦ㄥ姞阌佺殑镞跺椤氩姞阌佸嚑鍙皉edis链嶅姟鍣锛岄氩父𨱍呭喌涓媟edis閮ㄧ讲镄勬椂鍊欐槸2n+1鍙帮纴闾d箞鍦ㄥ姞阌佺殑镞跺欓渶瑕佷缭璇佽繃鍗婃暟链嶅姟鍣ㄥ姞阌佹垚锷熶简锛屼篃灏辨槸璇磏+1鍙版湇锷″櫒銆傝繖镞跺欓櫎闱炴暣涓闆嗙兢閮戒笉鍙鐢ㄤ简锛屽垯杩欎釜瀹夊叏镐у皢澶у箙搴︽彁鍗囥
杩欎釜闂棰树篃链夊紑婧愬簱瑙e喅浜嗭纴灏辨槸redis绾㈤挛銆
涓嬩竴涓闂棰樻槸鍒嗗竷寮忛挛鍙浠ラ吨鍏ヤ箞锛
濡傛灉𨱍宠佸疄鐜板彲閲嶅叆镄勫垎甯冨纺阌佺殑璇濓纴闇瑕佸湪璁剧疆value镄勬椂鍊椤姞涓婄嚎绋嬩俊鎭鍜屽姞阌佹℃暟镄勪俊鎭銆备絾鏄杩欐槸绠鍗旷殑镐濊矾锛屽傛灉锷犱笂杩囨湡镞堕棿绛夐梾棰树箣钖庯纴鍙閲嶅叆阌佸氨鍙鑳芥瘆杈冨嶆潅浜嗐
㈢ Redis怎么实现分布式锁
阿粉最近迷上了 Redis,为什么呢?感觉 Redis 确实功能很强大呀,一个基于内存的系统 Key-Value 存储的数据库,竟然有这么多的功能,而阿粉也要实实在在地把 Redis 来弄一下,毕竟面试的时候,Redis 可以说是一个非常不错的加分项。
为什么需要分布式锁?
目前很多的大型项目全部都是基于分布式的,而分布式场景中的数据一致性问题一直是一个不可忽视的问题,大家知道关于分布式的 CAP 理论么?
CAP 理论就是说任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。
而我们的系统最终满足的永远都是最终一致性,而这种最终一致性,有些时候有人会喜欢问关于分布式事务,而有些人则偏重在分布式锁上。
但是阿粉选择的就是使用缓存来实现分布式锁,也就是我们在项目中最经常使用的 Redis ,谈到 Redis,那真是可以用在太多地方了,比如说:
我们今天就来实现用 Redis 来实现分布式锁,并且要学会怎么使用。
1.准备使用 Jedis 的 jar 包,在项目中导入 jar 包。
jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); 这个加锁的姿势才是我们最需要了解的,不然你用的时候都不知道怎么使用。
key:加锁的键,实际上就是相当于一个唯一的标志位,不同的业务,你可以使用不同的标志位进行加锁。
requestId:这个东西实际上就是用来标识他是哪一个请求进行的加锁,因为在分布式锁中,我们要知道一件事,就是加锁的和解锁的,必须是同一个客户端才可以。
而且还有一种比较经典的就是 B 把 A 的锁给释放了,导致释放混乱,如果你不加相同的请求,A 线程处理业务,执行了加锁,锁的过期时间是5s, B线程尝试获取锁,如果 A 处理业务时间超过5s,这时候 A 就要开始释放锁,而B在这时候没有检测到这个锁,从而进行了加锁,这时候加锁的时候,A还没处理完对应业务,当他处理完了之后,再释放锁的话,要是就是直接把 B 刚加的锁释放了,要么就是压根都没办法释放锁。
SET_IF_NOT_EXIST:看字面意思,如果 key 不存在,我们进行Set操作,如果存在,啥都不干,也就不在进行加锁。
SET_WITH_EXPIRE_TIME:是否过期
expireTime:这是给 key 设置一个过期的时间,万一你这业务一直被锁着了,然后之后的业务想加锁,你直接给一直持有这个这个锁,不进行过期之后的释放,那岂不是要凉了。
上面的方法中 tryGetDistributedLock 这个方法也就是我们通常使用的加锁的方法。
大家看到这个 script 的时候,会感觉有点奇怪,实际上他就是一个 Lua 的脚本,而 Lua 脚本的意思也比较简单。
其实这时候就有些人说,直接 del 删除不行么?你试试你如果这么写的话,你们的领导会不会把你的腿给你打断。
这种不先判断锁的拥有者而直接解锁的方式,会导致任何客户端都可以随时进行解锁,也就是说,这锁就算不是我加的,我都能开,这怎么能行呢?
在这里给大家放一段使用的代码,比较简单,但是可以直接用到你们的项目当中
我们先把这个实现方式实现了,然后我们再来说说大家最不愿意看的理论知识,毕竟这理论知识是你面试的时候经常会被问到的。
分布式CAP理论:
加州大学伯克利分校的 Eric Brewer 教授在 ACM PODC 会议上提出 CAP 猜想。2年后,麻省理工学院的 Seth Gilbert 和 Nancy Lynch 从理论上证明了 CAP。之后,CAP 理论正式成为分布式计算领域的公认定理。
也就是说,在二十年前的时候,CAP 理论只是个猜想。结果两年之后被证实了,于是,大家在考虑分布式的时候,就有根据来想了,不再是空想了。
什么是分布式的 CAP 理论 ?
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项
这个和(Atomicity)不太一样,因为之前看有些人说,在 CAP 理论中的 A 和数据库事务中的 A 是一样的,单词都不一样,那能一样么?
Availability :分布式中的 A 表示的是可用性,也就是说服务一直可用,而且是正常响应时间。
而你在搭建分布式系统的时候,要保证每个节点都是稳定的,不然你的可用性就没有得到相对应的保证,也谈不上是什么分布式了。只能称之为一个伪分布式。
Consistency: 一致性
也就是说你的更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致,这个如果你在使用 Redis 做数据展示的时候,很多面试官都会问你,那你们是怎么保证数据库和缓存的一致性的呢?
毕竟你只是读取的话,没什么问题,但是设计到更新的时候,不管是先写数据库,再删除缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。
所以如果你对这个很感兴趣,可以研究一下,比如说:
如果你能在面试的时候把这些都给面试官说清楚,至少感觉你应该能达到你自己的工资要求。
Partition tolerance:分区容错性
分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。
其实在 CAP 理论当中,我们是没有办法同时满足一致性、可用性和分区容错性这三个特性,所以有所取舍就可以了。
关于使用 Redis 分布式锁,大家学会了么?
㈣ 使用redis实现的分布式锁原理是什么
一、写在前面
现在面试,一般都会聊聊分布式系统这块的东西。通常面试官都会从服务框架(Spring Cloud、Dubbo)聊起,一路聊到分布式事务、分布式锁、ZooKeeper等知识。
所以咱们这篇文章就来聊聊分布式锁这块知识,具体的来看看Redis分布式锁的实现原理。
说实话,如果在公司里落地生产环境用分布式锁的时候,一定是会用开源类库的,比如Redis分布式锁,一般就是用Redisson框架就好了,非常的简便易用。
大家如果有兴趣,可以去看看Redisson的官网,看看如何在项目中引入Redisson的依赖,然后基于Redis实现分布式锁的加锁与释放锁。
下面给大家看一段简单的使用代码片段,先直观的感受一下:
大家看到了吧,那个myLock的hash数据结构中的那个客户端ID,就对应着加锁的次数
(5)释放锁机制
如果执行lock.unlock(),就可以释放分布式锁,此时的业务逻辑也是非常简单的。
其实说白了,就是每次都对myLock数据结构中的那个加锁次数减1。
如果发现加锁次数是0了,说明这个客户端已经不再持有锁了,此时就会用:
“del myLock”命令,从redis里删除这个key。
然后呢,另外的客户端2就可以尝试完成加锁了。
这就是所谓的分布式锁的开源Redisson框架的实现机制。
一般我们在生产系统中,可以用Redisson框架提供的这个类库来基于redis进行分布式锁的加锁与释放锁。
(6)上述Redis分布式锁的缺点
其实上面那种方案最大的问题,就是如果你对某个redis master实例,写入了myLock这种锁key的value,此时会异步复制给对应的master slave实例。
但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。
接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。
此时就会导致多个客户端对一个分布式锁完成了加锁。
这时系统在业务语义上一定会出现问题,导致各种脏数据的产生。
所以这个就是redis cluster,或者是redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。