阅读目录:

  1. 介绍
  2. 基于IP全局限流
  3. 基于IP的端点限流
  4. 基于IP和客户端key的端点限流
  5. IP和客户端key的白名单
  6. IP和客户端key自定义限制频率
  7. 端点自定义限制频率
  8. 关于被拒请求的计数器
  9. 在web.config或app.config中定义限制策略
  10. 获取API的客户端key
  11. 存储限流的数据
  12. 运行期间更新限制频率
  13. 限流的请求日志
  14. 用ThrottlingFilter、EnableThrottlingAttribute特性配置限制频率
  15. 关于ThrottlingMiddleware限制频率

介绍

为了防止网站意外暴增的流量比如活动、秒杀、攻击等,导致整个系统瘫痪,在前后端接口服务处进行流量限制是非常有必要的。本篇主要介绍下Net限流框架WebApiThrottle的使用。

WebApiThrottle是一个专门为webApi限制请求频率而设计的,支持寄宿OWIN上的中间件的限制过滤。服务端接口可以基于客户端请求IP地址、客户端请求key、及请求路由去限制webapi接口的访问频率。

使用nuget命令安装WebApiThrottle:

PM> Install-Package WebApiThrottle

Nuget地址:

https://www.nuget.org/packages/WebApiThrottle/

WebApiThrottle支持自定义配置各种限流策略。可以根据不同场景配置多个不同的限制,比如授权某个IP每秒、每分钟、每小时、每天、每周的最大调用次数。 这些限制策略可以配置在所有请求上,也可以单独给每个API接口去配置。

基于IP全局限流

下面的代码是限制来自同IP请求的最大次数。如果在一分钟内,同样IP的客户端分别调用api/values和api/values/1两个接口, 那么调用api/values/1的请求会被拒绝掉。

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: , perHour: , perDay: , perWeek: )
{
IpThrottling = true
},
Repository = new CacheRepository()
});
}
}

如果是自寄宿在Owin上的WebApi,上面的CacheRepository必须替换成运行时的MemoryCacheRepository类,因为CacheRepository使用的是Asp.net版本的缓存。

public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration(); //Register throttling handler
config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: , perHour: , perDay: , perWeek: )
{
IpThrottling = true
},
Repository = new MemoryCacheRepository()
}); appBuilder.UseWebApi(config);
}
}

基于IP的端点限流

上面的api/values限流配置会对整个api/values开头的API限流,同一秒内、同一ip访问api/values后,所有后续访问api/values/xxx的请求都会被拒绝掉。 如果配置了端点限流,同一秒内你也访问api/values/1了,请求将不会被拒绝,因为它们走的是不同的路由。

config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: )
{
IpThrottling = true,
EndpointThrottling = true
},
Repository = new CacheRepository()
});

基于IP和客户端key的端点限流

如果同一个ip的客户端,在同一秒内,调用了2次api/values,其最后一次的调用将会被拒绝掉。

如果想接口通过唯一key去识别限制客户端,忽略客户端的ip地址限制,应该配置IpThrottling为false。

config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: )
{
IpThrottling = true,
ClientThrottling = true,
EndpointThrottling = true
},
Repository = new CacheRepository()
});

IP和客户端key的白名单

如果请求是从一个白名单中的IP或客户端key发起的,那么限流策略将不会生效,这个请求的所有信息也不会被存储。 其IP白名单列表支持IP v4和v6的范围配置,比如"192.168.0.0/24", "fe80::/10" 和 "192.168.0.0-192.168.0.255",关于IP范围的更多信息请查看https://github.com/jsakamoto/ipaddressrange

config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: )
{
IpThrottling = true,
IpWhitelist = new List<string> { "::1", "192.168.0.0/24" }, ClientThrottling = true,
ClientWhitelist = new List<string> { "admin-key" }
},
Repository = new CacheRepository()
});

IP和客户端key自定义限制频率

你可以自定义基于ip或客户端key的请求频率限制,这些限制会重写WebApiThrottle的默认配置。

