讲师中心 微信公众号
AI工具推荐 视频效率加速

c# 如何用c#实现一个漏桶算法来进行API限流

千萱大大_1299

千萱大大_1299

发布时间:2026-01-27 11:04:34

|

136人浏览过

|

来源于php中文网

原创

漏桶算法的核心逻辑是用固定速率“漏水”的容器约束请求流入,只保证流出恒定而不关心突发流量。C#中通过维护currentLevel和lastLeakTime两个状态,按时间差计算自然漏量,结合ConcurrentDictionary实现无锁、线程安全、纯内存的单机限流。

c# 如何用c#实现一个漏桶算法来进行api限流

漏桶算法的核心逻辑是什么

漏桶算法本质是用固定速率“漏水”的容器来约束请求流入。它不关心突发流量有多大,只保证流出速率恒定。在 C# 中实现时,关键不是模拟水滴物理过程,而是维护两个状态:currentLevel(当前桶中水量,即待处理请求数)和lastLeakTime(上次漏水时间),再按时间推算已自然漏掉多少请求。

用 ConcurrentDictionary + DateTime.UtcNow 实现线程安全的单机限流

不需要引入 Redis 或外部依赖,纯内存实现适用于单服务实例场景。重点在于避免锁竞争,同时保证时间计算不被系统时钟回拨干扰。

  • ConcurrentDictionary<string bucketstate></string> 按 API 路径或用户 ID 分桶,key 建议包含租户/用户标识以支持细粒度控制
  • 每次请求调用 TryAcquire() 方法:先读取当前桶状态,再按时间差计算应漏掉的量,更新 currentLevel,最后判断是否 ≤ 容量
  • 必须用 DateTime.UtcNow,不能用 DateTime.Now,否则跨时区或本地时钟不准会导致误判
  • 更新状态时使用 GetOrAdd + CompareExchange 模式,避免竞态下覆盖他人写入
public class LeakyBucketRateLimiter
{
    private readonly ConcurrentDictionary<string, BucketState> _buckets = new();
    private readonly int _capacity;
    private readonly double _leakRatePerSecond; // 每秒漏出请求数,如 10 表示 QPS=10
<pre class='brush:php;toolbar:false;'>public LeakyBucketRateLimiter(int capacity, double leakRatePerSecond)
{
    _capacity = capacity;
    _leakRatePerSecond = leakRatePerSecond;
}

public bool TryAcquire(string key)
{
    var now = DateTime.UtcNow;
    var bucket = _buckets.GetOrAdd(key, _ => new BucketState());

    while (true)
    {
        var snapshot = bucket.Value;
        var elapsedSeconds = (now - snapshot.LastLeakTime).TotalSeconds;
        var leaked = elapsedSeconds * _leakRatePerSecond;
        var newLevel = Math.Max(0, snapshot.CurrentLevel - leaked);

        var updated = new BucketState
        {
            CurrentLevel = newLevel + 1,
            LastLeakTime = now
        };

        if (newLevel + 1 <= _capacity)
        {
            if (bucket.CompareExchange(updated, snapshot) == snapshot)
                return true;
        }
        else
        {
            // 超过容量,不增加 currentLevel,只更新时间以便下次计算漏水量
            var idleUpdate = new BucketState
            {
                CurrentLevel = newLevel,
                LastLeakTime = now
            };
            bucket.CompareExchange(idleUpdate, snapshot);
            return false;
        }
    }
}

private class BucketState
{
    public double CurrentLevel { get; set; }
    public DateTime LastLeakTime { get; set; } = DateTime.UtcNow;
}

}

Redis Skill - 高性能缓存管理
Redis Skill - 高性能缓存管理

Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。

下载

为什么不用 Timer 或后台线程主动漏水

主动定时“漏水”看似直观,但实际会带来严重问题:

  • 每个桶配一个 Timer → 内存与线程开销爆炸,尤其 key 多时(如每用户一桶)
  • Timer 触发非实时,可能延迟几十毫秒,导致限流精度下降
  • 应用重启时 Timer 状态丢失,而按需计算的方式天然无状态、可热启
  • 漏桶本就是被动模型——只在请求来时才结算“到目前为止漏了多少”,这才是符合语义的实现

部署到 ASP.NET Core 的中间件里要注意什么

直接注入 LeakyBucketRateLimiter 实例到 DI 容器没问题,但必须注意生命周期和 key 构造:

  • 注册为 Singleton,桶状态要跨请求共享
  • key 不要只用 httpContext.Request.Path,建议组合 ip + path 或 userId + path,否则所有用户共用一个桶就失去意义
  • 若用 JWT,可在中间件里解析 HttpContext.User.Identity.Name 或自定义 claim 获取用户标识
  • 返回 429 时,建议加 Retry-After 响应头,值可估算:`(currentLevel / leakRatePerSecond)` 秒后才可能通过

漏桶真正难的不是代码几行,而是 key 的语义设计和漏率单位的对齐——比如你设了每秒漏 5 个,但业务上其实是“每 200ms 放行 1 个”,这两者在浮点运算下会有累积误差,高并发下可能偏移数百毫秒。上线前务必用 Stopwatch 做真实吞吐压测,别只信理论计算。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

629

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

624

2025.12.18

ThinkPHP中间件机制与请求拦截处理实践
ThinkPHP中间件机制与请求拦截处理实践

本专题围绕 ThinkPHP 中间件体系展开,深入讲解中间件的定义、注册与执行流程。内容包括全局中间件与路由中间件的区别、请求前后处理逻辑、自定义中间件开发以及权限验证与日志处理应用。通过实际案例,帮助开发者掌握中间件在项目中的核心作用与最佳实践。

418

2026.03.31

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4078

2023.08.10

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

5716

2023.08.14

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

4449

2023.11.02

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

3995

2023.11.14

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

7352

2024.04.02

Linux 新手先学哪些命令
Linux 新手先学哪些命令

Linux新手命令专题汇集终端基础、文件目录操作、文本查看、软件安装和权限管理等入门文章,帮助按实际任务练习常用命令并建立命令行操作习惯。

0

2026.10.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn