API网关后端微服务【免费下载链接】Ocelot.NET API Gateway项目地址https://gitcode.com/gh_mirrors/oc/Ocelot点击查看免费下载导读Ocelot 作为 .NET 生态的 API 网关内置了面向**上游请求upstream requests**的限流能力用于防止下游服务被突发流量压垮。本文以仓库 docs/features/ratelimiting.rst 文档为主线结合 src/RateLimiting 目录下的核心实现源码系统讲解RateLimitOptions配置 Schema、路由级与全局级限流的完整配置、Limit/Period/Wait等参数的语义与默认值、Fixed Window 与 Hybrid Fixed Window 两种已实现算法、以及 By Clients Header 规则分区Partition的处理流程。读完本文你将能够在ocelot.json中独立配置路由级与全局限流理解配额超限Quota Exceeded期间响应头与状态码的行为并掌握与 ASP.NET Core 原生限流中间件的边界关系。说明限流是 Ocelot 历史最悠久的功能之一由 PR 引入后于 1.3.2 版本首次发布全局限流配置于 24.1 版本引入见 ReleaseNotes.md 与 docs/releasenotes.rst 相关章节。文中涉及的配置均以当前仓库代码为准。一、RateLimitOptionsSchema路由级限流配置骨架Ocelot 为每个路由Route预留了名为RateLimitOptions的特殊 JSON 对象。正如 docs/features/configuration.rst 中的路由 Schema 与动态路由 Schema 章节所述你可以在路由的RateLimitOptions中定义限流规则。完整的 Schema 示例如下JSON 注释仅用于说明ocelot.json本身不支持注释RateLimitOptions: { // rule, partition by ClientIdHeader: , ClientWhitelist: [], // management opts EnableRateLimiting: true, EnableHeaders: true, // algorithm Limit: 1, Period: , Wait: , // extended opts StatusCode: 1, QuotaMessage: , KeyPrefix: }三个必须理解的要点完整 Schema 的权威定义在 C# 类中路由级RateLimitOptions的全部可用属性定义在 src/Configuration/File/FileRateLimitByHeaderRule.cs 的FileRateLimitByHeaderRule类中全局级配置对应的FileGlobalRateLimitByHeaderRule类定义于 src/Configuration/File/FileGlobalRateLimitByHeaderRule.cs额外增加了一个RouteKeys数组选项用于把全局选项应用到指定的路由分组。如果全局RateLimitOptions中没有定义RouteKeys则全局设置将应用到所有路由。必填项只有Limit与Period其余选项均有默认值。如果这两个必填项未定义且不存在全局配置Ocelot 会因内部生成的验证错误而启动失败错误会出现在日志中。这一验证逻辑在 src/Configuration/Validator/RouteFluentValidator.cs 中实现当RateLimitOptions存在且EnableRateLimiting ! false时会校验Limit必须大于 0、Period非空、且Period必须是整数 单位的合法格式如1m表示 1 分钟。部分选项来自旧版 Schema从 24.0 及更早版本沿用的若干 废弃选项 会保留一个发布周期新旧选项的对应关系详见下文配置表。二、完整配置路由级 全局级限流一份完整的限流配置由路由级与全局级两部分组成。全局配置写在ocelot.json的GlobalConfiguration节中仓库中可参考 samples/Basic/ocelot.json 等示例的配置结构。以下示例来自官方文档并做了参数级注解Routes: [ { Key: R1, RateLimitOptions: { ClientWhitelist: [ocelot-client1-preshared-key], Limit: 1000, Period: 20s, // 支持 (milli)seconds、minutes、hours、days Wait: 1.5m, // 支持 (milli)seconds、minutes、hours、days StatusCode: 418, // Im a teapot - 特殊状态码 QuotaMessage: Out of coffee! Our bar can only serve up to {0} cups of coffee every {1}. In the meantime, why not grab some tea and relax for Retry-After seconds until were ready to serve again? } } ], GlobalConfiguration: { BaseUrl: https://api.ocelot.net, RateLimitOptions: { RouteKeys: [R1], // 未定义或空数组时选项应用于所有路由 ClientIdHeader: Oc-Client, // 标准默认头名称 Limit: 100, Period: 30s, // 支持 ms、s、m、h、d Wait: 1m, // 支持 ms、s、m、h、d StatusCode: 429, // Too Many Requests - 标准状态码 QuotaMessage: Ocelot API calls quota exceeded! Maximum admitted {0} per {1}., // 含 2 个占位符的标准模板 KeyPrefix: ocelot-rate-limiting // 缓存键前缀 } }配置参数详解Schema 选项说明ClientIdHeader用于标识客户端的请求头名称默认值为Oc-Client。ClientWhitelist豁免限流的客户端 ID 数组白名单。EnableRateLimiting启用或禁用限流默认true启用。EnableHeaders是否输出X-RateLimit-*与Retry-After响应头未定义时默认true启用。Limit客户端在给定时间Period内允许的最大请求数。Period限流周期固定窗口可表达为毫秒1ms、秒1s、分1m、时1h或天1d。当请求数恰好达到Limit即配额超限*时请求被立即拦截若定义了Wait则开始等待期。Wait限流等待窗口无服务期单位同上。该时长可以与Period固定窗口不同可更短或更长用于延长或缩短配额超限期*——该时期通常在固定窗口结束后终止。StatusCode配额超限期*内返回的拒绝状态码默认值 429Too Many Requests。QuotaMessage配额超限时返回的消息体模板作为超限响应消息的格式化字符串未指定时使用默认的提示性消息。KeyPrefix计数器前缀用于组合限流计数器的缓存键供IRateLimitStorage服务使用默认值为Ocelot.RateLimiting。关于配额超限期Quota Exceeded period术语它指Wait窗口若已定义或请求数超出Limit那一刻起Period固定窗口的剩余时长。在此期间网关返回配置的拒绝StatusCode并在响应体中写入格式化后的QuotaMessage。客户端应通过Retry-After头浮点数秒判断该时期何时结束——它表示距离下一个固定窗口开始的秒数。若EnableHeaders开启X-RateLimit-*头也会在配额超限期内随响应返回。Period与Wait的解析规则字符串必须由浮点数 时间单位构成支持的单位为ms、s、m、h、d。未指定单位时默认按毫秒解释例如333.5被解析为 333 毫秒又 500 微秒等价于333.5ms。浮点部分可省略如10.0s等价于10s。这些值在运行期动态解析ocelot.json中必填的Period会在 Ocelot 启动时通过 FluentValidation 提前校验见 src/Configuration/Validator/RouteFluentValidator.cs。若传入非法值限流中间件会抛出FormatException并记录日志。具体的解析实现位于 src/Configuration/RateLimitRule.cs 的RateLimitRule.ParseTimespan方法它按字符串中最后一个数字/小数分隔符位置切分出数值与单位再依据d/h/m/s/ms/空 六种情况换算为TimeSpan未知单位直接抛出FormatException。RateLimitRule还会对Limit取绝对值Math.Abs并把规则格式化为{Limit}/{Period}/w{Wait}字符串见 src/Configuration/RateLimitRule.cs该字符串参与计数器缓存键的生成。三、路由级与全局级限流的关系与注意事项从源码结构看全局选项的落地依赖路由分组机制FileGlobalRateLimitByHeaderRule实现IRouteGroup接口通过RouteKeysHashSetstring引用已定义的FileRouteBase.Key属性见 src/Configuration/File/FileGlobalRateLimitByHeaderRule.cs。使用全局限流时需注意路由归属判定若全局RateLimitOptions未定义RouteKeys或数组为空全局设置应用于所有路由若数组包含路由键则定义了一个路由分组仅对该组生效。被排除在分组之外的路由必须自行声明路由级RateLimitOptions否则将无任何限流规则。适用场景的权衡全局限流会统一限制所有路由在微服务架构中通常不合理不同服务应有不同配额但如果所有路由共享相同的下游主机全局限流可以有效地把配额限定到单个服务或单个产品的用量上此时全局方案是合理的。四、废弃选项Deprecated Options以下选项来自 24.0 及更早版本的旧 Schema保留一个发布周期用于向后兼容预计在 25.0 大版本中移除废弃选项新选项说明DisableRateLimitHeadersEnableHeaders控制X-RateLimit-*与Retry-After响应头的禁用/启用。PeriodTimespanWait以秒为单位指定允许重试的时间在该间隔内QuotaExceededMessage会随对应的HttpStatusCode一起写入响应建议客户端依据Retry-After头确定后续请求时机。HttpStatusCodeStatusCode限流期间返回的 HTTP 状态码默认 429Too Many Requests。QuotaExceededMessageQuotaMessage配额超限时展示的消息可选默认消息为提示性文本。RateLimitCounterPrefixKeyPrefix用于构造限流计数器缓存键的前缀。优先级与迁移建议DisableRateLimitHeaders自 24.1 起被标记为废弃[Obsolete]应改用EnableHeaders并按需取布尔取反。若两者同时定义DisableRateLimitHeaders优先否则使用EnableHeaders。不要同时定义这两个选项。从 src/Configuration/File/FileRateLimitByHeaderRule.cs 可以看到这些旧属性均带[Obsolete]特性并明确注明将在版本 25.0 移除其迁移逻辑在RateLimitOptions(FileRateLimitByHeaderRule fromRule)构造函数中体现见 src/Configuration/RateLimitOptions.cs例如StatusCode取HttpStatusCode ?? StatusCode ?? 429QuotaMessage取QuotaExceededMessage为空时的QuotaMessageKeyPrefix同理回退。官方计划引入自动配置升级机制以支持向后兼容但仍建议尽早切换到新选项。五、已实现的限流算法Fixed Window 与 Hybrid Fixed WindowOcelot 自研限流器当前实现了两种算法固定窗口Fixed window仅基于Period选项不依赖Wait即此前废弃的PeriodTimespan对应的行为。混合固定窗口Hybrid fixed windowPeriod与Wait的组合在固定窗口行为之上增加了对配额超限期时长与处理方式的额外控制。从历史沿革看Ocelot 的限流算法本就是经典固定窗口 等待无服务期的混合形态自 24.1 起该混合算法被拆分为两个独立算法经典固定窗口可以单独使用。算法核心实现的证据src/RateLimiting/RateLimiting.csCount方法第 72-90 行维护一个RateLimitCounter结构体见 src/RateLimiting/RateLimitCounter.cs包含StartedAt、Total与可空的ExceededAt。逻辑为无缓存条目时以当前请求为第 1 次开始计数每次请求Total当超过Limit且尚未记录超限时刻时记录ExceededAt now随后判断StartedAt PeriodSpan now固定窗口内或ExceededAt WaitSpan now等待窗口内任一成立则继续计数否则重置计数器并立即开始新一轮计数。RetryAfter方法第 127-153 行计算重试秒数未超限返回 0Wait未启用且固定窗口未结束返回窗口结束时刻 - now的秒数等待窗口活跃时返回超限时刻 等待时长 - now的秒数两个窗口均已结束返回 -1由上层ProcessRequest触发计数器重置。ProcessRequest第 31-63 行通过静态ProcessLocker锁保证对存储的串行读写计数器过期时间取PeriodSpan WaitSpan再额外加 1 秒作为并发线程同步余量。两点重要的边界说明官方文档明确Ocelot 自研限流器未实现滑动窗口Sliding Window、令牌桶Token Bucket、并发Concurrency等其他经典算法——这些已列入 Roadmap 计划。Ocelot 自研限流器不通过队列管理并发 HTTP 请求并发处理与决策应放在客户端使用经典重试模式保证服务质量。其管理策略刻意保持简单先到先得First-In means First Wins。若首个请求从限流配额中取得虚拟租约后配额立即超限第二个请求将被以 429Too Many Requests直接拒绝。术语背景固定窗口、滑动窗口、令牌桶等概念可参考官方文档开篇给出的学习资源如微软 Learn 的What is rate limiting?、Rate Limiting pattern、Rate limit an HTTP handler in .NET、Rate limiting middleware in ASP.NET Core等文章这里不再展开行业通识。六、规则与分区Rules / PartitionsBy Clients HeaderOcelot 的限流规则rule是配置项的超集它通过不同的处理阶段实现分区限流客户端标识 → 专用分区计数器配额→ 限流算法 → 配额超限响应行为。其类定义为 src/Configuration/File/FileRateLimitByHeaderRule.cs 中的FileRateLimitByHeaderRuleJSON 对应上文 第一节 的 Schema。客户端请求的四步处理流程目前中间件仅支持并处理按客户端请求头By Clients Header这一种规则分区——即 ASP.NET Core 术语中的 API Key partition。Ocelot 的限流架构为每个路由提供独立子分区每个子分区拥有独立的算法计数器。当客户端流量进入 Ocelot 管线后请求按以下步骤处理路由识别Ocelot 将 URL 路径与上游路由路径匹配识别路由后由限流中间件把该客户端纳入路由分区处理。身份构建限流中间件依据配置的 By Clients Header 规则创建客户端身份并为其分配独立的限流计数器。身份在 src/RateLimiting/ClientRequestIdentity.cs 中定义为ClientRequestIdentity(ClientId, LoadBalancerKey)只读记录结构ToString()输出ClientId:LoadBalancerKey格式。算法执行中间件执行已配置的限流算法即上文的混合固定窗口。入口代码见 src/RateLimiting/RateLimitingMiddleware.cs_limiter.ProcessRequest(...)返回计数器当counter.Total rule.Limit时先计算RetryAfter值、记录被拦截请求的警告日志然后调用Break短路响应。配额超限响应若配额超限中间件返回配额超限期产物——拒绝状态码、响应体消息以及Retry-After等头。身份识别失败与白名单行为身份识别失败 → 503如果客户端身份为空例如缺少请求头或ClientIdHeader值无效中间件会以503 Service Unavailable状态拦截请求并在响应体写入相应的错误消息。在 RateLimitingMiddleware.cs 中空ClientId会触发警告日志与Break(context, errorOpts, -1.0)短路其中errorOpts强制将StatusCode置为 503。白名单豁免通过ClientWhitelist定义的白名单客户端不受限流限制直接放行到下一中间件第 43-47 行。EnableHeaders行为未超限的正常请求在EnableHeaders开启时会挂载X-RateLimit-*响应头X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset由 src/RateLimiting/RateLimitingHeaders.cs 定义头部数据由RateLimiting.GetHeaders计算remaining Limit - counter.Totalreset StartedAt PeriodSpan见 src/RateLimiting/RateLimiting.cs。重要安全提示中间件不负责 API Key 校验Ocelot 的限流中间件不负责校验 API Key即客户端请求头的值。用户与开发者必须在 Ocelot 侧将这些头值注册为预共享 API Key并确保在控制权移交给RateLimitingMiddleware之前完成校验。官方推荐方案实现自定义中间件校验 API Key并通过中间件注入特性注入 Ocelot 管线——覆盖第 3 位的PreErrorResponderMiddleware因为它先于第 10 位的RateLimitingMiddleware执行。更进阶的方案是使用第 7 位的SecurityMiddleware但此时必须自行实现ISecurityPolicy服务并在依赖注入容器中替换默认实现。关于 Ocelot 管线的中间件位置可参考OcelotMiddlewareExtensions见 src/Middleware/OcelotMiddlewareExtensions.cs中Use*Middleware的注册顺序。缓存键与存储计数器缓存键由 src/RateLimiting/RateLimiting.cs 的GetStorageKey生成——先拼接{KeyPrefix}_{identity}_{rule}再做 SHA1 哈希并转为十六进制字符串。存储通过IRateLimitStorage抽象默认实现为基于IMemoryCache的 MemoryCacheRateLimitStorage.cs每个 Ocelot 实例独立、实例间无同步如需跨实例共享计数可注册基于IDistributedCache的 DistributedCacheRateLimitStorage.cs它将RateLimitCounter序列化为 JSON 存储。该抽象对应的单元测试见 unit/RateLimiting 目录。七、全局限流的历史与使用建议Notes版本沿革24.1 之前全局限流选项仅在特殊的动态路由Dynamic Routing模式下可用自 24.1 起全局配置对静态路由与动态路由均可用。官方团队正在考虑为聚合路由Aggregated Routes实现类似全局配置——不过聚合路由本质上是静态路由的组合因此需要谨慎设计。使用建议全局限流可能并不实用因为它对所有路由施加相同限制。微服务架构下为不同路由统一限流并不常见路由级限流通常能提供更贴合需求的方案。但如果所有路由共享同一组下游主机全局限流可以合理地把限制收敛到单个服务或单个产品的用量。DisableRateLimitHeaders的处置该选项自 24.1 起废弃改用EnableHeaders并按需取反若两者同时定义前者优先否则使用后者。不要同时定义两个选项。该设置仅为向后兼容保留并将在 25.0 大版本移除——其他废弃选项同理。与 ASP.NET Core 原生限流的关系Ocelot 自研限流不基于 ASP.NET Core 内置特性因此不是 Roadmap 中所述 ASP.NET Core 限流中间件的直接包装。Ocelot 团队认为 ASP.NET Core 的限流中间件通过限流策略rate-limiting policies实现了全局限制这是两种不同的设计取向。八、响应头与计数器运行期行为细节结合 src/RateLimiting/RateLimitingMiddleware.cs 的完整调用链可以归纳出中间件的运行期行为请求进入后中间件把当前 UTC 时间写入HttpContext.Items第 32-33 行并从DownstreamRoute读取RateLimitOptions若EnableRateLimiting false则直接放行第 35-40 行。身份识别Identify逻辑读取ClientIdHeader指定的请求头为空时回退到默认头Oc-Client构造ClientRequestIdentity第 98-108 行。超限时Break方法把Retry-After以浮点秒字符串写入响应头构造DownstreamResponse并同时记录QuotaExceededError第 88-96 行GetResponseMessage使用string.Format(format, rule.Limit, rule.Period)填充QuotaMessage中的{0}与{1}占位符第 138-142 行。响应体的状态码直接取(HttpStatusCode)options.StatusCode第 121-136 行。值得留意的是源码注释指出 Ocelot 产出的限流头并不完全符合行业标准相关讨论与草案见RateLimitingHeaders类的文档注释src/RateLimiting/RateLimitingHeaders.cs因此在对接客户端 SDK 时建议以Retry-After为主、X-RateLimit-*为辅。九、Roadmap 路线图规则RulesOcelot 团队正在参照 2022 年 7 月发布的 Announcing Rate Limiting for .NET 文章重新设计限流特性。当前决定是保留自研RateLimitingMiddleware并扩展一条引用 ASP.NET Core 限流策略policy的新规则该规则很可能随 25.0 版本落地。算法Algorithms除已内置的混合固定窗口外团队计划引入行业标准算法滑动窗口Sliding window优先级最高将最先引入、令牌桶Token bucket、并发Concurrency。这些轻量级算法应能通过 JSON 直接配置以便非 .NET 开发者无需编写 C# 代码即可使用。其他有价值的算法也欢迎社区讨论。官方仓库中可以通过带Rate Limiting标签的 Issue/PR 追踪该功能的开发历史仓库 README.md 与 ReleaseRadar.md 中亦有版本动态说明。十、快速上手清单在路由的RateLimitOptions中至少配置Limit与Period如需等待窗口配置Wait。如需全局统一配额在GlobalConfiguration.RateLimitOptions中配置并用RouteKeys限定目标路由分组留空则作用于所有路由。设置ClientIdHeader以标识客户端默认Oc-Client并通过ClientWhitelist放行可信客户端。开启EnableHeaders默认开启以输出X-RateLimit-*与Retry-After头QuotaMessage可自定义包含{0}Limit与{1}Period占位符的模板。校验 API Key 请使用自定义中间件推荐覆盖PreErrorResponderMiddleware不要依赖限流中间件本身。若需跨实例共享计数用IDistributedCache替换默认的IMemoryCache存储DistributedCacheRateLimitStorage。升级到 24.1 后逐步把DisableRateLimitHeaders/PeriodTimespan/HttpStatusCode/QuotaExceededMessage/RateLimitCounterPrefix迁移到新选项避免 25.0 移除后配置失效。赞分享API网关后端微服务【免费下载链接】Ocelot.NET API Gateway项目地址https://gitcode.com/gh_mirrors/oc/Ocelot点击查看免费下载相关推荐BullMQ Elixir 限流Rate Limiting实战指南Worker 级限流配置、Redis 原理与监控BullMQ Elixir 限流Rate Limiting实战指南Worker 级限流配置、Redis 原理与监控 导读 本指南基于 BullMQ 官方指后端消息队列任务调度终极指南DataHub服务限流配置详解与最佳实践终极指南DataHub服务限流配置详解与最佳实践 DataHub作为现代数据栈的核心元数据平台随着用户规模和数据量的增长服务限流Rate Limitin数据目录数据治理数据血缘后端前端数据工程数据集成Yii 2 RESTful API 限流Rate Limiting完整实战指南从 RateLimitInterface 到漏桶算法与 429 响应Yii 2 RESTful API 限流Rate Limiting完整实战指南从 RateLimitInterface 到漏桶算法与 429 响应 Yii后端Web框架上一篇React Live Hook使用指南在实时编辑中优雅使用React Hooks下一篇如何快速上手InfoSpider5分钟掌握你的数据管理神器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考