nginx限流配置
-
nginx限流算法
- 令牌桶算法
- 令牌以固定速率产生,并缓存到令牌桶中;
- 令牌桶放满时,多余的令牌被丢弃;
- 请求要消耗等比例的令牌才能被处理;
- 令牌不够时,请求被缓存
- 漏桶算法
- 水(请求)从上方倒入水桶,从水桶下方流出(被处理);
- 来不及流出的水存在水桶中(缓冲),以固定速率流出;
- 水桶满后水溢出(丢弃)。
- 这个算法的核心是:缓存请求、匀速处理、多余的请求直接丢弃。
- 相比漏桶算法,令牌桶算法不同之处在于它不但有一只“桶”,还有个队列,这个桶是用来存放令牌的,队列才是用来存放请求的。
- 两者区别:
从作用上来说,漏桶和令牌桶算法最明显的区别就是是否允许突发流量(burst)的处理,漏桶算法能够强行限制数据的实时传输(处理)速率,对突发流量不做额外处理;而令牌桶算法能够在限制数据的平均传输速率的同时允许某种程度的突发传输。 - 拿进火车站的示例来讲:
- 令牌桶算法是出火车票的速度是固定的,所有人只有拿到票后才可以进行候车大厅。候车大厅人满了,直接拒绝。(出票速度是一定的,如1分钟出10张票。旅客上车的速度不进行限制)
漏桶算法是进行候车大厅不需要票,旅客上车的速度是一定。候车大厅人满了,直接拒绝。
- 令牌桶算法是出火车票的速度是固定的,所有人只有拿到票后才可以进行候车大厅。候车大厅人满了,直接拒绝。(出票速度是一定的,如1分钟出10张票。旅客上车的速度不进行限制)
- 令牌桶算法
-
实战配置
- 限制访问速率
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s; server { location / { limit_req zone=mylimit; } }
我们使用单个IP在10ms内发并发送了6个请求,只有1个成功,剩下的5个都被拒绝。我们设置的速度是2r/s,为什么只有1个成功呢,是不是Nginx限制错了?当然不是,是因为Nginx的限流统计是基于毫秒的,我们设置的速度是2r/s,转换一下就是500ms内单个IP只允许通过1个请求,从501ms开始才允许通过第二个请求。
2. burst缓存处理limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s; server { location / { limit_req zone=mylimit burst=4; } }
Nginx按照毫秒级精度统计,超出限制的请求直接拒绝。这在实际场景中未免过于苛刻,真实网络环境中请求到来不是匀速的,很可能有请求“突发”的情况,也就是“一股子一股子”的。Nginx考虑到了这种情况,可以通过burst关键字开启对突发请求的缓存处理,而不是直接拒绝。
但是请注意:burst的作用是让多余的请求可以先放到队列里,慢慢处理。如果不加nodelay参数,队列里的请求不会立即处理,而是按照rate设置的速度,以毫秒级精确的速度慢慢处理。
3. nodelay降低排队时间
实例二中我们看到,通过设置burst参数,我们可以允许Nginx缓存处理一定程度的突发,多余的请求可以先放到队列里,慢慢处理,这起到了平滑流量的作用。但是如果队列设置的比较大,请求排队的时间就会比较长,用户角度看来就是RT变长了,这对用户很不友好。有什么解决办法呢?nodelay参数允许请求在排队的时候就立即被处理,也就是说只要请求能够进入burst队列,就会立即被后台worker处理,请注意,这意味着burst设置了nodelay时,系统瞬间的QPS可能会超过rate设置的阈值。nodelay参数要跟burst一起使用才有作用。延续实例二的配置,我们加入nodelay选项:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s; server { location / { limit_req zone=mylimit burst=4 nodelay; } }