限流是什么尸红?
限流在日常生活中限流很常見(jiàn),例如去有些景區(qū)玩刹泄,每天售賣(mài)的門(mén)票數(shù)是有限的外里,例如 2000 張,即每天最多只有 2000 個(gè)人能進(jìn)去游玩特石。那在我們工程上限流是什么呢盅蝗?限制的是 「流」,在不同場(chǎng)景下「流」的定義不同姆蘸,可以是每秒請(qǐng)求數(shù)墩莫、每秒事務(wù)處理數(shù)、網(wǎng)絡(luò)流量等等逞敷。通常意義我們說(shuō)的限流指代的是限制到達(dá)系統(tǒng)的并發(fā)請(qǐng)求數(shù)狂秦,使得系統(tǒng)能夠正常的處理部分用戶(hù)的請(qǐng)求,來(lái)保證系統(tǒng)的穩(wěn)定性兰粉。
限流的本質(zhì)是因?yàn)楹蠖颂幚砟芰τ邢薰嗜枰氐舫^(guò)處理能力之外的請(qǐng)求,亦或是為了均衡客戶(hù)端對(duì)服務(wù)端資源的公平調(diào)用玖姑,防止一些客戶(hù)端餓死愕秫。
為什么要限流?
- 為了保證系統(tǒng)的穩(wěn)定性焰络。
日常的業(yè)務(wù)上有類(lèi)似秒殺活動(dòng)戴甩、雙十一大促或者突發(fā)新聞等場(chǎng)景,用戶(hù)的流量突增闪彼,后端服務(wù)的處理能力是有限的甜孤,如果不能處理好突發(fā)流量协饲,后端服務(wù)很容易就被打垮。另外像爬蟲(chóng)之類(lèi)的不正常流量缴川,我們對(duì)外暴露的服務(wù)都要以最大惡意為前提去防備調(diào)用者茉稠。我們不清楚調(diào)用者會(huì)如何調(diào)用我們的服務(wù),假設(shè)某個(gè)調(diào)用者開(kāi)幾十個(gè)線(xiàn)程一天二十四小時(shí)瘋狂調(diào)用你的服務(wù)把夸,如果不做啥處理咱服務(wù)基本也玩完了而线,更勝者還有ddos攻擊。
- 保證資源公平利用
對(duì)于很多第三方開(kāi)放平臺(tái)來(lái)說(shuō)恋日,不僅僅要防備不正常流量膀篮,還要保證資源的公平利用,一些接口資源不可能一直都被一個(gè)客戶(hù)端占著岂膳,也需要保證其他客戶(hù)端能正常調(diào)用誓竿。
例子:高德開(kāi)放平臺(tái)流量限制說(shuō)明
常見(jiàn)的限流算法
1、計(jì)數(shù)器限流
計(jì)數(shù)器限流也就是最簡(jiǎn)單的限流算法就是計(jì)數(shù)限流了谈截。例如系統(tǒng)能同時(shí)處理 100 個(gè)請(qǐng)求筷屡,保存一個(gè)計(jì)數(shù)器,處理了一個(gè)請(qǐng)求簸喂,計(jì)數(shù)器就加一速蕊,一個(gè)請(qǐng)求處理完畢之后計(jì)數(shù)器減一。每次請(qǐng)求來(lái)的時(shí)候看看計(jì)數(shù)器的值娘赴,如果超過(guò)閾值就拒絕。計(jì)數(shù)器的值要是存內(nèi)存中就算單機(jī)限流算法跟啤,如果放在第三方存儲(chǔ)里(例如Redis中)集群機(jī)器訪問(wèn)就算分布式限流算法诽表。
優(yōu)點(diǎn):簡(jiǎn)單,單機(jī)在 Java 中可用 Atomic 等原子類(lèi)隅肥、分布式就使用 Redis incr命令竿奏。
缺點(diǎn):假設(shè)我們?cè)试S的閾值是1萬(wàn),此時(shí)計(jì)數(shù)器的值為 0腥放,當(dāng) 1 萬(wàn)個(gè)請(qǐng)求在1秒內(nèi)全部請(qǐng)求進(jìn)來(lái)泛啸,那么服務(wù)可能就扛不住了。
計(jì)數(shù)器限流偽代碼實(shí)現(xiàn)
boolean tryAcquire() {
if (counter < threshold) {
counter++;
return true;
}
return false;
}
boolean tryRelease() {
if (counter > 0) {
counter--;
return true;
}
return false;
}
一般的限流都是為了限制在指定時(shí)間間隔內(nèi)的訪問(wèn)量秃症,因此還有個(gè)算法叫固定窗口候址。
2、固定窗口限流
它相比于計(jì)數(shù)限流主要是多了個(gè)時(shí)間窗口的概念种柑,計(jì)數(shù)器每過(guò)一個(gè)時(shí)間窗口就重置岗仑。規(guī)則如下:
請(qǐng)求次數(shù)小于閾值,允許訪問(wèn)并且計(jì)數(shù)器 +1聚请;
請(qǐng)求次數(shù)大于閾值荠雕,拒絕訪問(wèn);
這個(gè)時(shí)間窗口過(guò)了之后,計(jì)數(shù)器清零炸卑;
固定窗口限流偽代碼實(shí)現(xiàn)
boolean trvAcquire() {
// 獲取當(dāng)前時(shí)間
long now = currentTimeMillis( )既鞠;
// 看是否過(guò)了時(shí)間窗口
if (now - lastAcquireTime > TimeWindow ) {
// 計(jì)數(shù)器置零
counter = 0;
lastAcquireTime = now;
}
// 小于閾值
if (counter < threshold) {
counter++;
return true;
}
return false
}
這種方式也會(huì)面臨一些問(wèn)題,例如固定窗口臨界問(wèn)題:假設(shè)系統(tǒng)每秒允許 100 個(gè)請(qǐng)求盖文,假設(shè)第一個(gè)時(shí)間窗口是 0-1s嘱蛋,在第 0.55s 處一下次涌入 100 個(gè)請(qǐng)求,過(guò)了 1 秒的時(shí)間窗口后計(jì)數(shù)清零椅寺,此時(shí)在 1.05 s 的時(shí)候又一下次涌入100個(gè)請(qǐng)求浑槽。雖然窗口內(nèi)的計(jì)數(shù)沒(méi)超過(guò)閾值,但是全局來(lái)看在 0.55s-1.05s 這 0.1 秒內(nèi)涌入了 200 個(gè)請(qǐng)求返帕,這其實(shí)對(duì)于閾值是 100/s 的系統(tǒng)來(lái)說(shuō)是無(wú)法接受的桐玻。
為了解決這個(gè)問(wèn)題,業(yè)界又提出另外一種限流算法荆萤,即滑動(dòng)窗口限流镊靴。
3冷冗、滑動(dòng)窗口限流
滑動(dòng)窗口限流解決固定窗口臨界值的問(wèn)題言津,可以保證在任意時(shí)間窗口內(nèi)都不會(huì)超過(guò)閾值。相對(duì)于固定窗口民轴,滑動(dòng)窗口除了需要引入計(jì)數(shù)器之外還需要記錄時(shí)間窗口內(nèi)每個(gè)請(qǐng)求到達(dá)的時(shí)間點(diǎn)敞峭,因此對(duì)內(nèi)存的占用會(huì)比較多踊谋。
規(guī)則如下,假設(shè)時(shí)間窗口為 1 秒:
記錄每次請(qǐng)求的時(shí)間
統(tǒng)計(jì)每次請(qǐng)求的時(shí)間至往前推1秒這個(gè)時(shí)間窗口內(nèi)的請(qǐng)求數(shù)旋讹,并且1 秒前的數(shù)據(jù)可以清除殖蚕。
統(tǒng)計(jì)的請(qǐng)求數(shù)小于閾值就記錄這個(gè)請(qǐng)求的時(shí)間,并允許通過(guò)沉迹,反之拒絕睦疫。
滑動(dòng)窗口
滑動(dòng)窗口偽代碼實(shí)現(xiàn)
boolean tryAcquire() {
long now = currentTimenillis();
// 根據(jù)當(dāng)前時(shí)間獲取時(shí)間窗口內(nèi)的計(jì)數(shù)
long counter = getCounterInTimewindow(now);
// 小于閾值
if (counter < threshold){
// 記錄當(dāng)前時(shí)間
addToTimewindow(now);
return true;
}
return false;
但是滑動(dòng)窗口和固定窗口都無(wú)法解決短時(shí)間之內(nèi)集中流量的沖擊問(wèn)題鞭呕。我們所想的限流場(chǎng)景是: 每秒限制 100 個(gè)請(qǐng)求蛤育。希望請(qǐng)求每 10ms 來(lái)一個(gè),這樣我們的流量處理就很平滑葫松,但是真實(shí)場(chǎng)景很難控制請(qǐng)求的頻率瓦糕,因?yàn)榭赡芫退阄覀冊(cè)O(shè)置了1s內(nèi)只能有100個(gè)請(qǐng)求,也可能存在 5ms 內(nèi)就打滿(mǎn)了閾值的情況进宝。當(dāng)然對(duì)于這種情況還是有變型處理的刻坊,例如設(shè)置多條限流規(guī)則。不僅限制每秒 100 個(gè)請(qǐng)求党晋,再設(shè)置每 10ms 不超過(guò) 2 個(gè)谭胚,不過(guò)帶來(lái)的就是比較差的用戶(hù)體驗(yàn)徐块。
而漏桶算法,可以解決時(shí)間窗口類(lèi)的痛點(diǎn)灾而,使得流量更加平滑胡控。
4、漏桶算法
如下圖所示旁趟,水滴持續(xù)滴入漏桶中昼激,底部定速流出。如果水滴滴入的速率大于流出的速率锡搜,當(dāng)存水超過(guò)桶的大小的時(shí)候就會(huì)溢出橙困。
規(guī)則如下:
請(qǐng)求來(lái)了放入桶中(不限制流入速率)
桶內(nèi)請(qǐng)求量滿(mǎn)了拒絕請(qǐng)求
服務(wù)定速?gòu)耐皟?nèi)拿請(qǐng)求處理(定速流出)
漏桶算法示意圖
漏桶偽代碼實(shí)現(xiàn)
LeakyDemo {
public long timeStamp = getNowTime();
public int capacity; // 桶的容量
public int rate; // 水漏出的速度
public Long water; // 當(dāng)前水量(當(dāng)前累積請(qǐng)求數(shù))
public boolean grant() {
long now = getNowTime();
water = Math.max(0L, water - (now - timeStamp) * rate); // 先執(zhí)行漏水,計(jì)算剩余水量
timeStamp = now;
if ((water + 1) < capacity) {
// 嘗試加水,并且水還未滿(mǎn)
water += 1;
return true;
}
else {
// 水滿(mǎn)耕餐,拒絕加水
return false;
}
}
private static Long getNowTime(){
return System.currentTimeMillis();
}
}
水滴對(duì)應(yīng)的就是請(qǐng)求凡傅。
- 特點(diǎn):流量寬進(jìn)嚴(yán)出。無(wú)論請(qǐng)求多少肠缔,請(qǐng)求的速率有多大夏跷,都按照固定的速率流出,對(duì)應(yīng)的就是服務(wù)按照固定的速率處理請(qǐng)求明未。和消息隊(duì)列思想有點(diǎn)像槽华,削峰填谷。一般而言漏桶也是由隊(duì)列來(lái)實(shí)現(xiàn)的趟妥,處理不過(guò)來(lái)的請(qǐng)求就排隊(duì)猫态,隊(duì)列滿(mǎn)了就拒絕請(qǐng)求。
與線(xiàn)程池實(shí)現(xiàn)的方式方式如出一轍披摄。
- 缺點(diǎn)
面對(duì)突發(fā)請(qǐng)求懂鸵,服務(wù)的處理速度和平時(shí)是一樣的,這并非我們實(shí)際想要的行疏。我們希望的是在突發(fā)流量時(shí),在保證系統(tǒng)平穩(wěn)的同時(shí)套像,也要盡可能提升用戶(hù)體驗(yàn)酿联,也就是能更快地處理并響應(yīng)請(qǐng)求,而不是和正常流量一樣循規(guī)蹈矩地處理夺巩。
而令牌桶在應(yīng)對(duì)突擊流量的時(shí)候贞让,可以更加的“激進(jìn)”。
5柳譬、令牌桶算法
令牌桶其實(shí)和漏桶的原理類(lèi)似喳张,只不過(guò)漏桶是定速地流出,而令牌桶是定速地往桶里塞入令牌美澳,然后請(qǐng)求只有拿到了令牌才能通過(guò)销部,之后再被服務(wù)器處理摸航。
當(dāng)然令牌桶的大小也是有限制的,假設(shè)桶里的令牌滿(mǎn)了之后舅桩,定速生成的令牌會(huì)丟棄酱虎。
規(guī)則:
定速的往桶內(nèi)放入令牌(定速生成)
令牌數(shù)量超過(guò)桶的限制,丟棄
請(qǐng)求來(lái)了先向桶內(nèi)索要令牌擂涛,索要成功則通過(guò)被處理读串,反之拒絕
令牌桶
令牌桶的原理與JUC的Semaphore 信號(hào)量很相似,信號(hào)量可控制某個(gè)資源被同時(shí)訪問(wèn)的個(gè)數(shù)撒妈,其實(shí)和拿令牌思想一樣恢暖,不同的是一個(gè)是拿信號(hào)量,一個(gè)是拿令牌狰右。信號(hào)量用完了返還杰捂,而令牌用了不歸還,因?yàn)榱钆茣?huì)定時(shí)再填充挟阻。
借助Semaphore實(shí)現(xiàn)單機(jī)流量限制(其原理與令牌桶算法基本一致)
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* @author: xiebochang
* @Title: SemaphoreLocalRateLimiter
* @date: 2021/4/20
*/
public class SemaphoreLocalRateLimiter {
public static void main (String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
// 最多允許5個(gè)線(xiàn)程同時(shí)訪問(wèn)
int limit = 5;
Semaphore semaphore = new Semaphore(limit);
// 模擬10個(gè)請(qǐng)求同時(shí)涌進(jìn)來(lái)
int requiredCount = 10;
for (int i = 0; i < requiredCount; i++) {
final int num = i;
service.submit(() -> {
try {
// 獲取許可
semaphore.acquire();
// 每個(gè)線(xiàn)程睡[0,10)s后釋放許可
System.out.println(num + "獲得許可琼娘,開(kāi)始執(zhí)行");
long sleepTime = new Random().nextInt(10000);
Thread.sleep(sleepTime);
semaphore.release();
System.out.println(num + "釋放許可," + "休眠了" + sleepTime + "ms");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
service.shutdown();
/**
*
* 執(zhí)行結(jié)果示例:(在5個(gè)許可發(fā)放完畢后附鸽,只有等拿到許可的線(xiàn)程釋放了許可脱拼,其它未獲取許可的線(xiàn)程才能獲取許可,執(zhí)行業(yè)務(wù)代碼)
*
* 5獲得許可坷备,開(kāi)始執(zhí)行
* 0獲得許可熄浓,開(kāi)始執(zhí)行
* 4獲得許可,開(kāi)始執(zhí)行
* 2獲得許可省撑,開(kāi)始執(zhí)行
* 3獲得許可赌蔑,開(kāi)始執(zhí)行
* 3釋放許可,休眠了964ms
* 1獲得許可竟秫,開(kāi)始執(zhí)行
* 0釋放許可娃惯,休眠了5139ms
* 6獲得許可,開(kāi)始執(zhí)行
* 5釋放許可肥败,休眠了6105ms
* 7獲得許可趾浅,開(kāi)始執(zhí)行
* 7釋放許可,休眠了319ms
* 8獲得許可馒稍,開(kāi)始執(zhí)行
* 4釋放許可皿哨,休眠了6912ms
* 9獲得許可,開(kāi)始執(zhí)行
* 2釋放許可纽谒,休眠了8870ms
* 8釋放許可证膨,休眠了3079ms
* 1釋放許可,休眠了9480ms
* 6釋放許可鼓黔,休眠了6018ms
* Disconnected from the target VM, address: '127.0.0.1:64441', transport: 'socket'
* 9釋放許可央勒,休眠了7000ms
*
**/
}
}
Guava包RateLimiter實(shí)現(xiàn)簡(jiǎn)單限流
/**
* 簡(jiǎn)單的tryAcquire
*
* @param
* @return void
**/
private static void testSimpleTryAcquire () throws InterruptedException {
RateLimiter limiter = RateLimiter.create(2);
while (true) {
Thread.sleep(2000);
System.out.println("tryAcquire:" + limiter.tryAcquire(2));
}
/**
*
* output:
*
* tryAcquire:true
* tryAcquire:true
* tryAcquire:true
*
**/
}
/**
*
* 默認(rèn)使用SmoothBursty -- 平滑突發(fā)限流
* 一開(kāi)始便初始化填入permitsPerSecond個(gè)令牌
* 不預(yù)熱不见,一開(kāi)始就固定令牌生成速率
*
* @param permitsPerSecond -- 每秒生成token數(shù)
* @param requiredPermits -- 請(qǐng)求token數(shù)
* @return void
**/
private static void simpleSmoothBursty (double permitsPerSecond, int requiredPermits) {
RateLimiter limiter = RateLimiter.create(permitsPerSecond);
int i = 1;
while (true) {
System.out.println("round " + i + ":get " + requiredPermits + " tokens spend:" + limiter.acquire(requiredPermits) + "s");
i ++;
}
/**
* permitsPerSecond = 2,requiredPermits = 2
*
* output:
*
* round 1:get 2 tokens spend:0.0s
* round 2:get 2 tokens spend:0.997221s
* round 3:get 2 tokens spend:0.99515s
* round 4:get 2 tokens spend:0.992469s
* round 5:get 2 tokens spend:0.996439s
* round 6:get 2 tokens spend:0.999554s
*
**/
}
簡(jiǎn)單令牌桶算法偽代碼
/**
* @author: xiebochang
* @Title: LocalRateLimiter
* @date: 2021/4/20
*/
public class LocalRateLimiter {
private long tokens = getInitTokens();
private long lastRefreshTime = getInitLastRefreshTime();
private int rate = 1; // 1ms生成1個(gè)
public boolean tryGrant (long required, long capacity) {
long now = System.currentTimeMillis();
// 計(jì)算生成令牌數(shù)
long generateTokens = Math.max(0, (now - lastRefreshTime) * rate);
// 可取令牌數(shù)
long currTokens = Math.min(tokens + generateTokens, capacity);
// 是否足夠取
boolean allowed = currTokens >= required;
if (allowed) {
tokens = currTokens - required;
lastRefreshTime = now;
return true;
}
return false;
}
private long getInitTokens() {
return 100;
}
private long getInitLastRefreshTime() {
return lastRefreshTime > 0 ? lastRefreshTime : System.currentTimeMillis() - 1000;
}
public static void main (String[] args) throws InterruptedException {
LocalRateLimiter limiter = new LocalRateLimiter();
System.out.println(limiter.tryGrant(1200, 3000));
Thread.sleep(1000);
System.out.println(limiter.tryGrant(2100, 3000));
}
}
對(duì)比漏桶算法可以看出令牌桶更適合應(yīng)對(duì)突發(fā)流量订歪,假如桶內(nèi)有 100 個(gè)令牌脖祈,那么這100個(gè)令牌可以馬上被取走,而不像漏桶那樣勻速的消費(fèi)刷晋。不過(guò)上面批量獲取令牌也會(huì)致使一些新的問(wèn)題出現(xiàn)盖高,比如導(dǎo)致一定范圍內(nèi)的限流誤差,舉個(gè)例子你取了 10 個(gè)此時(shí)不用眼虱,等下一秒再用喻奥,那同一時(shí)刻集群機(jī)器總處理量可能會(huì)超過(guò)閾值,所以現(xiàn)實(shí)中使用時(shí)捏悬,可能不會(huì)去考慮redis頻繁讀取問(wèn)題撞蚕,轉(zhuǎn)而直接采用一次獲取一個(gè)令牌的方式,具體采用哪種策略還是要根據(jù)真實(shí)場(chǎng)景而定过牙。
限流算法總結(jié)
1甥厦、計(jì)數(shù)器 VS 固定窗口 VS 滑動(dòng)窗口
計(jì)數(shù)器可以說(shuō)是固定窗口的低精度實(shí)現(xiàn),固定窗口又可以說(shuō)是滑動(dòng)窗口的低精度實(shí)現(xiàn)寇钉。
因此在限流時(shí)間精度上刀疙,三種算法關(guān)系為:計(jì)數(shù)器<固定窗口<滑動(dòng)窗口
但精度的精確同時(shí)也要消耗內(nèi)存,因此三種算法內(nèi)存占用關(guān)系為:計(jì)數(shù)器<固定窗口<滑動(dòng)窗口
2扫倡、漏桶算法 VS 令牌桶算法
兩者都比較適合阻塞式的限流場(chǎng)景谦秧。(類(lèi)似分布式鎖,獲取不到令牌則一直等待)
漏桶算法是將請(qǐng)求暫存于桶內(nèi)撵溃,再定速處理疚鲤,不大符合互聯(lián)網(wǎng)業(yè)務(wù)中低延遲的需求,用戶(hù)體驗(yàn)不佳缘挑。而令牌桶算法在限流時(shí)集歇,還可應(yīng)對(duì)突增流量的場(chǎng)景(可以批量獲取令牌),對(duì)用戶(hù)端的體驗(yàn)較好语淘。
但令牌桶算法使用不當(dāng)也有弊端鬼悠,比如上線(xiàn)初期未對(duì)桶內(nèi)的令牌做初始化,在第一批令牌還未生成時(shí)接受到請(qǐng)求會(huì)被丟棄亏娜,造成誤殺。
總的來(lái)說(shuō)
計(jì)數(shù)器比較適合簡(jiǎn)單蹬挺、粗力度限流需求
固定/滑動(dòng)窗口則適合對(duì)響應(yīng)時(shí)間要求較高的限流場(chǎng)景维贺,比如一些微服務(wù)接口
漏桶算法則比較適合后臺(tái)任務(wù)類(lèi)的限流場(chǎng)景
令牌桶則適用于大流量接口,特別是有瞬時(shí)流量較高的接口限流場(chǎng)景巴帮。
單機(jī)限流和分布式限流
單機(jī)限流和分布式限流本質(zhì)上的區(qū)別在于 “閾值” 存放的位置溯泣,單機(jī)限流就是“閥值”存放在單機(jī)部署的服務(wù)/內(nèi)存中虐秋,但我們的服務(wù)往往是集群部署的,因此需要多臺(tái)機(jī)器協(xié)同提供限流功能垃沦。像上述的計(jì)數(shù)器或者時(shí)間窗口的算法客给,可以將計(jì)數(shù)器存放至 Redis 等分布式 K-V 存儲(chǔ)中。又如滑動(dòng)窗口的每個(gè)請(qǐng)求的時(shí)間記錄可以利用 Redis 的 zset
存儲(chǔ)肢簿,利用ZREMRANGEBYSCORE
刪除時(shí)間窗口之外的數(shù)據(jù)靶剑,再用 ZCARD
計(jì)數(shù),
限流的難點(diǎn)
- 如何設(shè)定閥值池充?
可以看到桩引,每個(gè)限流都有個(gè)閾值,這個(gè)閾值如何定是個(gè)難點(diǎn)收夸。定大了服務(wù)器可能頂不住坑匠,定小了就“誤殺”了,沒(méi)有資源利用最大化卧惜,對(duì)用戶(hù)體驗(yàn)不好厘灼。一般的做法是限流上線(xiàn)之后先預(yù)估個(gè)大概的閾值,然后不執(zhí)行真正的限流操作咽瓷,而是采取日志記錄方式设凹,對(duì)日志進(jìn)行分析查看限流的效果,然后調(diào)整閾值忱详,推算出集群總的處理能力围来,和每臺(tái)機(jī)子的處理能力(方便擴(kuò)縮容)。然后將線(xiàn)上的流量進(jìn)行重放匈睁,測(cè)試真正的限流效果监透,最終閾值確定,然后上線(xiàn)航唆。
其實(shí)真實(shí)的業(yè)務(wù)場(chǎng)景很復(fù)雜胀蛮,需要限流的條件和資源很多,每個(gè)資源限流要求還不一樣糯钙。
限流組件
一般而言粪狼,我們不需要自己實(shí)現(xiàn)限流算法來(lái)達(dá)到限流的目的,不管是接入層限流還是細(xì)粒度的接口限流任岸,都有現(xiàn)成的輪子使用再榄,其實(shí)現(xiàn)也是用了上述我們所說(shuō)的限流算法。
Google Guava
提供的限流工具類(lèi)RateLimiter
享潜,是基于令牌桶實(shí)現(xiàn)的困鸥,并且擴(kuò)展了算法,支持預(yù)熱功能剑按。阿里開(kāi)源的限流框架
Sentinel
中的勻速排隊(duì)限流策略疾就,就采用了漏桶算法澜术。Nginx 中的限流模塊
limit_req_zone
,采用了漏桶算法猬腰,還有 OpenResty 中的resty.limit.req
庫(kù)等等鸟废。基于redis lua腳本 / redisson實(shí)現(xiàn)的令牌桶。
具體的使用還是很簡(jiǎn)單的姑荷,有興趣的同學(xué)可以自行搜索盒延,對(duì)內(nèi)部實(shí)現(xiàn)感興趣的同學(xué)可以下個(gè)源碼看看,學(xué)習(xí)下生產(chǎn)級(jí)別的限流是如何實(shí)現(xiàn)的厢拭。
總結(jié)
限流具體應(yīng)用到工程還是有很多點(diǎn)需要考慮的兰英,并且限流只是保證系統(tǒng)穩(wěn)定性中的一個(gè)環(huán)節(jié),還需要配合降級(jí)供鸠、熔斷等相關(guān)內(nèi)容畦贸。