需要注意的是,这些自定义策略需要写到全局配置里才会生效,策略里可以单独给某个ip或某个key配置限流策略。

config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: , perHour: , perDay: )
{
IpThrottling = true,
IpRules = new Dictionary<string, RateLimits>
{
{ "192.168.1.1", new RateLimits { PerSecond = } },
{ "192.168.2.0/24", new RateLimits { PerMinute = , PerHour = *, PerDay = ** } }
}, ClientThrottling = true,
ClientRules = new Dictionary<string, RateLimits>
{
{ "api-client-key-1", new RateLimits { PerMinute = , PerHour = } },
{ "api-client-key-9", new RateLimits { PerDay = } }
}
},
Repository = new CacheRepository()
});

端点自定义限制频率

你也可以为明确的路由地址去自定义限制频率,这些限制配置会重写WebApiThrottle的默认配置。也可以通过相关联的路由地址去定义端点的限制规则,比如api/entry/1端点的请求仅仅是/entry/整个路由地址请求的一部分。 配置后,端点限制引擎会在请求的绝对URI中去搜索这个表达式(api/entry/1),如果这个表达式在请求路由策略中被找到,那么这个限制规则将会被应用。如果有两个或更多的限制规则匹配到同一个URL,更近一级的限制策略将会被应用。

config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: , perHour: )
{
IpThrottling = true,
ClientThrottling = true,
EndpointThrottling = true,
EndpointRules = new Dictionary<string, RateLimits>
{
{ "api/search", new RateLimits { PerSecond = , PerMinute = , PerHour = } }
}
},
Repository = new CacheRepository()
});

关于被拒请求的计数器

默认情况下,被拒绝的请求不会累加到WebApiThrottle的计数器里。 比如一个客户端在同一秒中请求了3次,而你配置的限制策略是每秒1次,那么分钟、小时、天的计数器只会记录第一次调用,因为第一次请求不会被拒绝。如果你想把被拒绝的请求也计算到其他的计数器里(分钟、小时、天),你可以设置StackBlockedRequests为true。

config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: )
{
IpThrottling = true,
ClientThrottling = true,
EndpointThrottling = true,
StackBlockedRequests = true
},
Repository = new CacheRepository()
});

在web.config或app.config中定义限制策略

在web.config或app.config中配置限制策略,通过ThrottlePolicy.FromStore加装配置项。

config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
Repository = new CacheRepository()
});

配置示例(policyType的值1代表ip、2代表clientkey、3代表端点)

<configuration>

  <configSections>
<section name="throttlePolicy"
type="WebApiThrottle.ThrottlePolicyConfiguration, WebApiThrottle" />
</configSections> <throttlePolicy limitPerSecond="1"
limitPerMinute="10"
limitPerHour="30"
limitPerDay="300"
limitPerWeek ="1500"
ipThrottling="true"
clientThrottling="true"
endpointThrottling="true">
<rules>
<!--Ip 规则-->
<add policyType="1" entry="::1/10"
limitPerSecond="2"
limitPerMinute="15"/>
<add policyType="1" entry="192.168.2.1"
limitPerMinute="12" />
<!--Client 规则-->
<add policyType="2" entry="api-client-key-1"
limitPerHour="60" />
<!--Endpoint 规则-->
<add policyType="3" entry="api/values"
limitPerDay="120" />
</rules>
<whitelists>
<!--Ip 白名单-->
<add policyType="1" entry="127.0.0.1" />
<add policyType="1" entry="192.168.0.0/24" />
<!--Client 白名单-->
<add policyType="2" entry="api-admin-key" />
</whitelists>
</throttlePolicy>
</configuration>

获取API的客户端key

默认情况下,WebApiThrottle的ThrottlingHandler(限流处理器)会从客户端请求head里通过Authorization-Token key取值。如果你的API key存储在不同的地方,你可以重写ThrottlingHandler.SetIndentity方法,指定你自己的取值策略。

