日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

常用的限流算法学习

發布時間:2024/8/23 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 常用的限流算法学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

常用的限流算法有漏桶算法和令牌桶算法,guava的RateLimiter使用的是令牌桶算法,也就是以固定的頻率向桶中放入令牌,例如一秒鐘10枚令牌,實際業務在每次響應請求之前都從桶中獲取令牌,只有取到令牌的請求才會被成功響應,獲取的方式有兩種:阻塞等待令牌或者取不到立即返回失敗。

限流算法:令牌桶算法、漏斗桶算法、基于redis的滑動窗口計數法

?

令牌桶算法

我們用的是guava的RateLimiter,用在處理請求時候,從桶中申請令牌,申請到了就成功響應,申請不到時直接返回失敗;

代碼示例:

package common.guava;import com.google.common.util.concurrent.RateLimiter; import org.junit.Test;public class RateLimitTest {@Testpublic void use1(){RateLimiter rateLimiter = RateLimiter.create(5.0);for (int i = 0 ; i < 20; i++){//嘗試獲取令牌if (rateLimiter.tryAcquire()){System.out.println("獲取令牌成功");//模擬業務執行 // try { // Thread.sleep(500); // } catch (InterruptedException e) { // e.printStackTrace(); // }}else {System.out.println("獲取令牌失敗");}}}@Testpublic void test2(){RateLimiter rateLimiter = RateLimiter.create(5);long start = System.currentTimeMillis()/1000;for (int i = 0 ; i < 10; i++){System.out.println("----start----");//阻塞式放行rateLimiter.acquire();System.out.println("放行");System.out.println("-----end-----");}long end = System.currentTimeMillis() / 1000;System.out.println(String.format("耗時:%d s", (end - start)));}}

漏斗桶算法

漏桶算法思路很簡單,水(請求)先進入到漏桶里,漏桶以一定的速度出水,當水流入速度過大會直接溢出,可以看出漏桶算法能強行限制數據的傳輸速率。

參考:https://www.cnblogs.com/xuwc/p/9123078.html

?

package flowLimit;import com.google.common.util.concurrent.RateLimiter; import org.junit.Test;import java.util.concurrent.TimeUnit;/*** @author: weijie* @Date: 2020/9/23 19:15* @url:https://blog.csdn.net/cailianren1/article/details/85283044*/ public class LeakyBucketLimitTest {/*** @param qps 平均qps 控制接口的響應速率,響應速率越快處理請求越多* @param countOfReq 桶的大小,接受請求的最大值* @return*/public RateLimiter createLeakyBucket(int qps, int countOfReq){return RateLimiter.create(qps,countOfReq, TimeUnit.MILLISECONDS);}@Testpublic void run(){RateLimiter leakyBucket = createLeakyBucket(100, 1000);long start = System.currentTimeMillis()/1000;int countRequest = 200;for (int i = 0; i < countRequest; i++){ // System.out.println("請求過來");leakyBucket.acquire(); // System.out.println("業務處理");}long spend = System.currentTimeMillis()/1000 - start;System.out.println("處理的請求數量:" + countRequest +"," +""+"耗時:" + spend + "s " +",qps:" + leakyBucket.getRate()+",實際qps:"+Math.ceil(countRequest/(spend)));} }

窗口計數法

優點:和令牌桶相比,這種算法不需要去等待令牌生成的時間,在新的時間窗口,可以立即處理大量的請求。
缺點:在一個窗口臨界點的前后時間,比如時間窗口是1分鐘,在59秒和1分01秒同時突發大量請求,極端情況下可能會帶來 2 倍的流量,系統可能承受不了這么大的突發性流量

java實現的固定窗口計數法:

package common.flowLimit;import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /*** @author: weijie* @Date: 2020/9/23 18:02* @Description:* @url: https://blog.csdn.net/king0406/article/details/103129530?*/ public class WindowLimiter {Logger log = LoggerFactory.getLogger(WindowLimiter.class);//本地緩存,以時間戳為key,以原子類計數器為valueprivate LoadingCache<Long, AtomicLong> counter =CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(new CacheLoader<Long, AtomicLong>() {@Overridepublic AtomicLong load(Long seconds) throws Exception {return new AtomicLong(0);}});private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);//設置限流閾值為15private long limit = 15;/*** 固定時間窗口* 每隔5s,計算時間窗口內的請求數量,判斷是否超出限流閾值*/@Testpublic void run(){while (true){fixWindow();}}private void fixWindow() {scheduledExecutorService.scheduleWithFixedDelay(() -> {try {// time windows 5 slong time = System.currentTimeMillis() / 5000;//模擬每秒發送隨機數量的請求int reqs = (int) (Math.random() * 5) + 1;long num = counter.get(time).addAndGet(reqs);log.info("time=" + time + ",num=" + num);if (num > limit) {log.info("限流了,num=" + num);}} catch (Exception e) {log.error("fixWindow error", e);} finally {}}, 0, 1000, TimeUnit.MILLISECONDS);} }

基于redis分布式固定窗口計數法:

package flowLimit;import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool;import java.util.Random;/*** @author: weijie* @Date: 2020/9/23 18:11* @url: https://blog.csdn.net/king0406/article/details/103130327*/ public class WindowLimiterByRedisTest {Logger logger = LoggerFactory.getLogger(WindowLimiterByRedisTest.class);JedisPool jedisPool;@Beforepublic void init(){String host = "39.96.204.209";int port = 6379;jedisPool = new JedisPool(host, port);}@Testpublic void run(){/*每次請求進來,查詢一下當前的計數值,如果超出請求數閾值,則拒絕請求,返回系統繁忙提示*/Jedis redis = jedisPool.getResource();redis.auth("123456");long limit = 10;while (true){Random random = new Random();//模擬三個不同的請求String request = "flow:" + random.nextInt(3);long count = 0;try {count = limitFlow(redis, request);//超過限流if (count > limit){logger.error("當前訪問過于頻道,請稍后再試");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}else {logger.info("請求放行,執行業務處理");}}catch (Exception e){e.printStackTrace();}}}private long limitFlow(Jedis jedis, String key) {//Setnx(SET if Not eXists) 命令在指定的 key 不存在時,為 key 設置指定的值。設置成功返回1,設置失敗返回0Long lng = jedis.setnx(key, "1");if (lng == 1) {//設置時間窗口,redis-key時效為10秒jedis.expire(key, 10);return 1L;} else {//Redis Incrby 命令將 key 中儲存的數字加上指定的增量值。相當于放在redis中的計數器,每次請求到來計數器自增1System.out.println("key: " + key);String va = jedis.get(key);System.out.println("value: " + va);long val = jedis.incr(key);System.out.println("result: " + val);return val;}} }

?

總結

以上是生活随笔為你收集整理的常用的限流算法学习的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。