openststry(二)

 

 

access_by_lua_block

 

[root@centos7 conf]# ls /usr/local/openresty/lualib/
cjson.so  librestysignal.so  ngx  redis  resty  tablepool.lua
[root@centos7 conf]# mkdir -p /usr/local/openresty/lualib/untils
[root@centos7 conf]# 

 

[root@centos7 conf]# cat /usr/local/openresty/lualib/utils/limit_conn.lua
 

 

[root@centos7 conf]# cat /usr/local/openresty/lualib/utils/limit_conn.lua
-- utils/limit_conn.lua
local limit_conn = require("resty.limit.conn")

-- new 的第四个参数用于估算每个请求会维持多长时间,以便于应用漏桶算法
local limit, limit_err = limit_conn.new("limit_conn_store", 10, 2, 0.05)
if not limit then
    error("failed to instantiate a resty.limit.conn object: ", limit_err)
end

local _M = {}

function _M.incoming()
    local key = ngx.var.binary_remote_addr
    local delay, err = limit:incoming(key, true)
    if not delay then
        if err == "rejected" then
            return ngx.exit(503)
        end
        ngx.log(ngx.ERR, "failed to limit req: ", err)
        return ngx.exit(500)
    end

    if limit:is_committed() then
        local ctx = ngx.ctx
        ctx.limit_conn_key = key
        ctx.limit_conn_delay = delay
    end

    if delay >= 0.001 then
        ngx.log(ngx.WARN, "delaying conn, excess ", delay,
                "s per binary_remote_addr by limit_conn_store")
        ngx.sleep(delay)
    end
end

function _M.leaving()
    local ctx = ngx.ctx
    local key = ctx.limit_conn_key
    if key then
        local latency = tonumber(ngx.var.request_time) - ctx.limit_conn_delay
        local conn, err = limit:leaving(key, latency)
        if not conn then
            ngx.log(ngx.ERR,
            "failed to record the connection leaving ",
            "request: ", err)
        end
    end
end

return _M

 

重点在于这句话local limit, limit_err = limit_conn.new("limit_conn_store", 8, 2, 0.05),允许的最大并发为常规的8个,突发的2个,一共8+2=10个并发,详情参考

被拒绝的请求直接返回503

if err == "rejected" then
    return ngx.exit(503) -- 超过的请求直接返回503
end


重点在于这句话,模拟每个请求0.5秒处理完成

content_by_lua_block {
    ngx.sleep(0.5)
}

注意在限制连接的代码里面,我们用 ngx.ctx 来存储 limit_conn_key。这里有一个坑。内部重定向(比如调用了 ngx.exec)会销毁 ngx.ctx,导致 limit_conn:leaving() 无法正确调用。 如果需要限连业务里有用到 ngx.exec,可以考虑改用 ngx.var 而不是 ngx.ctx,或者另外设计一套存储方式。只要能保证请求结束时能及时调用 limit:leaving() 即可。

 

重新加载配置文件 


worker_processes  1;
daemon off;
events {
    worker_connections  1024;
}
error_log logs/error_lua.log info;
http {
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    lua_code_cache on;    
   
    # 注意 limit_conn_store 的大小需要足够放置限流所需的键值。
    # 每个 $binary_remote_addr 大小不会超过 16 字节(IPv6 情况下),算上 lua_shared_dict 的节点大小,总共不到 64 字节。
    # 100M 可以放 1.6M 个键值对
    lua_shared_dict limit_conn_store 100M;
    
    server {
        listen 80;
        location / {
            access_by_lua_block {
                local limit_conn = require "utils.limit_conn"
                -- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
                if ngx.req.is_internal() then
                    ngx.log(ngx.INFO,">> lua redirect ")
                    return
                end
                limit_conn.incoming()
                ngx.log(ngx.INFO,">>> lua reqeust comes!")
            }
            content_by_lua_block {
                -- 模拟请求处理时间,很重要,不加可能测试不出效果
                -- 生产中没有请求是只返回一个静态的index.html的!
                ngx.sleep(0.5)
            }
            log_by_lua_block {
                local limit_conn = require "utils.limit_conn"
                limit_conn.leaving()
                ngx.log(ngx.INFO,">>> lua  reqeust leave!")
            }
            
        }
    }
}

 

openresty -s reload 
安装测试工具

yum -y install httpd-tools
[root@centos7 work]# ab -V
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

[root@centos7 work]# 

 

 

测试

上面的配置是每个请求处理0.5秒,并发是10

  • 10个请求,并发为1
ab -n 10 -c 1  127.0.0.1/
​
# 请求全部成功,用时5s左右
Concurrency Level:      1
Time taken for tests:   5.012 seconds 
Complete requests:      10 
Failed requests:        0

[root@centos7 work]# ab -n 10 -c 1  127.0.0.1/

 

return _M[root@centos7 conf]# ab -n 10 -c 1  127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        openresty/1.19.3.2
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        0 bytes

