Nginx+Lua脚本控制负载均衡
有时候会根据不同客户需求,提供特有的私有环境,但是接口入口都是统一的情况下,如何将用户请求转发到特定的机器上呢?
如果可以根据用户请求的参数进行判断,然后nginx转根据对应参数转发到对应服务器就可以啦。
Nginx本身是可以获取到用户请求参数的,就像这样:
比如我要获取https://api.example.com?id=test
location / {
echo "appId: $arg_id";
}
通过上述配置是可以获取到Get请求中Url所携带的参数,但是Post请求是无法获取的,但是现在大部分api都是Post请求。而且为了更灵活的判断用户参数,再进行相应转发,我们就需要用到Lua脚本啦。
Lua脚本配置
Lua 是一个由标准 C 语言 开发的、开源的、可扩展的、轻量级的、弱类型的、解释型脚本语言。
OpenResty集成了Lua脚本,直接上如何配置。
1.设置缓存数据的脚本 cache.lua
-- 获取内存数据
local ups_cache = nginx.shared.ups_cache
function set_cache(key, value)
local success, err = my_cache:set(key, calue)
if not success then
ngx.log(ngx.ERR, "failed to set cache: ", err)
return nil
end
return true
end
function get_cache(key)
return ups_cache:get(key)
end
function get_ups()
ngx.req.read_body() -- 确保读取整个请求体
local body_data = ngx.req.get_body_data()
if not body_data then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.say("Failed to read request body")
return nil
end
local json_data = cjson.decode(body_data)
if not json_data then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.say("Invalid JSON data in request body")
return nil
end
local appId = json_data.appId
return get_cache(appId)
end
return {
set_cache = set_cache;
get_cache = get_cache;
get_ups = get_ups;
}
2.根据缓存数据获取ups,(get_ups.lua)
local cacheUtils= require "cache"
local upsValue = cacheUtils.get_ups();
if upsValue then
ngx.var.my_ups = upsValue
end
Nginx配置
1. 指定内存区域缓存配置数据
http {
lua_shared_dict ups_cache 128k;
}
2.通过接口传输配置数据到Nginx
server {
listen 80;
server_name api.xxx.com;
location /updateCache {
content_by_lua_block {
-- 引入json工具
local cjson = require "cjson"
-- 引入cache.lua
local cache = require "cache"
-- 读取请求体中的 JSON 数据
ngx.req.read_body() -- 确保读取整个请求体
local json_data = ngx.req.get_body_data()
if not json_data then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.say("Failed to read request body")
return
end
-- 解析 JSON 数据
local data, err = cjson.decode(json_data)
if not data then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.say("Invalid JSON data")
return
end
local key = data.key
local value = cjson.encode(data.value) -- 将 Value 编码为 JSON 字符串存入缓存
-- 将数据存入缓存
if cache.set_cache(key, value) then
ngx.status = ngx.HTTP_OK
ngx.say("Data cached successfully")
else
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say("Failed to cache data")
end
}
}
}
3.业务接口配置
upstream ups_normal {
server 192.168.1.1:8080;
}
upstream ups_test {
server 192.168.1.2:8080;
}
server {
#省略
...
location /v1 {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
#设置默认转发的upstream
set $my_ups 'ups_normal';
access_by_lua_file "/opt/get_ups.lua";
proxy_pass http://$my_ups
}
}
这种方式可以很灵活的通过业务端进行负载均衡的控制,如果觉得Nginx的共享内存不稳定,容易造成配置数据的丢失,还可以对数据的缓存做进一步的处理,比如将数据缓存到redis中,再持久化到数据库中。定时将数据同步至Nginx缓存中,避免redis或者数据库对于接口性能的影响。