避坑指南:
1.尝试过ngx_http_dyups_module模块,感觉不太好用,OpenResty完全兼容nginx果断采用OpenResty方案
2.迁移最好是找个新机器,测试没问题再切流量
OpenResty是什么
淘宝团队(章亦春)基于官方 Nginx 打包的发行版
- 内置LuaJIT(极快的脚本引擎)
- 内置lua-nginx-module
- 内置几百个生产库(redis、mysql、dns、shared dict、upstream 管理等)
OpenResty 底层就是原汁原味 Nginx,完全兼容所有 Nginx 配置!所有 Nginx 配置直接复制到 OpenResty 100% 能用
特点
- 可以用 Lua 代码动态修改 upstream
- 不需要 reload、不需要改配置、0 抖动
- 可以写:
- 动态上下线节点 API
- 限流、熔断、灰度、AB 测试
- 动态负载、流量染色、鉴权
- 性能几乎和 Nginx 一致(LuaJIT 超快)
迁移全流程
1. 迁移前备份(必做!回滚用)
# 1. 备份原有 nginx 配置 cp -r /usr/local/nginx/conf /usr/local/nginx/conf.bak$(date +%Y%m%d) # 2. 备份原有 nginx 二进制 cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak # 3. 查看原有 nginx 编译参数(后续 openresty 保持一致) nginx -V2.安装 OpenResty 依赖
# CentOS yum install -y pcre-devel openssl-devel gcc curl make # Ubuntu apt install -y libpcre3-dev libssl-dev gcc curl make3.下载并编译 OpenResty(注意版本)
# 下载 cd /usr/local/src wget https://openresty.org/download/openresty-1.21.4.1.tar.gz tar -zxvf openresty-1.21.4.1.tar.gz cd openresty-1.21.4.1 # 编译配置(和你原 Nginx 1.21.4 完全兼容) ./configure \ --prefix=/usr/local/openresty \ --with-http_ssl_module \ --with-http_realip_module \ --with-http_gzip_static_module \ --with-http_stub_status_module # 编译安装 make -j4 && make install5.配置迁移
# 复制你原有 Nginx 配置到 OpenResty cp -rf /usr/local/nginx/conf/* /usr/local/openresty/nginx/conf/ #平滑关闭旧 Nginx,启动 OpenResty(零停机) # 平滑停止旧 Nginx(等待所有请求执行完,不中断) /usr/local/nginx/sbin/nginx -s quit # 启动 OpenResty(等价于 nginx,完全兼容) /usr/local/openresty/nginx/sbin/nginx # 查看版本 → 显示 openresty/1.21.4.1 即成功 /usr/local/openresty/nginx/sbin/nginx -v # 测试业务 → 原有网站/接口完全正常访问 curl http://你的域名核心配置:动态 Upstream(API 上下线,无需 reload)
1. 配置文件:/usr/local/openresty/nginx/conf/nginx.conf
pid /usr/local/openresty/nginx/logs/nginx.pid; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # 业务上游集群 upstream pos_gateway { server 127.0.0.1:8089; server 127.0.0.1:8088; } # 业务入口 8087 server { listen 8087; location / { proxy_pass http://pos_gateway; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } # 动态上下线 API服务(JSON输出+UTF8+节点保护) server { listen 8086; # 1. 查看节点状态 - 标准JSON输出 location /upstream/status { content_by_lua_block { -- 设置UTF-8编码,解决中文乱码 ngx.header.content_type = "application/json; charset=utf-8" local ngx_upstream = require "ngx.upstream" local cjson = require "cjson" local peers = ngx_upstream.get_primary_peers("pos_gateway") local result = { code = 200, msg = "查询成功", data = peers } ngx.say(cjson.encode(result)) } } # 2. 统一操作接口:up上线/down下线(JSON+保护机制) location /upstream/operate { content_by_lua_block { -- 核心:设置UTF8编码,彻底解决中文乱码 ngx.header.content_type = "application/json; charset=utf-8" local ngx_upstream = require "ngx.upstream" local cjson = require "cjson" -- 获取参数 local action = ngx.var.arg_action local ip = ngx.var.arg_ip local port = ngx.var.arg_port -- 统一JSON返回对象 local res = {code=500, msg="", data=nil} -- 参数校验 if not action or not ip or not port then res.msg = "参数错误:请传入 action=up/down、ip、port" ngx.say(cjson.encode(res)) return end if action ~= "up" and action ~= "down" then res.msg = "参数错误:action仅支持 up/down" ngx.say(cjson.encode(res)) return end local target_server = ip .. ":" .. port local peers = ngx_upstream.get_primary_peers("pos_gateway") local peer_index = nil local target_is_online = false -- 匹配目标节点 for i, peer in ipairs(peers) do if peer.name == target_server then peer_index = i - 1 target_is_online = not peer.down break end end if not peer_index then res.msg = "操作失败:未找到节点 " .. target_server ngx.say(cjson.encode(res)) return end -- 核心保护:禁止下线最后一个在线节点 if action == "down" then local online_count = 0 for _, peer in ipairs(peers) do if not peer.down then online_count = online_count + 1 end end if online_count == 1 and target_is_online then res.msg = "禁止操作:当前仅有一个节点在线,不允许下线" ngx.say(cjson.encode(res)) return end end -- 执行上下线操作 local is_down = (action == "down") local ok, err = ngx_upstream.set_peer_down("pos_gateway", false, peer_index, is_down) if ok then res.code = 200 res.msg = "操作成功:节点 " .. target_server .. (is_down and " 已下线" or " 已上线") else res.msg = "操作失败:" .. err end ngx.say(cjson.encode(res)) } } } # 测试服务 8089 server { listen 8089; location / { return 200 "8089"; } } # 测试服务 8088 server { listen 8088; location / { return 200 "8088"; } } }2. 测试验证
# 1. 查询节点状态 curl http://127.0.0.1:8086/upstream/status # 2. 下线8089节点 curl "http://127.0.0.1:8086/upstream/operate?action=down&ip=127.0.0.1&port=8089" # 3. 尝试下线最后一个节点8088(触发保护) curl "http://127.0.0.1:8086/upstream/operate?action=down&ip=127.0.0.1&port=8088" # 4. 上线8089节点 curl "http://127.0.0.1:8086/upstream/operate?action=up&ip=127.0.0.1&port=8089" # 5. 业务测试 curl http://127.0.0.1:8087 // 成功 {"code":200,"msg":"操作成功:节点 127.0.0.1:8089 已下线","data":null} // 保护提示 {"code":500,"msg":"禁止操作:当前仅有一个节点在线,不允许下线","data":null} // 状态查询 {"code":200,"msg":"查询成功","data":[{"name":"127.0.0.1:8089","down":false},...]}