nginx做白名单和限流

​ 在我们生产环境中使用到了地图服务,每个月有免费请求次数,近一个月请求次数突然暴涨,导致直接开启付费模式,一个月上百刀的花销着实难扛,根据实际我们的业务使用情况,远达不到付费标准,故考虑做白名单和限流措施,基于以上情况并遇到春节急需快速处理,所以选择了最简单方便的方式,通过nginx做限流

​ 我们都知道nginx里面是可以用lua脚本做一些稍微复杂些的逻辑处理的,要使用lua脚本需要编译lua解释器,时间有限我直接用了openresty,它集成了lua和nginx

1、openresty是什么?

OpenResty是一个基于Nginx的高性能Web平台,用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。具备下列特点:

具备Nginx的完整功能

基于Lua语言进行扩展,集成了大量精良的 Lua 库、第三方模块,允许使用Lua自定义业务逻辑、自定义库

二、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、目录结构

​ 默认安装在/usr/local/openresty

![image-20240205182218056](/Users/sunarmy/Library/Application Support/typora-user-images/image-20240205182218056.png)

看到里面有一个nginx目录,进去可以看到跟我们平常用的nginx是一模一样的,OpenResty就是在Nginx基础上集成了一些Lua模块

到这里我们就安装好了

7. 启动和运行

OpenResty底层是基于Nginx的,查看OpenResty目录的nginx目录,结构与windows中安装的nginx基本一致:

所以这个里面的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脚本文件(白名单加限流)

通过两个redis的key,map_request_limitation:存放令牌数量,map_request_white_list:白名单列表;白名单的IP,无需限流,只有白名单之外的才需要限流

复制代码
-- 其实这两个值可以从redis取  甚至可以给每个qrcode设置单独的速率和容积
-- 但如果想监听桶的状态  需要持续的请求, 只有每次请求后才重新计算并更新桶状态 否则桶状态不变
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
-- 权限校验
local res, err = red:auth("123456")
if not res then
    ngx.say("failed to authenticate: ", err)
    return
end
-- 发送 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

    -- 获取上次访问时间和令牌数量
    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

    -- 计算时间间隔
    local time_passed = current_time - (tonumber(last_access_time) or 0)

    -- 计算新的令牌数量
    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)

    -- 判断令牌数量是否足够
    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
]]

-- 执行脚本
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

启动之后当通过这个999端口访问之后,我们在redis里面可以看到以下两个key,白名单可以自行添加,即时生效

相关推荐
wdxylb35 分钟前
云原生俱乐部-shell知识点归纳(1)
linux·云原生
飞雪20072 小时前
Alibaba Cloud Linux 3 在 Apple M 芯片 Mac 的 VMware Fusion 上部署的完整密码重置教程(二)
linux·macos·阿里云·vmware·虚拟机·aliyun·alibaba cloud
路溪非溪2 小时前
关于Linux内核中头文件问题相关总结
linux
Lovyk4 小时前
Linux 正则表达式
linux·运维
Fireworkitte5 小时前
Ubuntu、CentOS、AlmaLinux 9.5的 rc.local实现 开机启动
linux·ubuntu·centos
sword devil9006 小时前
ubuntu常见问题汇总
linux·ubuntu
ac.char6 小时前
在CentOS系统中查询已删除但仍占用磁盘空间的文件
linux·运维·centos
淮北也生橘128 小时前
Linux的ALSA音频框架学习笔记
linux·笔记·学习
华强笔记11 小时前
Linux内存管理系统性总结
linux·运维·网络
十五年专注C++开发11 小时前
CMake进阶: CMake Modules---简化CMake配置的利器
linux·c++·windows·cmake·自动化构建