nginx使用 Lua 脚本实现负载均衡、请求转发和过滤功能

如何使用 Lua 脚本实现负载均衡、请求转发和过滤功能

1. 基础的负载均衡脚本

圆形轮询算法

-- 定义上游服务器列表
local upstreams = {
    "192.168.1.10:8080",
    "192.168.1.11:8080",
    "192.168.1.12:8080"
}

-- 使用 round-robin 算法
local function round_robin()
    -- 获取计数器
    local counter = ngx.shared.counter or 0
    counter = (counter + 1) % #upstreams
    ngx.shared.counter = counter
    return upstreams[counter + 1]
end

带权重的圆形轮询算法

-- 根据权重选择服务器
local function weighted_round_robin()
    local servers = {
        {host = "192.168.1.10", weight = 5},
        {host = "192.168.1.11", weight = 3},
        {host = "192.168.1.12", weight = 2}
    }
    
    local total = 0
    for _, server in ipairs(servers) do
        total = total + server.weight
    end
    
    local rand = math.random(total)
    local cur_weight = 0
    
    for _, server in ipairs(servers) do
        cur_weight = cur_weight + server.weight
        if rand <= cur_weight then
            return server.host
        end
    end
end

2. 请求转发和过滤

请求速率限制

-- 请求速率限制
local function limit_req()
    local limit_key = ngx.var.binary_remote_addr
    local limit_rate = 10  -- 每秒请求数限制
    
    local current_calls = ngx.shared.limits:get(limit_key)
    if current_calls and current_calls > limit_rate then
        ngx.status = 429
        ngx.say("Too Many Requests")
        return ngx.exit(ngx.HTTP_TOO_MANY_REQUESTS)
    end
    
    -- 增加计数
    local success, err = ngx.shared.limits:incr(limit_key, 1, 0, 1)
end

IP 黑白名单过滤

-- IP 黑白名单过滤
local function ip_filter()
    local client_ip = ngx.var.remote_addr
    local blacklist = {
        "192.168.1.100",
        "192.168.1.101"
    }
    
    for _, ip in ipairs(blacklist) do
        if client_ip == ip then
            ngx.status = 403
            ngx.say("Forbidden")
            return ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    end
end

URL 路径过滤

-- URL 路径过滤
local function url_filter()
    local uri = ngx.var.uri
    local blocked_paths = {
        "/admin",
        "/internal"
    }
    
    for _, path in ipairs(blocked_paths) do
        if string.find(uri, path) then
            ngx.status = 403
            ngx.say("Access Denied")
            return ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    end
end

3. 健康检查

local function health_check()
    local http = require "resty.http"
    local httpc = http.new()
    
    local function check_server(host)
        local ok, err = httpc:request_uri("http://" .. host .. "/health", {
            method = "GET",
            headers = {
                ["Host"] = "example.com"
            }
        })
        
        if not ok then
            return false
        end
        
        if ok.status == 200 then
            return true
        end
        
        return false
    end
    
    -- 检查所有服务器
    local healthy_servers = {}
    for _, server in ipairs(upstreams) do
        if check_server(server) then
            table.insert(healthy_servers, server)
        end
    end
    
    return healthy_servers
end

4. 完整的应用示例

-- 初始化共享内存
local shared = ngx.shared
shared.limits = shared.limits or {}
shared.counter = shared.counter or 0

-- 主处理函数
local function main()
    -- 1. IP 过滤
    ip_filter()
    
    -- 2. URL 过滤
    url_filter()
    
    -- 3. 速率限制
    limit_req()
    
    -- 4. 获取健康服务器
    local servers = health_check()
    if #servers == 0 then
        ngx.status = 503
        ngx.say("No available servers")
        return ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
    end
    
    -- 5. 负载均衡选择服务器
    local target = round_robin()
    
    -- 6. 转发请求
    local httpc = require("resty.http").new()
    local res, err = httpc:request_uri("http://" .. target .. ngx.var.uri, {
        method = ngx.req.get_method(),
        headers = ngx.req.get_headers(),
        body = ngx.req.get_body_data()
    })
    
    if not res then
        ngx.status = 502
        ngx.say("Bad Gateway")
        return ngx.exit(ngx.HTTP_BAD_GATEWAY)
    end
    
    -- 7. 返回响应
    ngx.status = res.status
    for k, v in pairs(res.headers) do
        ngx.header[k] = v
    end
    ngx.say(res.body)
end

-- 执行
main()

这个脚本实现了:

  • 多种负载均衡算法
  • 请求速率限制
  • IP 黑白名单过滤
  • URL 路径过滤
  • 服务器健康检查
  • 请求转发处理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值