nginx做白名單和限流的完整過程
在我們生產(chǎn)環(huán)境中使用到了地圖服務(wù),每個(gè)月有免費(fèi)請(qǐng)求次數(shù),近一個(gè)月請(qǐng)求次數(shù)突然暴漲,導(dǎo)致直接開啟付費(fèi)模式,一個(gè)月上百刀的花銷著實(shí)難扛,根據(jù)實(shí)際我們的業(yè)務(wù)使用情況,遠(yuǎn)達(dá)不到付費(fèi)標(biāo)準(zhǔn),故考慮做白名單和限流措施,基于以上情況并遇到春節(jié)急需快速處理,所以選擇了最簡(jiǎn)單方便的方式,通過nginx做限流
? 我們都知道nginx里面是可以用lua腳本做一些稍微復(fù)雜些的邏輯處理的,要使用lua腳本需要編譯lua解釋器,時(shí)間有限我直接用了openresty,它集成了lua和nginx
一、openresty是什么?
OpenResty是一個(gè)基于Nginx的高性能Web平臺(tái),用于方便地搭建能夠處理超高并發(fā)、擴(kuò)展性極高的動(dòng)態(tài) Web 應(yīng)用、Web 服務(wù)和動(dòng)態(tài)網(wǎng)關(guān)。具備下列特點(diǎn):
具備Nginx的完整功能
基于Lua語言進(jìn)行擴(kuò)展,集成了大量精良的 Lua 庫、第三方模塊,允許使用Lua自定義業(yè)務(wù)邏輯、自定義庫
二、OpenResty的安裝
1、添加OpenResty倉庫
# 由于公共庫中找不到openresty,所以需要添加openresty的源倉庫 yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo # 注意,如果上面命令提示不存在,那就先安裝一下 yum install -y yum-utils
2. 安裝OpenResty
# 安裝openresty yum install -y openresty # 安裝OpenResty管理工具,幫助我們安裝第三方的Lua模塊 yum install -y openresty-opm
3、目錄結(jié)構(gòu)
? 默認(rèn)安裝在/usr/local/openresty
看到里面有一個(gè)nginx目錄,進(jìn)去可以看到跟我們平常用的nginx是一模一樣的,OpenResty就是在Nginx基礎(chǔ)上集成了一些Lua模塊
到這里我們就安裝好了
4. 啟動(dòng)和運(yùn)行
OpenResty底層是基于Nginx的,查看OpenResty目錄的nginx目錄,結(jié)構(gòu)與windows中安裝的nginx基本一致:
所以這個(gè)里面的nginx和平常的nginx是一樣的
1)nginx配置文件
worker_processes 1; events { worker_connections 1024; } http { server{ listen 999; server_name localhost; location /mapbox/ { access_by_lua_file "/usr/local/openresty/nginx/lua_script/rule.lua"; proxy_pass https://api.mapbox.com/; proxy_ssl_server_name on; } } }
2)lua腳本文件(白名單加限流)
通過兩個(gè)redis的key,map_request_limitation:存放令牌數(shù)量,map_request_white_list:白名單列表;白名單的IP,無需限流,只有白名單之外的才需要限流
-- 其實(shí)這兩個(gè)值可以從redis取 甚至可以給每個(gè)qrcode設(shè)置單獨(dú)的速率和容積 -- 但如果想監(jiān)聽桶的狀態(tài) 需要持續(xù)的請(qǐng)求, 只有每次請(qǐng)求后才重新計(jì)算并更新桶狀態(tài) 否則桶狀態(tài)不變 local tokens_per_second = 0.2 -- 生成速率 /s local max_tokens = 10 -- 最大溶劑 local current_time = ngx.now() local path = ngx.var.uri local redis_key = "map_request_limitation" local redis_key_white_list = "map_request_white_list" local client_ip = ngx.var.remote_addr -- local redis_key = "path:" .. path -- 連接Redis local redis = require "resty.redis" local red = redis:new() red:set_timeout(1000) local ok, err = red:connect("127.0.0.1", 6379) if not ok then ngx.log(ngx.ERR, "Redis連接失敗: ", err) return ngx.exit(500) end -- 權(quán)限校驗(yàn) local res, err = red:auth("123456") if not res then ngx.say("failed to authenticate: ", err) return end -- 發(fā)送 Lua 腳本(保證redis原子性操作) local script = [[ local redis_key = KEYS[1] local redis_white_list_key = KEYS[2] local tokens_per_second = tonumber(ARGV[1]) local max_tokens = tonumber(ARGV[2]) local current_time = tonumber(ARGV[3]) local client_ip = ARGV[4] -- ip是否存在列表中 local is_in_whitelist, err = redis.call('sismember', redis_white_list_key, client_ip) if is_in_whitelist == 1 then return 1 end -- 獲取上次訪問時(shí)間和令牌數(shù)量 local res = redis.call('HMGET', redis_key, 'last_access_time', 'tokens') local last_access_time local last_tokens if res[1] and res[2] then last_tokens = res[2] last_access_time = res[1] end -- 計(jì)算時(shí)間間隔 local time_passed = current_time - (tonumber(last_access_time) or 0) -- 計(jì)算新的令牌數(shù)量 last_tokens = last_tokens and tonumber(last_tokens) or max_tokens local new_tokens = math.min(max_tokens, last_tokens + time_passed * tokens_per_second) -- 判斷令牌數(shù)量是否足夠 if new_tokens >= 1 then -- 消耗令牌 redis.call('HMSET', redis_key, 'last_access_time', current_time, 'tokens', new_tokens - 1) return 1 else return 0 end ]] -- 執(zhí)行腳本 local result = red:eval(script, 2, redis_key, redis_key_white_list,tokens_per_second, max_tokens,current_time,client_ip) if result == 1 then -- 成功 ngx.log(ngx.INFO, "成功") else -- 令牌不足 ngx.status = ngx.HTTP_TOO_MANY_REQUESTS ngx.say("OVERLOAD?。。?!",result) return ngx.exit(ngx.HTTP_TOO_MANY_REQUESTS) end -- 返還redis連接到連接池 local ok, err = red:set_keepalive(10000, 100) if not ok then ngx.log(ngx.ERR, err) end
啟動(dòng)之后當(dāng)通過這個(gè)999端口訪問之后,我們?cè)趓edis里面可以看到以下兩個(gè)key,白名單可以自行添加,即時(shí)生效
到此這篇關(guān)于nginx做白名單和限流的文章就介紹到這了,更多相關(guān)nginx白名單和限流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nginx和lvs各自的優(yōu)劣以及適合的使用環(huán)境
這篇文章主要介紹了nginx和lvs各自的優(yōu)劣以及適合的使用環(huán)境,幫助大家選擇符合需求的服務(wù)器,感興趣的朋友可以了解下2020-10-10ubuntu上配置Nginx+PHP5 FastCGI服務(wù)器配置
ubuntu上配置Nginx+PHP5 FastCGI服務(wù)器配置方法, 需要的朋友可以參考下。2010-06-06Nginx服務(wù)器中配置非80端口的端口轉(zhuǎn)發(fā)方法詳解
這篇文章主要介紹了Nginx服務(wù)器中配置非80端口的端口轉(zhuǎn)發(fā)方法詳解,文中使用到了Nginx中的proxy_pass配置項(xiàng),需要的朋友可以參考下2016-04-04