我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统。陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线上环境和私有化部署均有了越来越多的稳定用户。

而我收到的用户需求也越来越多,产品化的需求,个性化的需求都有。最近两天收到一个用户的开放接口需求,为客服系统的 Open Api 开放接口提供一个获取在线访客列表的接口。

如何在 .NET 系统中实现 Open Api 我在前文分解过,今天我想分享的是如何为在线客服系统的开放接口设计实现一个 QPS 限流功能

如下图所示,在为用户提供接口的过程中,我对这个接口应用了基本的 QPS 限流技术。


什么是 QPS 接口限流

QPS(Queries Per Second,查询每秒)接口限流是指对 API 或网络服务的访问进行限制,控制每秒钟可以接受的最大请求数量。这种限流机制常用于防止服务器因为过多的请求而被过载,从而保证服务的稳定性和性能。

QPS 限流的具体做法通常是:

  1. 设置最大 QPS 限制:对于每个用户、IP 地址或系统等,设定一个请求次数上限。比如,一个接口每秒钟最多允许 100 次请求。

  2. 超限处理:当请求数超过设定的 QPS 限制时,系统通常会拒绝多余的请求,返回错误信息(如 HTTP 429 Too Many Requests)。有时,也可能选择进行排队、重试等处理。

  3. 分级限流:为了避免单一用户或 IP 造成整个系统的拥塞,可以根据用户类型、接口的优先级等进行不同的限流策略。

  4. 突发流量处理:对于突发的高频请求,系统可能允许短时间内的超出限制的请求,但会有相应的窗口期或滑动窗口来平滑流量。

QPS 限流的目的通常是:

  • 防止恶意请求或过多请求导致服务崩溃。
  • 确保公平性,避免单个用户或请求占用过多资源。
  • 提高服务的可用性和稳定性。

.NET 接口有哪些QPS限流方案

1. 基于内存的限流(Memory-based Rate Limiting)

  • 这种方法使用内存中的数据结构(如 DictionaryQueue)来记录每个用户或请求的时间戳,从而计算每秒钟的请求数量。
  • 适用于流量较小、对性能要求较高的场景。

示例

public class MemoryRateLimiter
{
private readonly int _maxQps;
private readonly Dictionary<string, Queue<DateTime>> _requests = new Dictionary<string, Queue<DateTime>>(); public MemoryRateLimiter(int maxQps)
{
_maxQps = maxQps;
} public bool IsRequestAllowed(string key)
{
var now = DateTime.UtcNow;
if (!_requests.ContainsKey(key))
{
_requests[key] = new Queue<DateTime>();
} var requestQueue = _requests[key]; // Remove requests older than 1 second
while (requestQueue.Count > 0 && (now - requestQueue.Peek()).TotalSeconds >= 1)
{
requestQueue.Dequeue();
} // Check if the current request exceeds the limit
if (requestQueue.Count >= _maxQps)
{
return false;
} requestQueue.Enqueue(now);
return true;
}
}

2. 基于令牌桶算法(Token Bucket)

令牌桶算法是一种流量控制算法,它通过给每个请求一个令牌来限制流量。每秒钟会向桶中添加一定数量的令牌,只有获取到令牌的请求才能通过。

  • 适合需要处理突发流量的场景,因为令牌桶可以在短时间内允许一定数量的超限请求。
  • .NET 没有内置令牌桶算法,但可以自己实现或使用一些开源库(例如 RateLimiter 包)。

示例

