目 录CONTENT

文章目录

Nginx限流原理及实现

Josue
2022-03-28 / 0 评论 / 0 点赞 / 249 阅读 / 3,693 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-03-28,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1、简介

  • 限流两个算法漏桶(LeakyBucket)算法和令牌桶算法(TokenBucket)

  • nginx接入层限流可以使用Nginx自带的两个模块:

    漏桶算法实现的请求限流模块ngx_http_1imit_req_module控制速率。

    • #limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=l0r/s
    • limit_req zone=contentRateLimit burst=50 nodelay

    连接数限流模块ngx_http_limit_conn_module控制并发数

    • limit_conn_zone
    • limit_conn
  • SpringGateWay网关限流,使用的令牌桶算法。SpringCloudGateWay默认使用redis的RateLimter限流算法来实现。

2、限流算法(漏桶算法和令牌桶算法)

2.1、漏桶(LeakyBucket)算法

请求大于接口响应速率直接拒绝,接口响应速率匀速

思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率。示意图如下:

image-20220328144219490

2.2、令牌桶算法(TokenBucket)

和Leaky Bucket效果一样但方向相反的算法,更加容易理解。随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了,新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务。

image-20220328144742677

2.3、两者区别

在于”漏桶算法“能够强行限制数据的传输速率,而“令牌桶算法“在能够限制数据的平均传输速率外,还允许某种程度的突发传输。在令牌桶算法“中,只要令牌桶中存在令牌,那么就允许突发地传输数据直到达到用户配置的门限,所以它适合于具有突发特性的流量。

3、Nginx控制速率配置

3.1、配置一个最基本的空桶

修改/usr/local/openresty/nginx/conf/nginx.conf

worker_processes  auto;
events {
    worker_connections  1024;
}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    #cache
    lua_shared_dict dis_cache 128m;
    #限流设置
    limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=l0r/s
 	#根据ip地址来限制,存储内存大小10M
 	
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
    #gzip  on;
    server{
        listen	80;
        server_name localhost;
        location /update_content {
            content_by_lua_file /root/lua/update_content.lua;
        }
        location /read_content{
            #使用限流配置
            limit_req zone=contentRateLimit;

            content_by_lua_file /root/lua/read_content.lua;
    	} 
    }
}

# 1imit_req_zone表示用的是ngx_http_1imit_req_module
# $binary_remote_addr是一种key,表示基于remote_addr(客户端IP)来做限流,binary_ 的目的是压缩内存占用量。
# zone:定义共享内存区来存储访问信息,contentRateLimit:10m表示一个大小为10M,名字contentRateLimit的内存区域。1M能存储16000 IP地址的访问信息,10M可以存储16W IP地址访问信息。
# rate用于设置最大访问速率,rate=10r/s表示每秒最多处理10个请求。Nginx实际上以毫秒为粒度来跟踪请求信息,因此10r/s实际上是限制:每100毫秒处理一个请求。这意味着,自上一个请求处理完后,若后续100毫秒内又有请求到达,将拒绝处理该请求。

#所以如果10次请求同时到达,那么只有一个请求能够得到执行,其它的,都会被拒绝。
#这不太友好,大部分业务场景下我们希望这1个请求都能得到执行。(问题)
#因此,可以配置burst(解决)

3.2、配置burst

 server{
        listen	80;
        server_name localhost;
        location /update_content {
            content_by_lua_file /root/lua/update_content.lua;
            }
        location /read_content{
            #使用限流配置
            limit_req zone=contentRateLimit burst=50;

            content_by_lua_file /root/lua/read_content.lua;
		} 
}

#若同时有50个请求到达,Nginx会处理第一个请求,剩余49个请求将放入队列,然后每隔100ms从队列中获取一个请求进行处理。若请求数大于50将拒绝处理多余的请求,直接返回503.

#假设burst=50,rate依然为10r/s.如果有10次请求同时到达,它们会依次执行,每100ms执行1个,第50个请求却需要等待50*100ms即5s,这么长的处理时间自然难以接受。(问题)
#国此,burst往往结合nodelay一起使用(解决)

3.3、配置nodelay

 server{
        listen	80;
        server_name localhost;
        location /update_content {
            content_by_lua_file /root/lua/update_content.lua;
            }
        location /read_content{
            #使用限流配置
            limit_req zone=contentRateLimit burst=50 nodelay;

            content_by_lua_file /root/lua/read_content.lua;
		} 
}
#平均每秒允许不超过10个请求,突发不超过50个请求,并且处理突发50个请求的时候,没有延退,等到完成之后,按照正常的速率处理。

4、Nginx控制并发量(连接数)

ngx_http_limit_conn_module提供了限制连接数的能力。主要是利用limit_conn_zonelimit_conn两个指令。

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    #cache
    lua_shared_dict dis_cache 128m;
    #限流设置
    limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=l0r/s
 	#根据ip地址来限制,存储内存大小10M
 	
 	#【这里】
 	limit_conn_zone $binary_remote_addr zone=addr:10m;
 	
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
    #gzip  on;
    server{
        listen	80;
        server_name localhost;
        #【这里】所有一brand开始的请求,访问ip的微服务
         location /brand{
            #使用限流配置
           limit_conn addr 2;
           proxy_pass http://xxx.xx.xx.xx:xxx
    	} 
    	
        location /update_content {
            content_by_lua_file /root/lua/update_content.lua;
        }    
        location /read_content{
            #使用限流配置
            limit_req zone=contentRateLimit;
            content_by_lua_file /root/lua/read_content.lua;
    	} 
    }
}

#limit_conn_zone $binary_remote_addr zone=addr:10m;
1imit_conn_zone:是针对每个IP定义一个存储session状态的容器.这个示例中定义了一个10m的容器,按照32bytes/session,可以处理320000个session

# 1imit_conn addr 2;
“addr”与上面的对应,也可以自定义命名,表示同一个地址最大同时连接数数2次,超过这个数字的请求将被返回”Serviceunavailable”(593)代码。
0

评论区