.NetCore 常见限流策略、原理及使用方式
在分布式系统和高并发应用中,限流(Rate Limiting)是一项关键技术,用于防止过多的请求淹没服务器,从而保证服务的稳定性与性能。本文介绍几种常见的限流算法,包括固定窗口限流、滑动窗口限流、令牌桶算法、漏桶算法。
固定窗口限流
原理
固定窗口限流在一个固定的时间窗口内(如1秒、1分钟),限制请求数量。例如,一个用户在1分钟内最多只能发送100个请求。如果请求数超过阈值,则拒绝请求。时间窗口结束后,计数器重置。
优点
实现简单:使用简单的计数器即可实现。
低资源占用:不需要大量额外的计算和存储资源。
缺点
临界问题:在时间窗口的边界可能出现大量突发请求。例如,一个用户在窗口结束前发出多个请求,并在新窗口开始时再次发出多个请求,导致短时间内服务器受到过多请求的压力。
代码示例
public class RateLimiterDemo
{
private readonly int _maxRequests;
private readonly TimeSpan _windowTime;
private int _requestCount;
private DateTime _windowStart;
public RateLimiterDemo(int maxRequests, TimeSpan windowTime)
{
_maxRequests = maxRequests;
_windowTime = windowTime;
_windowStart = DateTime.UtcNow;
_requestCount = 0;
}
public bool IsRequestAllowed()
{
var now = DateTime.UtcNow;
if (now - _windowStart > _windowTime)
{
_windowStart = now;
_requestCount = 0;
}
if (_requestCount < _maxRequests)
{
_requestCount++;
return true;
}
return false;
}
}
滑动窗口限流
原理
滑动窗口限流通过将时间窗口细分为多个小窗口,并对每个小窗口的请求进行统计来平滑流量。它在每个时间点都会计算过去固定时间内的请求总数,避免固定窗口的临界问题。
优点
解决临界问题:滑动窗口避免了固定窗口临界点的突发流量问题。
限流更加平滑:更加精准地控制请求频率。
缺点
实现复杂:需要存储每个小窗口的请求计数,并动态更新窗口。
较高的资源开销:需要更多的计算和存储空间。
代码示例
public class RateLimiterDemo
{
private readonly int _maxRequests;
private readonly TimeSpan _windowTime;
private readonly LinkedList<DateTime> _requestTimestamps = new LinkedList<DateTime>();
public RateLimiterDemo(int maxRequests, TimeSpan windowTime)
{
_maxRequests = maxRequests;
_windowTime = windowTime;
}
public bool IsRequestAllowed()
{
var now = DateTime.UtcNow;
var windowStart = now - _windowTime;
while (_requestTimestamps.Count > 0 && _requestTimestamps.First.Value < windowStart)
{
_requestTimestamps.RemoveFirst();
}
if (_requestTimestamps.Count < _maxRequests)
{
_requestTimestamps.AddLast(now);
return true;
}
return false;
}
}
令牌桶算法
原理
令牌桶算法通过生成和消耗"令牌"来控制请求速率。系统以固定速率生成令牌并放入桶中,请求到达时从桶中取走一个令牌,如果桶中没有令牌,则拒绝请求。未使用的令牌可以累积,因此允许一定的突发流量。
优点
支持突发流量:未使用的令牌可以累积,从而允许短期的流量高峰。
灵活性高:可以通过调整令牌生成速率和桶的大小来调整限流策略。
缺点
精确控制较弱:突发流量过大时仍可能导致系统压力增加。
代码示例
public class RateLimiterDemo
{
private readonly int _capacity;
private readonly int _tokensPerSecond;
private int _tokens;
private DateTime _lastRefillTime;
public RateLimiterDemo(int capacity, int tokensPerSecond)
{
_capacity = capacity;
_tokensPerSecond = tokensPerSecond;
_tokens = capacity;
_lastRefillTime = DateTime.UtcNow;
}
public bool IsRequestAllowed()
{
var now = DateTime.UtcNow;
var timeElapsed = (now - _lastRefillTime).TotalSeconds;
// Refill tokens
var tokensToAdd = (int)(timeElapsed * _tokensPerSecond);
_tokens = Math.Min(_capacity, _tokens + tokensToAdd);
_lastRefillTime = now;
if (_tokens > 0)
{
_tokens--;
return true;
}
return false;
}
}
漏桶算法
原理
漏桶算法将请求流量控制为一个固定速率。它模拟了一个装水的桶,水(请求)可以以任意速率流入桶中,但只能以固定速率流出(处理请求)。如果桶满了,超出的请求将被丢弃。该算法强制将请求处理速率保持稳定。
优点
严格控制流量:漏桶算法能严格限制请求的处理速率,流量平滑。
适用于带宽控制:特别适用于需要严格限速的场景。
缺点
不支持突发流量:多余的请求直接丢弃,无法处理突发流量。
代码示例
public class RateLimiterDemo
{
private readonly int _capacity;
private readonly int _dripRate; // Requests per second
private int _currentLoad;
private DateTime _lastLeakTime;
public RateLimiterDemo(int capacity, int dripRate)
{
_capacity = capacity;
_dripRate = dripRate;
_currentLoad = 0;
_lastLeakTime = DateTime.UtcNow;
}
public bool IsRequestAllowed()
{
var now = DateTime.UtcNow;
var timeElapsed = (now - _lastLeakTime).TotalSeconds;
// Leak the bucket
var leaks = (int)(timeElapsed * _dripRate);
_currentLoad = Math.Max(0, _currentLoad - leaks);
_lastLeakTime = now;
if (_currentLoad < _capacity)
{
_currentLoad++;
return true;
}
return false;
}
}
总结
- 感谢你赐予我前进的力量
本网站的原创文章部分资源内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系博主邮箱:zzyo.yj@outlook.com 进行删除处理
本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向博主举报
声明:版权所有,违者必究 | 如未注明,均为原创 | 本网站采用CC BY-NC-SA 4.0 协议进行授权
转载:转载请注明原文链接 - Lycoris