public class CustomThrottlingHandler : ThrottlingHandler
{
protected override RequestIdentity SetIndentity(HttpRequestMessage request)
{
return new RequestIdentity()
{
ClientKey = request.Headers.Contains("Authorization-Key") ? request.Headers.GetValues("Authorization-Key").First() : "anon",
ClientIp = base.GetClientIp(request).ToString(),
Endpoint = request.RequestUri.AbsolutePath.ToLowerInvariant()
};
}
}

存储限流的数据

WebApiThrottle会在内存中存储所有的请求数据,寄宿在IIS里使用ASP.NET版本的cache、自寄宿在Owin上使用运行时版本的缓存MemoryCache。如果你想改变请求数据存储的策略,框架是支持redis、nosql、数据库存储的,这种情况下必须创建自己的存储引擎,可以通过实现IThrottleRepository接口完成。

public interface IThrottleRepository { bool Any(string id);

ThrottleCounter? FirstOrDefault(string id);

void Save(string id, ThrottleCounter throttleCounter, TimeSpan expirationTime);

void Remove(string id);

void Clear();
}

自从1.2版本后有IPolicyRepository的接口可以实现存储、获取限制策略对象,意味着可以持久化限流策略,同时也可以被用于在运行期间动态更新限制策略对象。

public interface IPolicyRepository
{
ThrottlePolicy FirstOrDefault(string id); void Remove(string id); void Save(string id, ThrottlePolicy policy);
}

运行期间更新限制频率

为了更新限制策略对象,并在运行时使用新的ThrottlingHandler对象,需要引入WebApiThrottle 1.2版本后支持的ThrottleManager.UpdatePolicy函数。

在启动时注册ThrottlingHandler对象,并在构造函数中传入PolicyCacheRepository ,如果你是通过Owin自寄宿的webapi,需要使用PolicyMemoryCacheRepository对象。

public static void Register(HttpConfiguration config)
{
//trace provider
var traceWriter = new SystemDiagnosticsTraceWriter()
{
IsVerbose = true
};
config.Services.Replace(typeof(ITraceWriter), traceWriter);
config.EnableSystemDiagnosticsTracing(); //添加限流处理者到Web API消息处理集合里
config.MessageHandlers.Add(new ThrottlingHandler(
policy: new ThrottlePolicy(perMinute: , perHour: , perDay: , perWeek: )
{
//启用ip限制策略
IpThrottling = true, //启用客户端key限制策略
ClientThrottling = true,
ClientRules = new Dictionary<string, RateLimits>
{
{ "api-client-key-1", new RateLimits { PerMinute = , PerHour = } },
{ "api-client-key-2", new RateLimits { PerDay = } }
}, //启用端点限制策略
EndpointThrottling = true
}, //如果是owin寄宿,替换成PolicyMemoryCacheRepository
policyRepository: new PolicyCacheRepository(), //如果是owin寄宿,替换成MemoryCacheRepository
repository: new CacheRepository(), logger: new TracingThrottleLogger(traceWriter)));
}

当你想更新限制策略对象时,可以在任何你的代码里调用静态方法ThrottleManager.UpdatePolicy去刷新内存中的策略数据。

public void UpdateRateLimits()
{
//初始化策略仓库
var policyRepository = new PolicyCacheRepository(); //从缓存中获取策略对象
var policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey()); //更新客户端限制频率
policy.ClientRules["api-client-key-1"] =
new RateLimits { PerMinute = , PerHour = }; //添加新的客户端限制频率
policy.ClientRules.Add("api-client-key-3",
new RateLimits { PerMinute = , PerHour = }); //应用策略更新
ThrottleManager.UpdatePolicy(policy, policyRepository); }

限流的请求日志

如果你想记录限流后的请求日志,可以实现IThrottleLogger接口,添加到ThrottlingHandler里。

public interface IThrottleLogger
{
void Log(ThrottleLogEntry entry);
}

实现ITraceWriter日志记录接口的例子