public class TokenBucketRateLimiter
{
private readonly int _bucketCapacity;
private readonly int _tokensPerSecond;
private int _tokens;
private DateTime _lastRefillTime; public TokenBucketRateLimiter(int bucketCapacity, int tokensPerSecond)
{
_bucketCapacity = bucketCapacity;
_tokensPerSecond = tokensPerSecond;
_tokens = bucketCapacity;
_lastRefillTime = DateTime.UtcNow;
} public bool IsRequestAllowed()
{
var now = DateTime.UtcNow;
var elapsedSeconds = (now - _lastRefillTime).TotalSeconds; // Refill tokens
if (elapsedSeconds > 1)
{
_tokens = Math.Min(_bucketCapacity, _tokens + (int)(elapsedSeconds * _tokensPerSecond));
_lastRefillTime = now;
} // Check if we have tokens available
if (_tokens > 0)
{
_tokens--;
return true;
} return false;
}
}

3. 基于滑动窗口(Sliding Window)

滑动窗口限流算法通过维护一个请求的时间窗口来限制请求次数。在窗口内,最多可以接受一定数量的请求。每次请求都会刷新这个窗口,并根据窗口内的请求数决定是否允许请求通过。

  • 适合对请求的时间分布进行精确控制的场景。
  • 实现相对复杂,但能更平滑地处理流量。

示例

public class SlidingWindowRateLimiter
{
private readonly int _maxQps;
private readonly TimeSpan _windowSize;
private readonly Queue<DateTime> _requests = new Queue<DateTime>(); public SlidingWindowRateLimiter(int maxQps, TimeSpan windowSize)
{
_maxQps = maxQps;
_windowSize = windowSize;
} public bool IsRequestAllowed()
{
var now = DateTime.UtcNow; // Remove requests that are outside the window
while (_requests.Count > 0 && (now - _requests.Peek()).TotalMilliseconds > _windowSize.TotalMilliseconds)
{
_requests.Dequeue();
} // Check if we can allow the request
if (_requests.Count < _maxQps)
{
_requests.Enqueue(now);
return true;
} return false;
}
}

