Loading... ### Nginx+Lua脚本控制负载均衡 有时候会根据不同客户需求,提供特有的私有环境,但是接口入口都是统一的情况下,如何将用户请求转发到特定的机器上呢? 如果可以根据用户请求的参数进行判断,然后nginx转根据对应参数转发到对应服务器就可以啦。 Nginx本身是可以获取到用户请求参数的,就像这样: 比如我要获取https://api.example.com?id=test ```shell location / { echo "appId: $arg_id"; } ``` 通过上述配置是可以获取到Get请求中Url所携带的参数,但是Post请求是无法获取的,但是现在大部分api都是Post请求。而且为了更灵活的判断用户参数,再进行相应转发,我们就需要用到Lua脚本啦。 #### Lua脚本配置 **Lua** 是一个由标准 **C** 语言 开发的、开源的、**可扩展的**、**轻量级的**、**弱类型的**、**解释型脚本语言**。 OpenResty集成了Lua脚本,直接上如何配置。 ##### 1.设置缓存数据的脚本 cache.lua ```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) ```lua local cacheUtils= require "cache" local upsValue = cacheUtils.get_ups(); if upsValue then ngx.var.my_ups = upsValue end ``` #### Nginx配置 ##### 1. 指定内存区域缓存配置数据 ```shell http { lua_shared_dict ups_cache 128k; } ``` ##### 2.通过接口传输配置数据到Nginx ```shell 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.业务接口配置 ```shell 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或者数据库对于接口性能的影响。 © Allow specification reprint Support Appreciate the author AliPayWeChat Like 2 If you think my article is useful to you, please feel free to appreciate