<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Redis 限流的 3 種方式,還有誰(shuí)不會(huì)!

          共 2900字,需瀏覽 6分鐘

           ·

          2021-12-09 10:55

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

          面對(duì)越來(lái)越多的高并發(fā)場(chǎng)景,限流顯示的尤為重要。

          當(dāng)然,限流有許多種實(shí)現(xiàn)的方式,Redis具有很強(qiáng)大的功能,我用Redis實(shí)踐了三種的實(shí)現(xiàn)方式,可以較為簡(jiǎn)單的實(shí)現(xiàn)其方式。Redis不僅僅是可以做限流,還可以做數(shù)據(jù)統(tǒng)計(jì),附近的人等功能,這些可能會(huì)后續(xù)寫(xiě)到。

          1第一種:基于Redis的setnx的操作

          我們?cè)谑褂肦edis的分布式鎖的時(shí)候,大家都知道是依靠了setnx的指令,在CAS(Compare and swap)的操作的時(shí)候,同時(shí)給指定的key設(shè)置了過(guò)期實(shí)踐(expire),我們?cè)谙蘖鞯闹饕康木褪菫榱嗽趩挝粫r(shí)間內(nèi),有且僅有N數(shù)量的請(qǐng)求能夠訪(fǎng)問(wèn)我的代碼程序。所以依靠setnx可以很輕松的做到這方面的功能。

          比如我們需要在10秒內(nèi)限定20個(gè)請(qǐng)求,那么我們?cè)趕etnx的時(shí)候可以設(shè)置過(guò)期時(shí)間10,當(dāng)請(qǐng)求的setnx數(shù)量達(dá)到20時(shí)候即達(dá)到了限流效果。代碼比較簡(jiǎn)單就不做展示了。

          當(dāng)然這種做法的弊端是很多的,比如當(dāng)統(tǒng)計(jì)1-10秒的時(shí)候,無(wú)法統(tǒng)計(jì)2-11秒之內(nèi),如果需要統(tǒng)計(jì)N秒內(nèi)的M個(gè)請(qǐng)求,那么我們的Redis中需要保持N個(gè)key等等問(wèn)題。

          2第二種:基于Redis的數(shù)據(jù)結(jié)構(gòu)zset

          ?5)?{????????????return?Response.ok("每分鐘最多只能訪(fǎng)問(wèn)5次");????????}????}????redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);????return?Response.ok("訪(fǎng)問(wèn)成功");}通過(guò)上述代碼可以做到滑動(dòng)窗口的效果,并且能保證每N秒內(nèi)至多M個(gè)請(qǐng)求,缺點(diǎn)就是zset的數(shù)據(jù)結(jié)構(gòu)會(huì)越來(lái)越大。實(shí)現(xiàn)方式相對(duì)也是比較簡(jiǎn)單的。" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">其實(shí)限流涉及的最主要的就是滑動(dòng)窗口,上面也提到1-10怎么變成2-11。其實(shí)也就是起始值和末端值都各+1即可。

          ?5)?{????????????return?Response.ok("每分鐘最多只能訪(fǎng)問(wèn)5次");????????}????}????redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);????return?Response.ok("訪(fǎng)問(wèn)成功");}通過(guò)上述代碼可以做到滑動(dòng)窗口的效果,并且能保證每N秒內(nèi)至多M個(gè)請(qǐng)求,缺點(diǎn)就是zset的數(shù)據(jù)結(jié)構(gòu)會(huì)越來(lái)越大。實(shí)現(xiàn)方式相對(duì)也是比較簡(jiǎn)單的。" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">而我們?nèi)绻肦edis的list數(shù)據(jù)結(jié)構(gòu)可以輕而易舉的實(shí)現(xiàn)該功能。

          ?5)?{????????????return?Response.ok("每分鐘最多只能訪(fǎng)問(wèn)5次");????????}????}????redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);????return?Response.ok("訪(fǎng)問(wèn)成功");}通過(guò)上述代碼可以做到滑動(dòng)窗口的效果,并且能保證每N秒內(nèi)至多M個(gè)請(qǐng)求,缺點(diǎn)就是zset的數(shù)據(jù)結(jié)構(gòu)會(huì)越來(lái)越大。實(shí)現(xiàn)方式相對(duì)也是比較簡(jiǎn)單的。" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">我們可以將請(qǐng)求打造成一個(gè)zset數(shù)組,當(dāng)每一次請(qǐng)求進(jìn)來(lái)的時(shí)候,value保持唯一,可以用UUID生成,而score可以用當(dāng)前時(shí)間戳表示,因?yàn)閟core我們可以用來(lái)計(jì)算當(dāng)前時(shí)間戳之內(nèi)有多少的請(qǐng)求數(shù)量。而zset數(shù)據(jù)結(jié)構(gòu)也提供了range方法讓我們可以很輕易的獲取到2個(gè)時(shí)間戳內(nèi)有多少請(qǐng)求

          ?5)?{????????????return?Response.ok("每分鐘最多只能訪(fǎng)問(wèn)5次");????????}????}????redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);????return?Response.ok("訪(fǎng)問(wèn)成功");}通過(guò)上述代碼可以做到滑動(dòng)窗口的效果,并且能保證每N秒內(nèi)至多M個(gè)請(qǐng)求,缺點(diǎn)就是zset的數(shù)據(jù)結(jié)構(gòu)會(huì)越來(lái)越大。實(shí)現(xiàn)方式相對(duì)也是比較簡(jiǎn)單的。" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2">代碼如下

          ?5)?{????????????return?Response.ok("每分鐘最多只能訪(fǎng)問(wèn)5次");????????}????}????redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);????return?Response.ok("訪(fǎng)問(wèn)成功");}通過(guò)上述代碼可以做到滑動(dòng)窗口的效果,并且能保證每N秒內(nèi)至多M個(gè)請(qǐng)求,缺點(diǎn)就是zset的數(shù)據(jù)結(jié)構(gòu)會(huì)越來(lái)越大。實(shí)現(xiàn)方式相對(duì)也是比較簡(jiǎn)單的。" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2">public?Response?limitFlow(){
          ????Long?currentTime?=?new?Date().getTime();
          ????System.out.println(currentTime);
          ????if(redisTemplate.hasKey("limit"))?{
          ????????Integer?count?=?redisTemplate.opsForZSet().rangeByScore("limit",?currentTime?-??intervalTime,?currentTime).size();????????//?intervalTime是限流的時(shí)間?
          ????????System.out.println(count);
          ????????if?(count?!=?null?&&?count?>?5)?{
          ????????????return?Response.ok("每分鐘最多只能訪(fǎng)問(wèn)5次");
          ????????}
          ????}
          ????redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);
          ????return?Response.ok("訪(fǎng)問(wèn)成功");
          }

          ?5)?{????????????return?Response.ok("每分鐘最多只能訪(fǎng)問(wèn)5次");????????}????}????redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);????return?Response.ok("訪(fǎng)問(wèn)成功");}通過(guò)上述代碼可以做到滑動(dòng)窗口的效果,并且能保證每N秒內(nèi)至多M個(gè)請(qǐng)求,缺點(diǎn)就是zset的數(shù)據(jù)結(jié)構(gòu)會(huì)越來(lái)越大。實(shí)現(xiàn)方式相對(duì)也是比較簡(jiǎn)單的。" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" style="color: rgb(58, 58, 58);" data-linktype="2">通過(guò)上述代碼可以做到滑動(dòng)窗口的效果,并且能保證每N秒內(nèi)至多M個(gè)請(qǐng)求,缺點(diǎn)就是zset的數(shù)據(jù)結(jié)構(gòu)會(huì)越來(lái)越大。實(shí)現(xiàn)方式相對(duì)也是比較簡(jiǎn)單的。最新面試題整理好了,大家可以在Java面試庫(kù)小程序在線(xiàn)刷題。

          3第三種:基于Redis的令牌桶算法

          提到限流就不得不提到令牌桶算法了。

          令牌桶算法提及到輸入速率和輸出速率,當(dāng)輸出速率大于輸入速率,那么就是超出流量限制了。

          也就是說(shuō)我們每訪(fǎng)問(wèn)一次請(qǐng)求的時(shí)候,可以從Redis中獲取一個(gè)令牌,如果拿到令牌了,那就說(shuō)明沒(méi)超出限制,而如果拿不到,則結(jié)果相反。

          依靠上述的思想,我們可以結(jié)合Redis的List數(shù)據(jù)結(jié)構(gòu)很輕易的做到這樣的代碼,只是簡(jiǎn)單實(shí)現(xiàn)。另外,關(guān)注Java技術(shù)棧,在后臺(tái)回復(fù):面試,可以獲取我整理的 Redis 系列面試題和答案,非常齊全。

          依靠List的leftPop來(lái)獲取令牌

          //?輸出令牌
          public?Response?limitFlow2(Long?id){
          ????Object?result?=?redisTemplate.opsForList().leftPop("limit_list");
          ????if(result?==?null){
          ????????return?Response.ok("當(dāng)前令牌桶中無(wú)令牌");
          ????}
          ????return?Response.ok(articleDescription2);
          }

          再依靠Java的定時(shí)任務(wù),定時(shí)往List中rightPush令牌,當(dāng)然令牌也需要唯一性,所以我這里還是用UUID進(jìn)行了生成

          //?10S的速率往令牌桶中添加UUID,只為保證唯一性
          @Scheduled(fixedDelay?=?10_000,initialDelay?=?0)
          public?void?setIntervalTimeTask(){
          ????redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());
          }

          綜上,代碼實(shí)現(xiàn)起始都不是很難,針對(duì)這些限流方式我們可以在A(yíng)OP或者filter中加入以上代碼,用來(lái)做到接口的限流,最終保護(hù)你的網(wǎng)站。

          Redis其實(shí)還有很多其他的用處,他的作用不僅僅是緩存,分布式鎖的作用。他的數(shù)據(jù)結(jié)構(gòu)也不僅僅是只有String,Hash,List,Set,Zset。有興趣的可以后續(xù)了解下他的GeoHash算法;BitMap,HLL以及布隆過(guò)濾器數(shù)據(jù)(Redis4.0之后加入,可以用Docker直接安裝redislabs/rebloom)結(jié)構(gòu)。

          有問(wèn)題歡迎留言探討。

          原文鏈接:https://blog.csdn.net/lmx125254/article/details/90700118

          版權(quán)聲明:本文為CSDN博主「Leonis丶L」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。


          23 種設(shè)計(jì)模式實(shí)戰(zhàn)(很全)
          官宣:Redis OM 對(duì)象映射框架來(lái)了!
          你還在遍歷搜索集合?Java 8 一行代碼搞定!
          去了家新公司,技術(shù)總監(jiān)不讓用 IntelliJ IDEA!
          重磅!JDK 17 發(fā)布,正式免費(fèi)。。
          面試官:Java 8 map 和 flatMap 的區(qū)別?
          別再寫(xiě)滿(mǎn)屏的 get & set 了,試試 MapStruct!
          推薦一款代碼神器,代碼量至少省一半!
          程序員精通各種技術(shù)體系,45歲求職難!
          重磅!Spring Boot 2.6 正式發(fā)布
          Spring Boot 學(xué)習(xí)筆記,這個(gè)太全了!



          關(guān)注Java技術(shù)棧看更多干貨



          獲取 Spring Boot 實(shí)戰(zhàn)筆記!
          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  很很鲁97视频 | 乱伦中文网| 日日操视频 | 高清无码毛片在线看 | 欧洲亚洲韩国在线观看 |