前言

虽然nginx中自带了限流的模块,只能直接限定超出的数量,但对于允许范围内的流量如何进行限流是个问题。nginx的限流方式!

1
2
3
4
5
6
7
8
9


 limit_conn perserver 100;


 limit_conn perip 15;


 limit_rate 512k;

但是比如这100的允许的值,0-30个请求去mysql读数据,31-70去redis读数据,71-100去文件直接读数据,nginx不好做这个事情,所以引入lua的lua-resty-limit-traffic来设计。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177


local limit_req = require "resty.limit.req"


-- 这里设置rate=50个请求/每秒,漏桶桶容量设置为1000个请求


-- 因为模块中控制粒度为毫秒级别,所以可以做到毫秒级别的平滑处理


-- my_limit_req_store是共享内存,请在http中设置一下  lua_shared_dict my_limit_req_store 100m;


local lim, err = limit_req.new("my_limit_req_store", 50, 1000)


if not lim then


    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)


    return ngx.exit(501)


end


 


local key = ngx.var.binary_remote_addr


local delay, err = lim:incoming(key, true)


 


 


ngx.say("计算出来的延迟时间是:")


ngx.say(delay)


 


--if ( delay <0 or delay==nil ) then


    --return ngx.exit(502)


--end


 


 


-- 1000以外的就溢出


if not delay then


    if err == "rejected" then


        return ngx.say("1000以外的就溢出")


        -- return ngx.exit(502)


    end


    ngx.log(ngx.ERR, "failed to limit req: ", err)


    return ngx.exit(502)


end


 


-- 50-100的等待从微服务+mysql获取实时数据;(100-50)/50 =1


if ( delay >0 and delay <=1 ) then


    ngx.say("第50-第100个 等待0-1秒后 从mysql获取数据")


    ngx.sleep(delay)


 


-- 100-400的直接从redis获取实时性略差的数据;(400-50)/50 =7


elseif ( delay >1 and delay <=7 ) then


    local resp, err = redis_instance:get("redis_goods_list_advert")


    ngx.say("第100-第400个 降级为从redis获取数据")


    ngx.say(resp)


    return


 


-- 400-1000的从静态文件获取实时性非常低的数据(1000-50)/50 =19


elseif ( delay >7) then


 


    ngx.say("第400-第1000个 降级为从静态文件(死页面)获取数据")


    ngx.header.content_type="application/x-javascript;charset=utf-8"


    local file = "/etc/nginx/html/goods_list_advert.json"


    local f = io.open(file, "rb")


    local content = f:read("*all")


    f:close()


    ngx.print(content)


    return


end


 


 


ngx.say("进入查询微服务+mysql(最实时的数据,进入这里就是没降级)")