4. 使用第三方库(如 AspNetCoreRateLimit

AspNetCoreRateLimit 是一个非常流行的 .NET 库,可以帮助开发者轻松实现 API 的限流。它支持多种限流算法,如固定窗口、滑动窗口、令牌桶等,并且可以在 ASP.NET Core 中使用。

安装 NuGet 包

dotnet add package AspNetCoreRateLimit

配置示例:

public void ConfigureServices(IServiceCollection services)
{
// Add rate limiting services
services.AddInMemoryRateLimiting();
services.Configure<IpRateLimitOptions>(options =>
{
options.GeneralRules = new List<RateLimitRule>
{
new RateLimitRule
{
Endpoint = "*",
Period = "1s", // Limit requests per second
Limit = 100 // Max 100 requests per second
}
};
}); services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
} public void Configure(IApplicationBuilder app)
{
app.UseIpRateLimiting();
}

5. 使用 Redis 实现分布式限流

如果你的应用是分布式的,可以使用 Redis 来存储每个请求的时间戳或者计数器,从而实现跨多台服务器的 QPS 限流。

示例

public class RedisRateLimiter
{
private readonly string _key;
private readonly int _maxQps;
private readonly IDatabase _database; public RedisRateLimiter(string key, int maxQps, IConnectionMultiplexer redis)
{
_key = key;
_maxQps = maxQps;
_database = redis.GetDatabase();
} public async Task<bool> IsRequestAllowedAsync()
{
var now = DateTime.UtcNow;
var timeFrame = TimeSpan.FromSeconds(1); var requestCount = await _database.ListLengthAsync(_key); // Remove expired requests from the list
await _database.ListRemoveAsync(_key, now.Add(-timeFrame).ToString()); if (requestCount < _maxQps)
{
// Add current request time to the list
await _database.ListLeftPushAsync(_key, now.ToString());
return true;
} return false;
}
}

6. 基于 ASP.NET Core 中间件限流

在 ASP.NET Core 应用中,可以创建一个中间件来处理请求限流逻辑,并通过 HTTP 请求的头信息来告知客户端当前的请求状态。

示例

public class RateLimitingMiddleware
{
private readonly RequestDelegate _next;
private readonly MemoryRateLimiter _rateLimiter; public RateLimitingMiddleware(RequestDelegate next, MemoryRateLimiter rateLimiter)
{
_next = next;
_rateLimiter = rateLimiter;
} public async Task InvokeAsync(HttpContext context)
{
if (!_rateLimiter.IsRequestAllowed(context.Connection.RemoteIpAddress.ToString()))
{
context.Response.StatusCode = 429;
await context.Response.WriteAsync("Rate limit exceeded.");
return;
} await _next(context);
}
}

总结

在 .NET 中实现 QPS 限流有很多方案,对于小流量的应用,内存限流和基于中间件的限流方式可能已经足够,而对于高并发的分布式系统,可能需要 Redis 或者更复杂的算法,如令牌桶或滑动窗口。


简介下这个 .net 开发的小系统

https://kf.shengxunwei.com/

升讯威在线客服与营销系统是一款客服软件,但更重要的是一款营销利器。

  • 可以追踪正在访问网站或使用 APP 的所有访客,收集他们的浏览情况,使客服能够主动出击,施展话术,促进成单。
  • 可嵌入网站、手机 APP、公众号、或者通过 URL 地址直接联系客服。
  • 支持访客信息互通,可传输访客标识、名称和其它任意信息到客服系统,与您的业务系统对接。
  • 可全天候 7 × 24 小时挂机运行,网络中断,拔掉网线,手机飞行模式,不掉线不丢消息,欢迎实测。

希望能够打造: 开放、开源、共享。努力打造 .net 社区的一款优秀开源产品。

钟意的话请给个赞支持一下吧,谢谢~

如何为 .NET 在线客服系统的 Open Api 开放接口实现 QPS 限流功能的更多相关文章

  1. .net core 和 WPF 开发升讯威在线客服系统:调用百度翻译接口实现实时自动翻译

    业余时间用 .net core 写了一个在线客服系统.并在博客园写了一个系列的文章,写介绍这个开发过程. 我把这款业余时间写的小系统丢在网上,陆续有人找我要私有化版本,我都给了,毕竟软件业的初衷就是免 ...

  2. 使用 WPF+ ASP.NET MVC 开发 在线客服系统 (一)

    近段时间利用业余时间开发了一套在线客服系统,期间遇到过大大小小不少问题,好在都一一解决,最终效果也还可以,打算写一个系列的文章把开发过程详细的记录下来. 希望能够和更多的开发人员互相交流学习,也希望有 ...

  3. Vue在线客服系统【开源项目】

    1. 项目介绍 一个基于Vue2.0的在线客服系统. 技术栈包含:Vue.VueX.Vue Router.Element UI. 2. 功能介绍 项目包含了2个模块:客服端和访客端. 2.1 客服端功 ...

  4. .net core 和 WPF 开发升讯威在线客服系统【私有化部署免费版】发布

    希望 .net 和 WPF 技术时至今日,还能有一些存在感. 这个项目源于2015年前后,当时开发的初版,我使用了 ASP.NET MVC 做为后端,数据库使用原生 ADO.NET 进行操作.WPF ...

  5. CentOS 30分钟部署 .net core 在线客服系统

    前段时间我发表了一系列文章,开始介绍基于 .net core 的在线客服系统开发过程.期间有一些朋友希望能够给出 Linux 环境的安装部署指导,本文基于 CentOS 8.3 来安装部署.在本文中我 ...

  6. Docker 版 3分钟部署 .net core 开源在线客服系统,他来了

    我在博客园发表了一系列文章,开始介绍基于 .net core 的在线客服系统开发过程. 前些天又应朋友的要求,发了一篇 CentOS 版本的安装部署教程:https://www.cnblogs.com ...

  7. Linux + .net core 开发升讯威在线客服系统:同时支持 SQL Server 和 MySQL 的实现方法

    前段时间我发表了一系列文章,开始介绍基于 .net core 的在线客服系统开发过程. 有很多朋友一直提出希望能够支持 MySQL 数据库,考虑到已经有朋友在用 SQL Server,我在升级的过程中 ...

  8. Linux + .net core 开发升讯威在线客服系统:首个经过实际验证的高性能版本

    业余时间用 .net core 写了一个在线客服系统.并在博客园写了一个系列的文章,写介绍这个开发过程: .net core 和 WPF 开发升讯威在线客服系统:目录 https://blog.she ...

  9. 使用 WPF + Chrome 内核实现 在线客服系统 的复合客服端程序

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 免费使用 & 私有化部署免费下载:https://docs.sh ...

  10. .net core 和 WPF 开发升讯威在线客服系统:把 .Net Framework 打包进安装程序

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程. 系列文章目录: https://blog.shengxunwei.com/Home/Post/44a3 ...

随机推荐

  1. 2020-2021 ACM-ICPC Brazil Subregional Programming Contest

    A. Sticker Album 你想要得到\(n\)张贴纸,每包礼物中等概率出现 \([A,B]\)范围内数量的贴纸,求需要买多少包礼物才能至少获得\(n\)张贴纸的期望次数 \(1 \leq n ...

  2. 《Java开发手册》-部分编码规范分享

    0. 前言 本文来自<阿里巴巴Java开发手册>,以下内容均根据自己偏好摘抄.总结.分享. 1. 编程规约 包名单数,类名复数.例如:com.tao.util.JsonUtils.java ...

  3. 销讯通CRM系统如何确保拜访数据的真实有效

    销讯通CRM系统如何确保并检查拜访过程数据的真实性,是一个值得深入探讨的课题. 01 在信息化高度发达的今天,我们拥有GPS定位.AI人脸识别等先进技术,这些技术无疑为数据的真实有效性提供了强有力的保 ...

  4. NET 6 中新增的LINQ 方法

    .NET 6 中添加了许多 LINQ 方法. 下表中列出的大多数新方法在 System.Linq.Queryable 类型中具有等效方法. 欢迎关注 如果你刻意练习某件事情请超过10000小时,那么你 ...

  5. 以下哪一项是对CSMA/CA和CSMA/CD LAN控制通用的CSMA方法的适当描述?

    A.   检测载波信号并控制数据传输. B.   获得具有传输权的消息(令牌)的终端传输数据. C.   如果在数据传输过程中发生冲突,立即重新发送. D.   即使在使用传输线时也可以传输数据. = ...

  6. Redis应用—4.在库存里的应用

    大纲 1.库存模块设计 2.库存缓存分片和渐进式同步方案 3.基于缓存分片的下单库存扣减方案 4.商品库存设置流程与异步落库的实现 6.库存入库时"缓存分片写入 + 渐进式写入 + 写入失败 ...

  7. FineReport取消强制分页和调整宽度的设置方法

    在decision里,找到管理系统-目录管理,打开相应挂载的报表,在参数设置里,添加以下内容: _bypagesize_ 字符串 false

  8. 鸿蒙应用开发从入门到入行 - 篇8:Tabs选项卡页签视图切换

    鸿蒙应用开发从入门到入行 第八天 - Tabs选项卡 导读:在本篇文章里,您将掌握使用Tabs选项卡做栏目分类,这是未来应用开发中极为常用的组件 首先说一声抱歉,比较忙很久没更新了.但放心吧,目前该忙 ...

  9. .NET Aspire 中的服务发现

    .NET Aspire 中的服务发现 https://www.nuget.org/packages/Microsoft.Extensions.ServiceDiscovery .NET Aspire ...

  10. WPS在ArchLinux常见问题

    问题简述wps在aur源上有包,直接下载安装即可,但是通过包管理器安装的wps会出现一些奇怪的问题,我遇到的有两个: wps在打开时提示缺少字体wps word不能导出pdf文档,同时wps pdf也 ...