public class TracingThrottleLogger : IThrottleLogger
{
private readonly ITraceWriter traceWriter; public TracingThrottleLogger(ITraceWriter traceWriter)
{
this.traceWriter = traceWriter;
} public void Log(ThrottleLogEntry entry)
{
if (null != traceWriter)
{
traceWriter.Info(entry.Request, "WebApiThrottle",
"{0} Request {1} from {2} has been throttled (blocked), quota {3}/{4} exceeded by {5}",
entry.LogDate, entry.RequestId, entry.ClientIp, entry.RateLimit, entry.RateLimitPeriod, entry.TotalRequests);
}
}
}

用SystemDiagnosticsTraceWriter和ThrottlingHandler记录日志的使用例子:

var traceWriter = new SystemDiagnosticsTraceWriter()
{
IsVerbose = true
};
config.Services.Replace(typeof(ITraceWriter), traceWriter);
config.EnableSystemDiagnosticsTracing(); config.MessageHandlers.Add(new ThrottlingHandler()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: )
{
IpThrottling = true,
ClientThrottling = true,
EndpointThrottling = true
},
Repository = new CacheRepository(),
Logger = new TracingThrottleLogger(traceWriter)
});

用ThrottlingFilter、EnableThrottlingAttribute特性配置限制频率

EnableThrottling与ThrottlingHandler是一个二选一的策略配置方案,二者会做同样的事情,但ThrottlingHandler可以通过EnableThrottlingAttribute特性指定某个webapi的controllers和actions去自定义频率限制。需要注意的是,在webapi请求管道中,ThrottlingHandler是在controller前面执行,因此在你不需要ThrottlingFilter提供的功能时,可以用ThrottlingHandler去直接替代它。

设置ThrottlingFilter过滤器的步骤,跟ThrottlingHandler类似:

config.Filters.Add(new ThrottlingFilter()
{
Policy = new ThrottlePolicy(perSecond: , perMinute: ,
perHour: , perDay: , perWeek: )
{
//ip配置区域
IpThrottling = true,
IpRules = new Dictionary<string, RateLimits>
{
{ "::1/10", new RateLimits { PerSecond = } },
{ "192.168.2.1", new RateLimits { PerMinute = , PerHour = *, PerDay = ** } }
},
//添加127.0.0.1到白名单,本地地址不启用限流策略
IpWhitelist = new List<string> { "127.0.0.1", "192.168.0.0/24" }, //客户端配置区域,如果ip限制也是启动的,那么客户端限制策略会与ip限制策略组合使用。
ClientRules = new Dictionary<string, RateLimits>
{
{ "api-client-key-demo", new RateLimits { PerDay = } }
},
//白名单中的客户端key不会进行限流。
ClientWhitelist = new List<string> { "admin-key" }, //端点限制策略配置会从EnableThrottling特性中获取。
EndpointThrottling = true
}
});

使用特性开启限流并配置限制频率:

[EnableThrottling(PerSecond = )]
public class ValuesController : ApiController
{
[EnableThrottling(PerSecond = , PerMinute = , PerHour = )]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
} [DisableThrotting]
public string Get(int id)
{
return "value";
}
}

关于ThrottlingMiddleware限制频率

ThrottlingMiddleware是一个OWIN中间件部分,它的作用跟ThrottlingHandler一样。使用ThrottlingMiddleware 你可以在webapi作用域范围外配置限制策略,跟使用OAuth中间件或SignalR端点类似。

自寄宿配置例子:

public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
... //从app.config加载限流策略
appBuilder.Use(typeof(ThrottlingMiddleware),
ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
new PolicyMemoryCacheRepository(),
new MemoryCacheRepository(),
null); ...
}
}

IIS寄宿配置例子:

public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
... //从web.config加载限流策略
appBuilder.Use(typeof(ThrottlingMiddleware),
ThrottlePolicy.FromStore(new PolicyConfigurationProvider()),
new PolicyCacheRepository(),
new CacheRepository(),
null); ...
}
}

翻译了https://github.com/stefanprodan/WebApiThrottle的官方文档,希望对大家有所帮助。

