限流懲罰是怎麼一回事
最近經常看到某某主播被直播平台限流懲罰,平台給主播的流量變少,甚至直接沒有流量了。這篇文章要說的是後端服務的限流懲罰,和這個主播被限流懲罰有點相似之處,又有些不同。
本文說的限流懲罰是什麼樣的?
服務調用者調用服務的次數超過了服務允許的最大上限,也就是達到了限流閾值,此時服務會返回一個限流錯誤給調用方,同時還要對調用方追加一些懲罰措施,比如限制調用方10秒鐘之內都不能訪問服務。
為什麼被限流了還要追加懲罰?
這裡邊的邏輯是:調用方之所以被限流,就是因為沒有合理的使用服務(當然這個合理性是由服務提供方來聲明的),作為服務提供方有責任督促調用方調整服務使用方式,懲罰就是督促的一種形式。如果不規範使用服務,導致被懲罰,調用方的業務也會受到較大影響,這會促使服務使用者不得不考慮改進訪問服務的行為。
導致不合理調用服務的一個原因可能是調用方程序錯誤,比如陷入了死循環,不停的訪問服務,這時候追加限流懲罰就很有必要,避免服務端承受大量無意義的請求,避免引起負載過重的問題。
還有一種是設計上的考量,比如頻繁的查詢用戶信息導致被限流懲罰,服務提供者的目的可能是要求服務調用方對用戶信息進行緩存,而不是每次都來查詢服務,給服務帶來較大的壓力。
如何實現限流懲罰?
一個很自然的思路就是:當限流被觸發時,標記調用方並設置一個過期時間,如果調用方在過期時間內來訪問則直接返回錯誤,如果調用方在過期時間後來訪問則恢復進行限流計數。這樣也可以進一步降低服務端的限流處理消耗。
下面來看一下具體的實現,在 FireflySoft.RateLimit 中進程內限流和Redis限流都支持進行限流懲罰。
定義限流懲罰
因為所有的限流算法都可能需要支持限流懲罰,所以在限流規則的基類中定義了一個字段:LockSeconds,表示在觸發限流後需要鎖定的秒數,即觸發限流後調用方不能繼續訪問服務的時間長度。
public abstract class RateLimitRule
{
/// <summary>
/// The number of seconds locked after triggering rate limiting. 0 means not locked
/// </summary>
public int LockSeconds { get; set; }
}
發起限流懲罰
這裡以進程內限流為例,觸發限流後會添加一個緩存項,並設置緩存的過期時間為上文定義的LockSeconds。
protected bool TryLock(string target, DateTimeOffset currentTime, TimeSpan expireTimeSpan)
{
var expireTime = currentTime.Add(expireTimeSpan);
return _cache.Add($"{target}-lock", 1, expireTime);
}
Redis發起限流懲罰的原理和這個差不多,只不過是寫到Redis的KV中。想要了解的同學可以點擊這裡查看。
應用限流懲罰
這裡還是以進程內限流為例,每次限流計數前都檢查是否存在限流懲罰緩存項,如果存在則直接返回錯誤。
protected bool CheckLocked(string target)
{
return _cache.Get($"{target}-lock") == null ? false : true;
}
好了,以上就是這篇文章的主要內容了。
如果你對 FireflySoft.RateLimit 有一點興趣,歡迎訪問我的Github://github.com/bosima/FireflySoft.RateLimit 。