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
{
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";
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, 0, 1))
{
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;
}
}
}
运行结果如图: