概述
本文档详细说明如何构建 OpenResty,并添加 nginx_upstream_check_module 模块以实现主动健康检查功能。该模块可以定期检查后端服务器的健康状态,自动剔除不健康的服务器,提高系统的可用性和稳定性。
前置要求
- Ubuntu 操作系统
- 已安装必要的编译工具(gcc、make 等)
- 已安装 Git
- 具备 root 权限或 sudo 权限
Ubuntu 系统安装编译工具
对于 Ubuntu/Debian 系统,使用以下命令安装必要的编译工具和依赖:
bash
# 更新软件包列表
apt-get update
# 安装编译工具和依赖库
apt-get install -y gcc g++ make automake autoconf libtool \
libpcre3-dev zlib1g-dev libssl-dev git
# 验证安装
gcc --version
make --version
git --version
构建步骤
步骤 1:下载并解压 OpenResty
下载最新版本的 OpenResty,解压缩后进入 OpenResty 目录。
bash
# 下载并解压 OpenResty(以1.27.1.2示例)
wget https://openresty.org/download/openresty-1.27.1.2.tar.gz
mkdir openresty
tar -xzf openresty-1.27.1.2.tar.gz --strip-components=1 -C openresty
步骤 2:安装 LuaJIT
进入 LuaJIT 目录并执行编译安装:
bash
cd openresty/bundle/LuaJIT-2.1-20250117
make && make install
步骤 3:配置 LuaJIT 环境变量
编辑 ~/.bashrc 文件,添加以下环境变量:
bash
vi ~/.bashrc
添加以下内容:
bash
export LUAJIT_INC=/usr/local/include/luajit-2.1
export LUAJIT_LIB=/usr/local/lib
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
使环境变量生效:
bash
source ~/.bashrc
步骤 4:校验 LuaJIT 安装配置
完成 LuaJIT 安装和环境变量配置后,执行以下命令进行校验:
bash
# 1. 验证 LuaJIT 可执行文件是否安装成功
luajit -v
# 2. 验证环境变量是否正确设置
echo $LUAJIT_INC
echo $LUAJIT_LIB
echo $LD_LIBRARY_PATH
预期结果:
luajit -v应显示 LuaJIT 版本信息(如:LuaJIT 2.1.0-beta3)- 环境变量应显示正确的路径
如果任何一项校验失败,请检查安装步骤和环境变量配置是否正确。
步骤 5:下载并配置 OpenSSL 3
下载 OpenSSL 3,解压缩到指定目录:
bash
# 返回到 openresty 根目录
cd ../../../
# 下载 OpenSSL 3.3.0
wget https://www.openssl.org/source/old/3.3/openssl-3.3.0.tar.gz
# 创建目标目录(如果不存在)
mkdir -p openresty/bundle/nginx-1.27.1/objs/lib/openssl-3.3.0
# 解压 OpenSSL 到目标目录
tar -xvf openssl-3.3.0.tar.gz -C openresty/bundle/nginx-1.27.1/objs/lib/openssl-3.3.0 --strip-components=1
步骤 6:下载 nginx_upstream_check_module
使用 Git 克隆健康检查模块:
bash
git clone https://github.com/yaoweibin/nginx_upstream_check_module.git
步骤 7:复制模块到 bundle 目录
将下载的 nginx_upstream_check_module 复制到 openresty/bundle 目录下。
bash
cp -r nginx_upstream_check_module openresty/bundle/
步骤 8:配置 Nginx 编译选项
进入 Nginx 源码目录并执行配置:
bash
cd openresty/bundle/nginx-1.27.1
patch -p1 < ../nginx_upstream_check_module/check_1.20.1+.patch
./configure --prefix=/usr/local/openresty/nginx \
--with-cc-opt='-O2 -DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre2/include -I/usr/local/openresty/openssl3/include' \
--add-module=../ngx_devel_kit-0.3.3 \
--add-module=../echo-nginx-module-0.63 \
--add-module=../xss-nginx-module-0.06 \
--add-module=../ngx_coolkit-0.2 \
--add-module=../set-misc-nginx-module-0.33 \
--add-module=../form-input-nginx-module-0.12 \
--add-module=../encrypted-session-nginx-module-0.09 \
--add-module=../srcache-nginx-module-0.33 \
--add-module=../ngx_lua-0.10.28 \
--add-module=../ngx_lua_upstream-0.07 \
--add-module=../headers-more-nginx-module-0.37 \
--add-module=../array-var-nginx-module-0.06 \
--add-module=../memc-nginx-module-0.20 \
--add-module=../redis2-nginx-module-0.15 \
--add-module=../redis-nginx-module-0.3.9 \
--add-module=../ngx_stream_lua-0.0.16 \
--with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre2/lib -L/usr/local/openresty/openssl3/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre2/lib:/usr/local/openresty/openssl3/lib' \
--with-pcre-jit \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-http_v2_module \
--with-http_v3_module \
--without-mail_pop3_module \
--without-mail_imap_module \
--without-mail_smtp_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_secure_link_module \
--with-http_random_index_module \
--with-http_gzip_static_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_slice_module \
--with-http_gunzip_module \
--with-threads \
--with-compat \
--with-stream \
--with-http_ssl_module \
--add-module=../nginx_upstream_check_module \
--with-openssl=objs/lib/openssl-3.3.0
步骤 9:编译 Nginx
执行编译(注意:不执行 make install):
bash
make
编译完成后,会在 objs/ 目录下生成 nginx 可执行文件。
构建失败时的清理和重新构建
如果构建失败,需要先清理构建生成的文件,然后重新配置和构建:
- 清理构建文件:
bash
make clean
- 重新执行 OpenSSL 配置(参考步骤 5):
bash
# 返回到 openresty 根目录
cd ../../../
# 创建目标目录(如果不存在)
mkdir -p openresty/bundle/nginx-1.27.1/objs/lib/openssl-3.3.0
# 解压 OpenSSL 到目标目录
tar -xvf openssl-3.3.0.tar.gz -C openresty/bundle/nginx-1.27.1/objs/lib/openssl-3.3.0 --strip-components=1
- 重新进入 Nginx 源码目录并执行配置(参考步骤 8):
bash
cd openresty/bundle/nginx-1.27.1
patch -p1 < ../nginx_upstream_check_module/check_1.20.1+.patch
./configure --prefix=/usr/local/openresty/nginx \
--with-cc-opt='-O2 -DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre2/include -I/usr/local/openresty/openssl3/include' \
--add-module=../ngx_devel_kit-0.3.3 \
--add-module=../echo-nginx-module-0.63 \
--add-module=../xss-nginx-module-0.06 \
--add-module=../ngx_coolkit-0.2 \
--add-module=../set-misc-nginx-module-0.33 \
--add-module=../form-input-nginx-module-0.12 \
--add-module=../encrypted-session-nginx-module-0.09 \
--add-module=../srcache-nginx-module-0.33 \
--add-module=../ngx_lua-0.10.28 \
--add-module=../ngx_lua_upstream-0.07 \
--add-module=../headers-more-nginx-module-0.37 \
--add-module=../array-var-nginx-module-0.06 \
--add-module=../memc-nginx-module-0.20 \
--add-module=../redis2-nginx-module-0.15 \
--add-module=../redis-nginx-module-0.3.9 \
--add-module=../ngx_stream_lua-0.0.16 \
--with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre2/lib -L/usr/local/openresty/openssl3/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre2/lib:/usr/local/openresty/openssl3/lib' \
--with-pcre-jit \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-http_v2_module \
--with-http_v3_module \
--without-mail_pop3_module \
--without-mail_imap_module \
--without-mail_smtp_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_secure_link_module \
--with-http_random_index_module \
--with-http_gzip_static_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_slice_module \
--with-http_gunzip_module \
--with-threads \
--with-compat \
--with-stream \
--with-http_ssl_module \
--add-module=../nginx_upstream_check_module \
--with-openssl=objs/lib/openssl-3.3.0
- 重新执行编译:
bash
make
可能遇到的问题 1:编译错误 next_try 标签未定义
错误信息:
src/http/modules/ngx_http_upstream_ip_hash_module.c: In function 'ngx_http_upstream_get_ip_hash_peer':
src/http/modules/ngx_http_upstream_ip_hash_module.c:248:13: error: label 'next_try' used but not defined
248 | goto next_try;
| ^~~~
make[1]: *** [objs/Makefile:1499: objs/src/http/modules/ngx_http_upstream_ip_hash_module.o] Error 1
原因:nginx_upstream_check_module 的补丁与 Nginx 版本不兼容,导致标签名称不匹配。
解决方案:
- 编辑出错的文件:
bash
vi src/http/modules/ngx_http_upstream_ip_hash_module.c
- 找到第 248 行附近的
goto next_try;语句,将其修改为goto next;:
bash
# 在文件中搜索 next_try
# 将所有的 next_try 替换为 next
- 或者使用 sed 命令批量替换:
bash
sed -i 's/goto next_try;/goto next;/g' src/http/modules/ngx_http_upstream_ip_hash_module.c
- 验证修改是否成功:
bash
grep -n "next_try\|goto next" src/http/modules/ngx_http_upstream_ip_hash_module.c
- 重新执行编译:
bash
make
可能遇到的问题 2:编译错误 failed 标签未定义
错误信息:
src/http/ngx_http_upstream_round_robin.c: In function 'ngx_http_upstream_free_round_robin_peer':
src/http/ngx_http_upstream_round_robin.c:821:13: error: label 'failed' used but not defined
821 | goto failed;
| ^~~~
make[1]: *** [objs/Makefile:1107: objs/src/http/ngx_http_upstream_round_robin.o] Error 1
原因 :nginx_upstream_check_module 的补丁在 ngx_http_upstream_free_round_robin_peer 函数中添加了 goto failed; 语句,但缺少 failed: 标签定义。
解决方案:
- 编辑出错的文件:
bash
vi src/http/ngx_http_upstream_round_robin.c
-
找到
ngx_http_upstream_free_round_robin_peer函数,定位到函数末尾(通常在return;语句之前)。 -
在函数最后添加以下代码:
c
return;
failed:
ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
ngx_http_upstream_rr_peers_unlock(rrp->peers);
pc->tries = 0;
return;
- 或者使用 sed 命令在函数末尾添加(需要先找到函数结束位置):
bash
# 先查看函数结构
grep -n "ngx_http_upstream_free_round_robin_peer" src/http/ngx_http_upstream_round_robin.c
# 然后手动编辑添加 failed 标签和代码块
- 验证修改是否成功:
bash
grep -A 10 "failed:" src/http/ngx_http_upstream_round_robin.c
- 重新执行编译:
bash
make
注意 :如果函数末尾已经有 return; 语句,只需在其后添加 failed: 标签及相应的代码块即可。
步骤 10:备份 Nginx 二进制文件
在替换 nginx 二进制文件之前,必须先备份原有的 nginx 文件,以便在出现问题时可以快速恢复。
bash
# 停止 OpenResty 服务
systemctl stop openresty
chmod -R 777 /usr/local/openresty/nginx/sbin
# 备份原有的 nginx 二进制文件(建议使用带时间戳的文件名)
cp /usr/local/openresty/nginx/sbin/nginx /usr/local/openresty/nginx/sbin/nginx.backup.$(date +%Y%m%d_%H%M%S)
# 验证备份文件是否存在
ls -lh /usr/local/openresty/nginx/sbin/nginx.backup.*
注意:
- 备份文件名包含时间戳,便于识别备份时间
- 建议将备份文件保存到安全的位置,避免误删
- 如果后续需要恢复,可以使用备份文件替换当前文件
步骤 11:替换 Nginx 二进制文件(已安装Openresty)
将编译生成的 nginx 文件复制到 OpenResty 安装目录:
bash
# 复制新编译的 nginx 文件
cp objs/nginx /usr/local/openresty/nginx/sbin/nginx
# 验证新文件是否复制成功
ls -lh /usr/local/openresty/nginx/sbin/nginx
步骤 12:配置 Nginx 主动健康检查
编辑 /usr/local/openresty/nginx/conf/nginx.conf 文件,添加主动健康检查配置。
Nginx 配置示例
nginx
http {
# 注意:添加 LuaJIT 库路径,否则 LuaJIT 库无法找到(手动构建存在的问题)
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
# 添加主动健康检查模块
upstream portal_backend {
# IP 哈希负载均衡,负载均衡算法为 IP 哈希
ip_hash;
# 后端服务器列表
server 192.168.3.3:9091; # 第一个后端服务器 IP 和端口
server 192.168.3.4:9091; # 第二个后端服务器 IP 和端口
# 健康检查配置
# interval=3000: 检查间隔 3000 毫秒
# rise=2: 连续成功 2 次后标记为健康
# fall=3: 连续失败 3 次后标记为不健康
# timeout=1000: 检查超时时间 1000 毫秒
# type=http: 使用 HTTP 类型检查
check interval=3000 rise=2 fall=3 timeout=1000 type=http;
# 如果有健康检查请求 URL,则使用健康检查请求 URL
# check_http_send "GET /health HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n";
# 如果没有健康检查请求 URL,则使用 GET / HTTP/1.0 请求方式
check_http_send "GET / HTTP/1.0\r\n\r\n";
# 期望的健康状态响应码(2xx 和 3xx 视为健康)
check_http_expect_alive http_2xx http_3xx;
}
# 添加虚拟主机
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://portal_backend;
}
}
}
步骤 13:启动Openresty服务
bash
systemctl start openresty
健康检查参数说明
check 指令参数
- interval: 健康检查的间隔时间(单位:毫秒)
- rise: 连续成功检查次数,达到此次数后服务器被标记为健康
- fall: 连续失败检查次数,达到此次数后服务器被标记为不健康
- timeout: 单次检查的超时时间(单位:毫秒)
- type : 检查类型,支持
http、tcp、ssl_hello等
check_http_send 指令
定义发送给后端服务器的健康检查请求。可以根据实际情况自定义请求路径和请求头。
check_http_expect_alive 指令
定义哪些 HTTP 状态码被视为健康响应。常用值:
http_2xx: 2xx 状态码http_3xx: 3xx 状态码http_4xx: 4xx 状态码http_5xx: 5xx 状态码
验证配置
- 检查 Nginx 配置语法:
bash
/usr/local/openresty/nginx/sbin/nginx -t
- 重新加载 Nginx 配置:
bash
/usr/local/openresty/nginx/sbin/nginx -s reload
- 查看 Nginx 状态和日志,确认健康检查是否正常工作。
注意事项
-
LuaJIT 路径配置 :手动构建时,必须正确配置
lua_package_path和lua_package_cpath,否则 LuaJIT 库无法正常加载。 -
备份原文件:替换 nginx 二进制文件前,必须按照步骤 9 进行备份,以便出现问题时可以快速恢复。建议将备份文件保存到安全位置。
-
版本兼容性:确保 OpenResty、LuaJIT、OpenSSL 和 nginx_upstream_check_module 的版本兼容。
-
防火墙配置:确保健康检查请求能够正常访问后端服务器。
-
性能影响:健康检查会增加一定的系统负载,建议根据实际情况调整检查间隔。
-
日志监控:建议定期查看 Nginx 错误日志,及时发现健康检查相关的问题。
常见问题
Q1: 编译时提示找不到 LuaJIT 头文件
解决方案 :检查环境变量 LUAJIT_INC 是否正确设置,并确保已执行 source ~/.bashrc。
Q2: 健康检查不生效
解决方案:
- 检查 nginx_upstream_check_module 是否正确编译到 nginx 中
- 检查 nginx.conf 配置语法是否正确
- 查看 Nginx 错误日志获取详细信息
Q3: 后端服务器被误判为不健康
解决方案:
- 调整
rise和fall参数,增加容错性 - 检查后端服务器的响应时间和状态码
- 确认
check_http_expect_alive配置是否合理
Q4: 启动时提示 resty.core 模块加载失败
错误信息:
nginx: [alert] failed to load the 'resty.core' module (https://github.com/openresty/lua-resty-core);
ensure you are using an OpenResty release from https://openresty.org/en/download.html
(reason: module 'resty.core' not found:
no field package.preload['resty.core']
no file './resty/core.lua'
no file '/usr/local/openresty/luajit/share/luajit-2.1/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core/init.lua'
no file '/usr/local/openresty/luajit/share/lua/5.1/resty/core.lua'
no file '/usr/local/openresty/luajit/share/lua/5.1/resty/core/init.lua'
no file './resty/core.so'
no file '/usr/local/lib/lua/5.1/resty/core.so'
no file '/usr/local/openresty/luajit/lib/lua/5.1/resty/core.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
no file './resty.so'
no file '/usr/local/lib/lua/5.1/resty.so'
no file '/usr/local/openresty/luajit/lib/lua/5.1/resty.so'
no file '/usr/local/lib/lua/5.1/loadall.so')
原因 :手动构建的 OpenResty 无法找到 LuaJIT 库路径,导致 resty.core 模块加载失败。
解决方案:
在 nginx 配置文件的 http 配置项最开始的位置添加 LuaJIT 库路径配置:
nginx
http {
# 注意:添加 LuaJIT 库路径,否则 LuaJIT 库无法找到(手动构建存在的问题)
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
# 其他配置...
}
重要提示:
- 这两行配置必须放在
http块的最开始位置,在其他配置之前 - 配置修改后,需要重新加载或重启 Openresty 服务才能生效
- 如果问题仍然存在,请检查
/usr/local/openresty/lualib/目录是否存在,以及该目录下是否包含resty相关的 Lua 文件