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

news/2025/2/23 5:13:17/文章来源:https://www.cnblogs.com/sheng_chao/p/18719024

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

而我收到的用户需求也越来越多,产品化的需求,个性化的需求都有。最近两天收到一个用户的开放接口需求,为客服系统的 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 secondwhile (requestQueue.Count > 0 && (now - requestQueue.Peek()).TotalSeconds >= 1){requestQueue.Dequeue();}// Check if the current request exceeds the limitif (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 tokensif (elapsedSeconds > 1){_tokens = Math.Min(_bucketCapacity, _tokens + (int)(elapsedSeconds * _tokensPerSecond));_lastRefillTime = now;}// Check if we have tokens availableif (_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 windowwhile (_requests.Count > 0 && (now - _requests.Peek()).TotalMilliseconds > _windowSize.TotalMilliseconds){_requests.Dequeue();}// Check if we can allow the requestif (_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 servicesservices.AddInMemoryRateLimiting();services.Configure<IpRateLimitOptions>(options =>{options.GeneralRules = new List<RateLimitRule>{new RateLimitRule{Endpoint = "*",Period = "1s",   // Limit requests per secondLimit = 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 listawait _database.ListRemoveAsync(_key, now.Add(-timeFrame).ToString());if (requestCount < _maxQps){// Add current request time to the listawait _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 社区的一款优秀开源产品。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/884896.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 部署 tensorRT resnet分类模型 deploy TensorRT model with C#

基于生态的优势,一般都是用pytorch写模型;但是工业现场的部署,目前比较方便的还是onnx;当下为了追求效率,使用了TensorRT C#: .net8 GPU: A2000 / 4070Ti OS: windows Cuda: 11.8 预处理:Emgu.CVinstall v11.8 Cuda 默认安装,会生成以下路径 C:\Program Files\NVIDIA GP…

自然语言处理入门【第6章】:自然语言处理的应用

搜广推业务 信息检索 搜索、广告和推荐是很多互联网大厂赖以生存的命脉。比如,百度的搜索引擎、京东淘宝的推荐系统、腾讯的广告业务等。这一节我们就看看搜广推业务当中的自然语言处理方法。 1. 什么是信息检索 信息检索(Information Retrieval,IR)是指从大量的非结构化或…

提取东京食尸鬼主题曲

钢琴的声音实在是太好听了,这演奏者的指法真的逆天了! 利用IE缓存来提取视频文件是屡试不爽啊,只要视频不是经过加密的,均能提取成功。打开IE浏览器,关闭所有标签,仅留下一个空白标签,并打开Internet选项删除浏览历史记录点设置,查看文件,打开缓存文件夹,删除文件夹内…

树梅派XBMC解决方案比较

本文是Raspberry Pi XBMC Solutions Compared: Raspbmc vs OpenELEC vs XBian的译文,可能已经过时。XMBC是我们最喜欢的媒体中心解决方案之一。Raspberry Pi使得打造一台豪华的XMBC机器仅需35$。有三个为Pi定制的版本,但是,你该选择哪一个呢?这些版本略有差异,各有长短。本…

deepseek破限的一种方法

起因是https://www.south-plus.net/read.php?tid=2455666这篇帖子的作者在B22F提到他的Deepseek的破甲关键词和使用流程,咱直接复制粘贴直接被deepseek拒绝了呜呜呜 失败案例: 我大致提取了一段不会被办的话,试了一下可以和其他的混合使用破甲效果极佳(但是荤段子得靠其他…

实体机双系统

本文年代久远,可能已经不再适用。仅供参考首先说一下,双系统并不会影响两个系统各自的速度。两个系统都是独立的,分别位于硬盘的不同位置,独立运行。也就是说,当一个系统在运行时,另一个系统只是储存在硬盘上的文件,这自然不会对系统的速度有影响。 另外,安装双系统是有…

2024.1.17web HTTP协议基础

2.1 HTTP的基本概念与交互模型 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写。它是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。 HTTP 协议的特点 1.无连接—限制每次连接只处理一个请求 2.无状态—协议对于事务…

173 词转换成向量形式

介绍一下\(\text{Skip-Gram}\)算法。非常简单的一个算法,训练集由\(\text{context}\)和\(\text{target}\)组成,前者是一个句子中的某一个单词,后者是这个句子中这个单词临近的某个词。举例如下我们获得单词的嵌入向量后,就放入神经网络中去跑,再利用\(\text{Softmax}\)如下…

对象

Array:数组 定义 var 变量名 = new Array(元素) var arr = new Array(1,2,3); var 变量名 = [元素] var arr = [1,2,3]; arr[索引]=值; 可以变长变类型

《操作系统真相还原》实验记录2.9——完善内存管理系统

本文章实现内容如下: ① 完成了更细粒度的内存分配机制——arena机制的建立 ② 完成了内存分配系统调用 malloc() 的实现 ③ 完成了内存释放系统调用 free() 的实现一、malloc 底层原理之前我们虽然已经实现了内存管理,但显得过于粗糙,分配的内存都是以 4KB 大小的页框为单位…

智能化客户画像构建管理:AI视频监控在大型商场的技术方案介绍(part5)

前言:某商家为了优化卖场服务与营销策略,希望通过非侵入式手段获取客户画像,不仅可以帮助卖场提升服务质量、优化营销策略,还能通过数据驱动的方式提升销售业绩和顾客满意度,为卖场的长期发展奠定坚实的基础。具体需求 1、性别分析:识别顾客的性别比例,为产品布局和服务…

169 使用词嵌入

以判断人名为例。如果我们只使用独热编码,那么我们的训练集不能太大(否则维度爆炸),所以遇到了下面这种情况我们没有在训练集中坚果durian和cultivator,导致我们没有判断出来Robert Lin是人名 但是如果我们使用词嵌入,我们的训练集就可以很大(从网上下载即可),然后通过…