您的位置:首页 > 数据库 > Redis

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;
}
}
}


运行结果如图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: