Asp.net mvc 3 ASP.NET MVC 3中的每日通话速率限制?

Asp.net mvc 3 ASP.NET MVC 3中的每日通话速率限制?,asp.net-mvc-3,rate-limiting,Asp.net Mvc 3,Rate Limiting,我见过Jarrod Dixon的解决方案()实现每秒呼叫速率限制。我现在正试图找出如何为每天N个电话构建一个类似的过滤器 我正在构建一个开发者API,免费帐户每天可以获得约100个调用,付费帐户可以获得更高的速率限制。在MVC 3中,每天通话速率限制的最佳方式是什么?我认为内存中的结构在这里不够,因为您需要测量很长的持续时间。在这种情况下,IIS回收将有问题。因此,我建议在数据库中记录用户对资源的访问,并且在过去24小时内只允许计数100 另一方面,我们实现了一个漏桶限制器(对于故障相对不重要的

我见过Jarrod Dixon的解决方案()实现每秒呼叫速率限制。我现在正试图找出如何为每天N个电话构建一个类似的过滤器


我正在构建一个开发者API,免费帐户每天可以获得约100个调用,付费帐户可以获得更高的速率限制。在MVC 3中,每天通话速率限制的最佳方式是什么?

我认为内存中的结构在这里不够,因为您需要测量很长的持续时间。在这种情况下,IIS回收将有问题。因此,我建议在数据库中记录用户对资源的访问,并且在过去24小时内只允许计数100

另一方面,我们实现了一个漏桶限制器(对于故障相对不重要的短期限制更方便)。使用.NET 4并发集合可能会改进此实现中的蛮力锁定:

public class RateLimiter
{
    private readonly double numItems;
    private readonly double ratePerSecond;
    private readonly Dictionary<object, RateInfo> rateTable = 
        new Dictionary<object, RateInfo>();
    private readonly object rateTableLock = new object();
    private readonly double timePeriod;

    public RateLimiter(double numItems, double timePeriod)
    {
        this.timePeriod = timePeriod;
        this.numItems = numItems;
        ratePerSecond = numItems / timePeriod;
    }

    public double Count
    {
        get
        {
            return numItems;
        }
    }

    public double Per
    {
        get
        {
            return timePeriod;
        }
    }

    public bool IsPermitted(object key)
    {
        RateInfo rateInfo;
        var permitted = true;
        var now = DateTime.UtcNow;
        lock (rateTableLock)
        {
            var expiredKeys = 
                rateTable
                .Where(kvp => 
                    (now - kvp.Value.LastCheckTime) 
                    > TimeSpan.FromSeconds(timePeriod))
                .Select(k => k.Key)
                .ToArray();
            foreach (var expiredKey in expiredKeys)
            {
                rateTable.Remove(expiredKey);
            }
            var dataExists = rateTable.TryGetValue(key,
                                                   out rateInfo);
            if (dataExists)
            {
                var timePassedSeconds = (now - rateInfo.LastCheckTime).TotalSeconds;
                var newAllowance = 
                     Math.Min(
                         rateInfo.Allowance 
                         + timePassedSeconds 
                         * ratePerSecond,
                         numItems);
                if (newAllowance < 1d)
                {
                    permitted = false;
                }
                else
                {
                    newAllowance -= 1d;
                }
                rateTable[key] = new RateInfo(now,
                                              newAllowance);
            }
            else
            {
                rateTable.Add(key,
                              new RateInfo(now,
                                           numItems - 1d));
            }

        }
        return permitted;
    }

    public void Reset(object key)
    {
        lock (rateTableLock)
        {
            rateTable.Remove(key);
        }
    }

    private struct RateInfo
    {
        private readonly double allowance;
        private readonly DateTime lastCheckTime;

        public RateInfo(DateTime lastCheckTime, double allowance)
        {
            this.lastCheckTime = lastCheckTime;
            this.allowance = allowance;
        }

        public DateTime LastCheckTime
        {
            get
            {
                return lastCheckTime;
            }
        }

        public double Allowance
        {
            get
            {
                return allowance;
            }
        }
    }

}
公共类费率限制器
{
私有只读双numItems;
私人只读双速率每秒;
专用只读字典速率表=
新字典();
私有只读对象rateTableLock=新对象();
专用只读双时间段;
公共费率限制器(双numimes,双时段)
{
this.timePeriod=时间段;
this.numItems=numItems;
ratePerSecond=numItems/时间段;
}
公众重复计数
{
得到
{
返回numItems;
}
}
公共双人房
{
得到
{
返回时间段;
}
}
公共布尔值允许(对象键)
{
RateInfo RateInfo;
允许的var=真;
var now=DateTime.UtcNow;
锁(rateTableLock)
{
var expiredKeys=
费率表
.其中(kvp=>
(现在-kvp.Value.LastCheckTime)
>TimeSpan.FromSeconds(时间段))
.选择(k=>k.Key)
.ToArray();
foreach(expiredKey中的var expiredKey)
{
rateTable.Remove(expiredKey);
}
var dataExists=rateTable.TryGetValue(键,
运输署(运输署),;
如果(数据存在)
{
var timePassedSeconds=(now-rateInfo.LastCheckTime).TotalSeconds;
var新备抵=
数学,敏(
差饷津贴
+时间流逝秒
*速率每秒,
努米特斯);
如果(新公差<1d)
{
允许=错误;
}
其他的
{
新余量-=1d;
}
rateTable[key]=新的RateInfo(现在,
新津贴);
}
其他的
{
比率表。添加(键,
新费率信息(现在,
numItems-1d);
}
}
准许返回;
}
公共无效重置(对象键)
{
锁(rateTableLock)
{
删除(键);
}
}
私有结构速率信息
{
私人只读双重津贴;
私有只读日期时间lastCheckTime;
公共费率信息(DateTime lastCheckTime,双折让)
{
this.lastCheckTime=lastCheckTime;
这个。津贴=津贴;
}
公共日期时间LastCheckTime
{
得到
{
返回上次检查时间;
}
}
公共双倍津贴
{
得到
{
返回津贴;
}
}
}
}

我强烈建议不要在lock语句之外声明(并立即初始化
)。虽然这不太可能发生在您的应用程序中,但是如果调用线程在
lock
语句中被阻塞很长时间,您可能会得到与
IsPermitted
调用不同的结果。