Concurrency Level:      1
Time taken for tests:   5.010 seconds
Complete requests:      10
Failed requests:        0
Write errors:           0
Total transferred:      1620 bytes
HTML transferred:       0 bytes
Requests per second:    2.00 [#/sec] (mean)
Time per request:       501.049 [ms] (mean)
Time per request:       501.049 [ms] (mean, across all concurrent requests)
Transfer rate:          0.32 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:   501  501   0.1    501     501
Waiting:      501  501   0.1    501     501
Total:        501  501   0.1    501     501

Percentage of the requests served within a certain time (ms)
  50%    501
  66%    501
  75%    501
  80%    501
  90%    501
  95%    501
  98%    501
  99%    501
 100%    501 (longest request)
[root@centos7 conf]# 

 

  • 10个请求,并发为10
ab -n 10 -c 10  127.0.0.1/
​
# 请求全部成功,用时1.5s左右
Concurrency Level:      10
Time taken for tests:   1.505 seconds
Complete requests:      10
Failed requests:        0
​

[root@centos7 conf]# ab -n 10 -c 10 127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software: openresty/1.19.3.2
Server Hostname: 127.0.0.1
Server Port: 80

Document Path: /
Document Length: 0 bytes

Concurrency Level: 10
Time taken for tests: 1.004 seconds
Complete requests: 10
Failed requests: 0
Write errors: 0
Total transferred: 1620 bytes
HTML transferred: 0 bytes
Requests per second: 9.96 [#/sec] (mean)
Time per request: 1004.494 [ms] (mean)
Time per request: 100.449 [ms] (mean, across all concurrent requests)
Transfer rate: 1.57 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 0.2 1 1
Processing: 501 502 0.2 502 502
Waiting: 501 502 0.3 502 502
Total: 502 502 0.2 502 503

Percentage of the requests served within a certain time (ms)
50% 502
66% 502
75% 502
80% 503
90% 503
95% 503
98% 503
99% 503
100% 503 (longest request)
[root@centos7 conf]#

 

  • 20个请求,并发为10,并发为10并不会触发限制条件,所以能成功!注意和下面并发11的区别!
ab -n 20 -c 10  127.0.0.1/
​
# 请求全部成功,用时2s左右
Concurrency Level:      10
Time taken for tests:   2.005 seconds
Complete requests:      20
Failed requests:        0
  • 22个请求,并发为11 重点解释一下:
    • 并发不是qps,并发11不是说第一秒发11个请求,然后第二秒再发送11个请求,而是发完第一波紧接着发第二波,每一波的间隔时间不一定是1秒,下面的1.506 seconds就能看出来,按理应该是2s但是并不是
    • 第一波11个请求发送过去了,但是只能处理10个,所以成功了10个,紧接着第二波11个请求发过去了,但是第一波大部分未处理完成所以第二波的都失败了,也有处理完成了的可以接着处理,所以至少会成功10个,下面显示的是11个
    • 此处的大量失败应该是并发超过了10,触发了限制条件让nginx worker线程睡眠了,所以导致后面的请求大量失败
    • -- 触发限制条件
      if delay >= 0.001 then
      ngx.sleep(delay) -- ngx worker睡眠
      end

 

[root@centos7 work]# ab -n 20 -c 10  127.0.0.1/

 

 

[root@centos7 conf]# ab -n 20 -c 10  127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        openresty/1.19.3.2
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        0 bytes

Concurrency Level:      10
Time taken for tests:   1.507 seconds
Complete requests:      20
Failed requests:        0
Write errors:           0
Total transferred:      3240 bytes
HTML transferred:       0 bytes
Requests per second:    13.27 [#/sec] (mean)
Time per request:       753.406 [ms] (mean)
Time per request:       75.341 [ms] (mean, across all concurrent requests)
Transfer rate:          2.10 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       1
Processing:   501  502   0.3    502     502
Waiting:      501  502   0.3    502     502
Total:        502  502   0.2    502     503

Percentage of the requests served within a certain time (ms)
  50%    502
  66%    502
  75%    503
  80%    503
  90%    503
  95%    503
  98%    503
  99%    503
 100%    503 (longest request)

 

ab -n 22 -c 11  127.0.0.1/
​
# 11个成功,11个失败
Concurrency Level:      11
Time taken for tests:   1.506 seconds
Complete requests:      22
Failed requests:        11
Non-2xx responses:      11 # HTTP状态非2xx的有11个,说明限并发成功(只有有非2xx的返回才会显示这句话)
[root@centos7 work]# ab -n 22 -c 11  127.0.0.1/

 

[root@centos7 conf]#  ab -n 22 -c 11  127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        openresty/1.19.3.2
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        0 bytes

Concurrency Level:      11
Time taken for tests:   2.013 seconds
Complete requests:      22
Failed requests:        0
Write errors:           0
Total transferred:      3564 bytes
HTML transferred:       0 bytes
Requests per second:    10.93 [#/sec] (mean)
Time per request:       1006.415 [ms] (mean)
Time per request:       91.492 [ms] (mean, across all concurrent requests)
Transfer rate:          1.73 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       1
Processing:   502  548 148.1    502    1007
Waiting:      501  548 148.1    502    1007
Total:        502  549 148.0    503    1007

Percentage of the requests served within a certain time (ms)
  50%    503
  66%    503
  75%    503
  80%    503
  90%    504
  95%   1005
  98%   1007
  99%   1007
 100%   1007 (longest request)
[root@centos7 conf]# 

log_by_lua_block

 

反向代理

上面测试的是content_by_lua,也就是内容直接在lua中生成,但是实际中内容有可能是后端服务器生成的,所以可以设置反向代理或者负载均衡,如下为反向代理配置

 

location / {
    access_by_lua_block {
        local limit_conn = require "utils.limit_conn"
        -- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
        if ngx.req.is_internal() then
            return
        end
        limit_conn.incoming()
    }
    log_by_lua_block {
        local limit_conn = require "utils.limit_conn"
        limit_conn.leaving()
    }
    
    # 反向代理
    proxy_pass http://172.17.0.3:8080;
    proxy_set_header Host $host;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_connect_timeout 60;
    proxy_read_timeout 600;
    proxy_send_timeout 600;
​
}
​

内部重定向

location / {
  access_by_lua_block {...}
  content_by_lua_block {...}
  log_by_lua_block {...}
}

 

https://github.com/moonbingbing/openresty-best-practices/blob/master/ngx_lua/lua-limit.md

OpenResty+Lua限流实战

posted on 2021-08-27 17:29  tycoon3  阅读(92)  评论(0编辑  收藏  举报

导航