接口限流预案
一、限流前提
限制资源使用速率,在互联网中一般是:
限制请求总量(秒杀)或某段时间内请求总量(攻击/服务资源有限)
-
访问耗时
接口响应速度时间 描述 <500ms 快 >1.5s 慢(优化) >3s -
访问频次
名词 含义 QPS 每秒查询 TPS 每秒事务 RT 响应时间 PV 一次刷新或一次请求 并发数 系统同时能处理的请求数量 吞吐量 单个request 对CPU消耗越高,外部系统接口、IO速度越慢,系统吞吐能力越低,反之越高
公式:按二八定律来看,如果每天 80% 的访问集中在 20% 的时间里,这 20% 时间就叫做峰值时间。
- QPS(TPS)= 并发数/平均响应时间
- 并发数 = QPS*平均响应时间
- ( 总PV数
*
80% ) / ( 每天秒数*
20% ) = 峰值时间每秒请求数(QPS) - 峰值时间每秒QPS / 单台机器的QPS = 需要的机器
-
实施方法
- 先通过JMeter测出接口的 QPS
- 根据接口请求数统计算出 峰值QPS
峰值QPS>QPS 可能就需要限流
二、限流方式
-
接口内部限制线程数
private readonly static Semaphore _semaphore = new Semaphore(4, 8); try { _semaphore.WaitOne(); // Do Something } finally { _semaphore.Release(); }
这种只是限制并发的线程数,外部请求是处于等待状态,最终都会返回,除非客户端超时处理。
-
IP同源限流
借助AspNetCoreRateLimit中间件实现IP同源限流,先安装中间件
Install-Package AspNetCoreRateLimit Install-Package Microsoft.Extensions.Caching.Redis // Redis分布式缓存
services.AddDistributedRedisCache(options => { options.Configuration = "127.0.0.1:6379,password=123456,connectTimeout=5000,syncTimeout=10000"; options.InstanceName = "WebRatelimit"; }); //从appsettings.json获取相应配置 services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting")); //注入计数器和规则存储 services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore, DistributedCacheRateLimitCounterStore>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); //配置(计数器密钥生成器) services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>(); //启用限流,需在UseMvc前面 app.UseIpRateLimiting();
-
Nginx限流
-
限制访问频率
Nginx中使用ngx_http_limit_req_module模块来限制的访问频率
http { limit_req_zone $binary_remote_addr zone=myLimit:10m rate=5r/s; } server{ location / { limit_req zone=myLimit burst=5 nodelay; rewrite / http://www.xxx.com permanent; } }
上面binary_remote_addr就是key,表示基于客户端ip(remote_addr)进行限流,binary_表示压缩内存占用量。定义了一个大小为10M,名称为myLimit的内存区,用于存储IP地址访问信息。rate设置IP访问频率,rate=5r/s表示每秒只能处理每个IP地址的5个请求。Nginx限流是按照毫秒级为单位的,也就是说1秒处理5个请求会变成每200ms只处理一个请求。如果200ms内已经处理完1个请求,但是还是有有新的请求到达,这时候Nginx就会拒绝处理该请求。burst=5 nodelay,如果没有添加nodelay参数,则可以理解为预先在内存中占用了5个请求的位置,如果有5个突发请求就会按照200ms去依次处理请求,也就是1s内把5个请求全部处理完毕。如果1s内有新的请求到达也不会立即进行处理,因为紧急程度更低。这样实际上就会将额外的5个突发请求以200ms/个去依次处理,保证了处理速率的稳定,所以在处理突发流量的时候也一样可以正常处理。如果添加了nodelay参数则表示要立即处理这5个突发请求。
-
限制并发连接数
Nginx中的ngx_http_limit_conn_module模块提供了限制并发连接数的功能
http { limit_conn_zone $binary_remote_addr zone=myip:10m; limit_conn_zone $server_name zone=myServerName:10m; } server{ location / { limit_conn myip 10; limit_conn myServerName 100; rewrite / http://www.xxx.com permanent; } }
上面配置了单个IP同时并发连接数最多只能10个连接,并且设置了整个虚拟服务器同时最大并发数最多只能100个链接。当然,只有当请求的header被服务器处理后,虚拟服务器的连接数才会计数。刚才有提到过Nginx是基于漏桶算法原理实现的,实际上限流一般都是基于漏桶算法和令牌桶算法实现的。
-
-
RabbitMq限流/消峰
如秒杀场景,有50000份,根据RabbitMq限制接受6000/8000请求,其他拒绝。
三、实施
-
测试监听限流配置(11-10)
通过监听配置文件,限制接口频次,不用重启应用
-
找出需要限流的接口(11-11)
- 统计访问量前十接口
- 统计响应慢前十接口
-
测出合适限流频次(11-12)
灰度环境测试这些接口的吞吐量,然后设定限流频次