ServiceStack.Redis实现Redis缓存的速率限制
2017-09-07 16:24
387 查看
Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Ntong.RL; namespace Ntong.RL.Test { class Program { static void Main(string[] args) { Limiter RateLimiter = new Limiter(); for (int i = 0; i < 25; i++) { try { //do stuff RateLimiter.CheckLimit("GetMyItems"); Console.WriteLine("调用 完成"); } catch (Exception exc) { Console.WriteLine(exc.Message); } } Console.ReadLine(); } } }
App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="RL.RedisHost" value="127.0.0.1"/> <add key="RL.RedisPort" value="6379"/> <add key="RL.PerSecondRateLimit" value="10"/> <add key="RL.PerMinuteRateLimit" value="20"/> <add key="RL.PerHourRateLimit" value="50"/> </appSettings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> </startup> </configuration>
Limiter.cs
using System; using RC.RateLimit.Common; using ServiceStack.Redis; namespace Ntong.RL { public class Limiter { string redisHost = Config.RedisHost; int redisPort = Config.RedisPort; int perSecondLimit = Config.PerSecondRateLimit; int perMinuteLimit = Config.PerMinuteRateLimit; int perHourLimit = Config.PerHourRateLimit; public RedisClient redisCl; public Limiter() { redisCl = new RedisClient(redisHost, redisPort,"123456"); } public void CheckLimit(string key) { try { PerSecondLimiter(redisCl, key, perSecondLimit); PerMinuteLimiter(redisCl, key, perMinuteLimit); PerHourLimiter(redisCl, key, perHourLimit); } catch (ServiceStack.Redis.RedisException ex) { throw ex; } } public void PerSecondLimiter(RedisClient client, string key, int limit) { key += ":Second"; //Redis Llen 命令用于返回列表的长度。 //如果列表 key 不存在,则 key 被解释为一个空列表,返回 0 。 //如果 key 不是列表类型,返回一个错误。 long rqs = client.LLen(key); if (rqs <= limit) { //LPush 命令将一个或多个值插入到列表头部。 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。 当 key 存在但不是列表类型时,返回一个错误。 //注意:在Redis 2.4版本以前的 LPUSH 命令,都只接受单个 value 值。 client.LPush(key, BitConverter.GetBytes(DateTime.Now.Ticks)); //DateTime.Now.Ticks 是指从DateTime.MinValue之后过了多少时间,10000000为一秒,保存在long类型的变量里,可以将它传到datetime的构造函数内转成时间类型。 } else { //LIndex 命令用于通过索引获取列表中的元素。你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 DateTime time = new DateTime(BitConverter.ToInt64(client.LIndex(key, -1),0)); if (DateTime.Now - time < new TimeSpan(0, 0, 1)) //指定hours, minutes,和seconds转换为个时钟周期,并且值初始化此实例。 { throw new RedisException("超过每秒速率限制."); } else { client.LPush(key, BitConverter.GetBytes(DateTime.Now.Ticks)); } } client.LTrim(key, 0, limit); } public void PerMinuteLimiter(RedisClient client, string key, int limit) { key += ":Minute"; long rqs = client.LLen(key); if (rqs <= limit) { client.LPush(key, BitConverter.GetBytes(DateTime.Now.Ticks)); } else { DateTime time = new DateTime(BitConverter.ToInt64(client.LIndex(key, -1), 0)); if (DateTime.Now - time < new TimeSpan(0, 1, 0)) { throw new RedisException("超过每分钟速率限制."); } else { client.LPush(key, BitConverter.GetBytes(DateTime.Now.Ticks)); } } client.LTrim(key, 0, limit); } public void PerHourLimiter(RedisClient client, string key, int limit) { key += ":Hour"; long rqs = client.LLen(key); if (rqs <= limit) { client.LPush(key, BitConverter.GetBytes(DateTime.Now.Ticks)); } else { DateTime time = new DateTime(BitConverter.ToInt64(client.LIndex(key, -1),0)); if (DateTime.Now - time < new TimeSpan(1, 0, 0)) { throw new RedisException("超出每小时速率限制."); } else { client.LPush(key, BitConverter.GetBytes(DateTime.Now.Ticks)); } } client.LTrim(key, 0, limit); } } }
Config.cs
using System; using System.Data; using static System.Int32; namespace Ntong.RL.Common { public class Config { public static string RedisHost => ReadConfiguration("RateLimit.RedisHost", ""); public static int RedisPort => Parse(ReadConfiguration("RateLimit.RedisPort", "")); public static int PerSecondRateLimit => Parse(ReadConfiguration("RateLimit.PerSecondRateLimit", "")); public static int PerMinuteRateLimit => Parse(ReadConfiguration("RateLimit.PerMinuteRateLimit", "")); public static int PerHourRateLimit => Parse(ReadConfiguration("RateLimit.PerHourRateLimit", "")); public static string ReadConfiguration(string key, string defaultValue = null) { var keyVal = System.Configuration.ConfigurationManager.AppSettings[key]; return !string.Equals(keyVal, null, StringComparison.Ordinal) ? keyVal : defaultValue; } } }
运行结果如图:
相关文章推荐
- "ServiceStack.Redis.RedisNativeClient”的方法“get_Db”没有实现。
- 使用ServiceStack.Redis实现Redis数据读写
- ServiceStack.Redis.RedisNativeClient的方法“get_Db”没有实现。
- MVC 4中使用ServiceStack.Redis实现Redis队列【错误日志并发处理】
- Redis分布式锁(ServiceStack.Redis实现)
- 在Redis数据库中实现分布式速率限制的方法
- C# servicestack.redis 互通 java jedis
- 深入理解Spring Redis的使用 (六)、用Spring Aop 实现注解Dao层的自动Spring Redis缓存
- C# 基于StackExchange.Redis.dll利用Redis实现分布式Session
- .NET平台下Redis使用(三)【ServiceStack.Redis学习】
- .Net使用Redis详解之ServiceStack.Redis
- ServiceStack.Redis之IRedisTypedClient<第四篇>
- ServiceStack.Redis常用操作 - 事务、并发锁
- 图文并茂超详细搭建redis缓存服务器(nginx+tomcat+redis+mysql实现session会话共享)
- ServiceStack.Redis 使用
- Redis缓存 ava-Jedis操作Redis,基本操作以及 实现对象保存
- Redis:ServiceStack.Redis之IRedisClient
- 使用ServiceStackRedis链接Redis简介
- Service-stack.redis 使用PooledRedisClientManager 速度慢的原因之一