lolly/docs/config/lua/balancer-by-lua.conf
xfy 6543422281 docs: 添加 Nginx 配置和 Lua 脚本示例文档
- config: 反向代理、缓存、负载均衡、安全、SSL 等配置模板
- lua: API 网关、认证、动态路由、限流、WebSocket 等脚本示例

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 17:59:22 +08:00

175 lines
5.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ============================================================
# 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 避免阻塞