WebApiThrottle限流框架使用手册的更多相关文章

  1. WebApiThrottle限流框架

    ASP.NET Web API Throttling handler is designed to control the rate of requests that clients can make ...

  2. webapi限流框架WebApiThrottle

    为了防止网站意外暴增的流量比如活动.秒杀.攻击等,导致整个系统瘫痪,在前后端接口服务处进行流量限制是非常有必要的.本篇主要介绍下Net限流框架WebApiThrottle的使用. WebApiThro ...

  3. 【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架

    Dnc.Api.Throttle    适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Thr ...

  4. 微服务组件--限流框架Spring Cloud Hystrix分析

    Hystrix的介绍 [1]Hystrix是springCloud的组件之一,Hystrix 可以让我们在分布式系统中对服务间的调用进行控制加入一些调用延迟或者依赖故障的容错机制. [2]Hystri ...

  5. 控制ASP.NET Web API 调用频率与限流

    ASP.NET MVC 实现 https://github.com/stefanprodan/MvcThrottle ASP.NET WEBAPI 实现 https://github.com/stef ...

  6. Spring Cloud alibaba网关 sentinel zuul 四 限流熔断

    spring cloud alibaba 集成了 他内部开源的 Sentinel 熔断限流框架 Sentinel 介绍 官方网址 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentine ...

  7. 简易RPC框架-客户端限流配置

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  8. Anno 框架 增加缓存、限流策略、事件总线、支持 thrift grpc 作为底层传输

    github 地址:https://github.com/duyanming/dymDemo dym 分布式开发框架 Demo 熔断 限流 事件总线(包括基于内存的.rabbitmq的) CQRS D ...

  9. 快速入门系列--WCF--06并发限流、可靠会话和队列服务

    这部分将介绍一些相对深入的知识点,包括通过并发限流来保证服务的可用性,通过可靠会话机制保证会话信息的可靠性,通过队列服务来解耦客户端和服务端,提高系统的可服务数量并可以起到削峰的作用,最后还会对之前的 ...

随机推荐

  1. GruntJS学习(转)

    GruntJS 是基于JavaScript的命令行构建工具,它可以帮助开发者们自动化重复性的工作.你可以把它看成是JavaScript下的Make或者Ant.它可以完成诸如精简.编译.单元测试.lin ...

  2. MySQL数据库1067 问题

    1.MySql1067错误解决方法 http://blog.csdn.net/mhmyqn/article/details/17043921   MySql 1045解决方法 my.ini  mysq ...

  3. D3中selection之使用

    1. 极为重要的reference: [1] How selections works. http://bost.ocks.org/mike/selection/ [2] Nested selecti ...

  4. Gym 100646 F Tanks a Lot RMQ

    Problem F: Tanks a Lot Imagine you have a car with a very large gas tank - large enough to hold what ...

  5. C#版 Winform界面 Socket编程 Client客户端

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  6. http错误代码含义中英文对照

    Http错误代码含义中文 概要当用户试图通过 HTTP 或文件传输协议 (FTP) 访问一台正在运行 Internet 信息服务 (IIS) 的服务器上的内容时,IIS 返回一个表示该请求的状态的数字 ...

  7. Ue4的容器(数据结构)

    之前都没注意,作为程序眼这些还是比较重要的 Engine\Source\Runtime\Core\Public\Containers\

  8. 数据泵Expdp和Impdp

    一.数据泵导入导出技术 1.结构 2.目录对象 二.EXPDP参数 1.attach 2.content 3.directory 4.dumpfile 5.estimate 6.estimate_on ...

  9. 关于PHP语言

    ------php语言与JavaScript的使用 方法是相似 <script type="text/javascript"> </script>--js与 ...

  10. HDU 2222  AC自动机模板题

    1.HDU 2222 2.题意:给出n个单词,一个字串,求有多少个单词在字串里出现了.注意给出的单词可能会重复,重复的不计. 3.总结:入门题.在查询这里还是不太懂. #include<bits ...