- config: 反向代理、缓存、负载均衡、安全、SSL 等配置模板 - lua: API 网关、认证、动态路由、限流、WebSocket 等脚本示例 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
175 lines
5.6 KiB
Plaintext
175 lines
5.6 KiB
Plaintext
# ============================================================
|
||
# Nginx balancer_by_lua 动态负载均衡配置示例
|
||
# ============================================================
|
||
#
|
||
# 功能说明:
|
||
# - 使用 Lua 实现动态负载均衡
|
||
# - 服务发现集成
|
||
# - 健康检查
|
||
#
|
||
# Lolly 对应配置:
|
||
# 可通过 Lua 实现自定义负载均衡逻辑
|
||
# 相关文档: docs/lua-nginx-module/08-balancer.md
|
||
# ============================================================
|
||
|
||
http {
|
||
lua_shared_dict upstream_list 10m;
|
||
lua_shared_dict health_status 5m;
|
||
|
||
# 初始化上游服务器列表
|
||
init_by_lua_block {
|
||
local upstream_list = ngx.shared.upstream_list
|
||
|
||
-- 初始服务器列表
|
||
local servers = {
|
||
{host = "backend1", port = 8080, weight = 3},
|
||
{host = "backend2", port = 8080, weight = 2},
|
||
{host = "backend3", port = 8080, weight = 1},
|
||
}
|
||
|
||
-- 存储到共享字典
|
||
local cjson = require "cjson.safe"
|
||
upstream_list:set("api_servers", cjson.encode(servers))
|
||
}
|
||
|
||
# 后台健康检查
|
||
init_worker_by_lua_block {
|
||
local health = require "health_checker"
|
||
|
||
-- 每 10 秒检查一次
|
||
local function check_health(premature)
|
||
if premature then return end
|
||
|
||
local upstream_list = ngx.shared.upstream_list
|
||
local health_status = ngx.shared.health_status
|
||
local cjson = require "cjson.safe"
|
||
|
||
local servers_raw = upstream_list:get("api_servers")
|
||
local servers = cjson.decode(servers_raw)
|
||
|
||
for _, server in ipairs(servers) do
|
||
local key = server.host .. ":" .. server.port
|
||
-- 发送健康检查请求(使用 cosocket)
|
||
local ok = health.check(server.host, server.port)
|
||
health_status:set(key, ok and "healthy" or "unhealthy")
|
||
end
|
||
|
||
-- 递归调度下次检查
|
||
ngx.timer.every(10, check_health)
|
||
end
|
||
|
||
-- 启动定时器
|
||
ngx.timer.at(0, check_health)
|
||
}
|
||
|
||
# 定义上游
|
||
upstream dynamic_backend {
|
||
server 0.0.0.1; # 占位符,实际由 balancer_by_lua 选择
|
||
|
||
balancer_by_lua_block {
|
||
local balancer = require "ngx.balancer"
|
||
local upstream_list = ngx.shared.upstream_list
|
||
local health_status = ngx.shared.health_status
|
||
local cjson = require "cjson.safe"
|
||
|
||
-- 获取服务器列表
|
||
local servers_raw = upstream_list:get("api_servers")
|
||
local servers = cjson.decode(servers_raw)
|
||
|
||
-- 过滤健康服务器
|
||
local healthy_servers = {}
|
||
for _, server in ipairs(servers) do
|
||
local key = server.host .. ":" .. server.port
|
||
if health_status:get(key) == "healthy" then
|
||
-- 根据权重添加多次
|
||
for _ = 1, server.weight do
|
||
table.insert(healthy_servers, server)
|
||
end
|
||
end
|
||
end
|
||
|
||
if #healthy_servers == 0 then
|
||
ngx.log(ngx.ERR, "No healthy servers available")
|
||
return ngx.exit(503)
|
||
end
|
||
|
||
-- 轮询选择(可替换为其他算法)
|
||
local idx = ngx.var.request_id:byte(1) % #healthy_servers + 1
|
||
local selected = healthy_servers[idx]
|
||
|
||
-- 设置当前请求的上游
|
||
local ok, err = balancer.set_current_peer(selected.host, selected.port)
|
||
if not ok then
|
||
ngx.log(ngx.ERR, "failed to set peer: ", err)
|
||
return ngx.exit(500)
|
||
end
|
||
}
|
||
}
|
||
|
||
server {
|
||
listen 80;
|
||
server_name balancer-lua.example.com;
|
||
|
||
location /api {
|
||
proxy_pass http://dynamic_backend;
|
||
proxy_set_header Host $host;
|
||
}
|
||
|
||
# 动态更新服务器列表 API
|
||
location /admin/servers {
|
||
content_by_lua_block {
|
||
local cjson = require "cjson.safe"
|
||
local upstream_list = ngx.shared.upstream_list
|
||
|
||
local method = ngx.req.get_method()
|
||
|
||
if method == "GET" then
|
||
local servers = upstream_list:get("api_servers")
|
||
ngx.header["Content-Type"] = "application/json"
|
||
ngx.say(servers)
|
||
|
||
elseif method == "POST" then
|
||
ngx.req.read_body()
|
||
local data = cjson.decode(ngx.req.get_body_data())
|
||
|
||
-- 验证数据格式
|
||
if not data or not data.servers then
|
||
ngx.status = 400
|
||
ngx.say(cjson.encode({error = "Invalid data"}))
|
||
ngx.exit(400)
|
||
end
|
||
|
||
upstream_list:set("api_servers", cjson.encode(data.servers))
|
||
ngx.say(cjson.encode({success = true}))
|
||
|
||
else
|
||
ngx.status = 405
|
||
ngx.say(cjson.encode({error = "Method not allowed"}))
|
||
end
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
# balancer_by_lua 说明:
|
||
#
|
||
# 1. 核心功能:
|
||
# - 动态选择上游服务器
|
||
# - 支持自定义负载均衡算法
|
||
# - 集成服务发现
|
||
#
|
||
# 2. ngx.balancer API:
|
||
# - set_current_peer(host, port): 设置目标服务器
|
||
# - set_more_tries(count): 设置重试次数
|
||
# - get_last_failure(): 获取上次失败信息
|
||
#
|
||
# 3. 使用场景:
|
||
# - 动态服务发现(Consul、etcd)
|
||
# - 基于权重的负载均衡
|
||
# - 基于延迟的路由
|
||
# - A/B 测试流量分发
|
||
#
|
||
# 4. 注意事项:
|
||
# - 需要占位符 server 指令
|
||
# - 健康检查需要自行实现
|
||
# - 使用 cosocket 避免阻塞 |