AppRateLimiter.Redis
1.0.1
dotnet add package AppRateLimiter.Redis --version 1.0.1
NuGet\Install-Package AppRateLimiter.Redis -Version 1.0.1
<PackageReference Include="AppRateLimiter.Redis" Version="1.0.1" />
<PackageVersion Include="AppRateLimiter.Redis" Version="1.0.1" />
<PackageReference Include="AppRateLimiter.Redis" />
paket add AppRateLimiter.Redis --version 1.0.1
#r "nuget: AppRateLimiter.Redis, 1.0.1"
#:package AppRateLimiter.Redis@1.0.1
#addin nuget:?package=AppRateLimiter.Redis&version=1.0.1
#tool nuget:?package=AppRateLimiter.Redis&version=1.0.1
AppRateLimiter.Redis
Redis-backed distributed store for AppRateLimiter.
Use this when you run more than one instance of your app (for example several Kubernetes or EKS pods). The default in-memory store counts requests per process, so with N replicas the effective limit becomes limit x N, and a client load balanced across pods can slip past any single pod's counter. This package keeps one shared counter in Redis so the limit holds globally, no matter which instance serves each request.
Install
dotnet add package AppRateLimiter.Redis
This package depends on AppRateLimiter, so the core middleware comes with it.
Usage
Register the Redis store instead of AddAppRateLimiter(). Everything else (the middleware, the IP and claim rules) works exactly as documented in the core package.
// Connect with a configuration string:
builder.Services.AddRedisRateLimiter("my-redis:6379");
// Optionally namespace the keys (defaults to "rl:"):
builder.Services.AddRedisRateLimiter("my-redis:6379", keyPrefix: "rl:prod:");
If you already manage your own connection, pass an existing IConnectionMultiplexer and the store will reuse it:
var mux = ConnectionMultiplexer.Connect("my-redis:6379");
builder.Services.AddRedisRateLimiter(mux, keyPrefix: "rl:prod:");
Then place the middleware in the pipeline the same way as with the in-memory store:
var app = builder.Build();
// IP limiting before authentication.
app.UseRateLimiting(RateLimitRules.ByIp(permitLimit: 100, window: TimeSpan.FromMinutes(1)));
app.UseAuthentication();
app.UseAuthorization();
// Claim limiting after authentication.
app.UseRateLimiting(RateLimitRules.ByClaim("sub", permitLimit: 1000, window: TimeSpan.FromMinutes(1)));
app.Run();
How it stays correct and fast
- Race free across pods. The whole sliding window read modify write runs inside a single Lua script, which Redis executes atomically. Concurrent requests from any number of instances cannot race, so there is no over admission.
- One round trip per check. The script is cached server side and called via EVALSHA, so each decision is a single pipelined round trip on the shared multiplexer, typically sub millisecond inside the same VPC or AZ. The store is fully async and never blocks thread pool threads.
- No pod clock skew. Time comes from the Redis server clock (via
TIME), not from each pod's clock. - Bounded memory. Each bucket is given a TTL of twice the window (the sliding window counter only needs the current and previous window), so idle keys expire on their own with no manual cleanup.
Securing Redis in production
The rate limit keys hold client IPs and claim values (such as sub), so treat the Redis instance as sensitive infrastructure:
Keep it private. Never expose Redis to the public internet. Put it in a private subnet and allow inbound
6379only from the app's security group. On EKS, prefer a managed endpoint (such as ElastiCache or MemoryDB) reachable only from the cluster. Leaveprotected-modeon.Require authentication with least privilege. Use a Redis ACL user limited to the commands this store needs:
EVAL,EVALSHA,SCRIPT,HMGET,HSET,PEXPIRE,TIME,PING.ACL SETUSER ratelimiter on >REPLACE_WITH_STRONG_SECRET ~rl:* +eval +evalsha +script +hmget +hset +pexpire +time +pingEncrypt in transit. Enable
ssl=truewith a real hostname, and turn on in transit and at rest encryption on managed Redis.Never hardcode the connection string. Load it from a secret (a Kubernetes
Secretor AWS Secrets Manager), not from source:builder.Services.AddRedisRateLimiter( builder.Configuration.GetConnectionString("Redis")!, keyPrefix: "rl:prod:");A secured connection string looks like:
my-redis.internal:6380,ssl=true,user=ratelimiter,password=<secret>,abortConnect=falseNamespace the keyspace. Use a distinct
keyPrefixper app and environment so multiple services can safely share one cluster while their ACL scope (~rl:*) stays contained.
Fails closed
If Redis is unreachable the request errors rather than silently skipping the limit, so an outage cannot be used to bypass rate limiting.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- AppRateLimiter (>= 1.0.0)
- StackExchange.Redis (>= 2.8.16)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on AppRateLimiter.Redis:
| Package | Downloads |
|---|---|
|
AppRateLimiter.Web
Classic ASP.NET (System.Web) integration for AppRateLimiter: an async IHttpModule that applies the same IP and claim rate-limit rules to WebForms / MVC 5 / Web API 2 apps on .NET Framework. Reuses the core store (in-memory or distributed Redis). |
GitHub repositories
This package is not used by any popular GitHub repositories.