OpenResty + nginx_upstream_check_module 构建主动健康检查模块

概述

本文档详细说明如何构建 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 可执行文件。

构建失败时的清理和重新构建

如果构建失败,需要先清理构建生成的文件,然后重新配置和构建:

  1. 清理构建文件
bash 复制代码
make clean
  1. 重新执行 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
  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
  1. 重新执行编译
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 版本不兼容,导致标签名称不匹配。

解决方案

  1. 编辑出错的文件:
bash 复制代码
vi src/http/modules/ngx_http_upstream_ip_hash_module.c
  1. 找到第 248 行附近的 goto next_try; 语句,将其修改为 goto next;
bash 复制代码
# 在文件中搜索 next_try
# 将所有的 next_try 替换为 next
  1. 或者使用 sed 命令批量替换:
bash 复制代码
sed -i 's/goto next_try;/goto next;/g' src/http/modules/ngx_http_upstream_ip_hash_module.c
  1. 验证修改是否成功:
bash 复制代码
grep -n "next_try\|goto next" src/http/modules/ngx_http_upstream_ip_hash_module.c
  1. 重新执行编译:
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: 标签定义。

解决方案

  1. 编辑出错的文件:
bash 复制代码
vi src/http/ngx_http_upstream_round_robin.c
  1. 找到 ngx_http_upstream_free_round_robin_peer 函数,定位到函数末尾(通常在 return; 语句之前)。

  2. 在函数最后添加以下代码:

c 复制代码
    return;

failed:

    ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
    ngx_http_upstream_rr_peers_unlock(rrp->peers);

    pc->tries = 0;
    return;
  1. 或者使用 sed 命令在函数末尾添加(需要先找到函数结束位置):
bash 复制代码
# 先查看函数结构
grep -n "ngx_http_upstream_free_round_robin_peer" src/http/ngx_http_upstream_round_robin.c
# 然后手动编辑添加 failed 标签和代码块
  1. 验证修改是否成功:
bash 复制代码
grep -A 10 "failed:" src/http/ngx_http_upstream_round_robin.c
  1. 重新执行编译:
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 : 检查类型,支持 httptcpssl_hello

check_http_send 指令

定义发送给后端服务器的健康检查请求。可以根据实际情况自定义请求路径和请求头。

check_http_expect_alive 指令

定义哪些 HTTP 状态码被视为健康响应。常用值:

  • http_2xx: 2xx 状态码
  • http_3xx: 3xx 状态码
  • http_4xx: 4xx 状态码
  • http_5xx: 5xx 状态码

验证配置

  1. 检查 Nginx 配置语法:
bash 复制代码
/usr/local/openresty/nginx/sbin/nginx -t
  1. 重新加载 Nginx 配置:
bash 复制代码
/usr/local/openresty/nginx/sbin/nginx -s reload
  1. 查看 Nginx 状态和日志,确认健康检查是否正常工作。

注意事项

  1. LuaJIT 路径配置 :手动构建时,必须正确配置 lua_package_pathlua_package_cpath,否则 LuaJIT 库无法正常加载。

  2. 备份原文件:替换 nginx 二进制文件前,必须按照步骤 9 进行备份,以便出现问题时可以快速恢复。建议将备份文件保存到安全位置。

  3. 版本兼容性:确保 OpenResty、LuaJIT、OpenSSL 和 nginx_upstream_check_module 的版本兼容。

  4. 防火墙配置:确保健康检查请求能够正常访问后端服务器。

  5. 性能影响:健康检查会增加一定的系统负载,建议根据实际情况调整检查间隔。

  6. 日志监控:建议定期查看 Nginx 错误日志,及时发现健康检查相关的问题。

常见问题

Q1: 编译时提示找不到 LuaJIT 头文件

解决方案 :检查环境变量 LUAJIT_INC 是否正确设置,并确保已执行 source ~/.bashrc

Q2: 健康检查不生效

解决方案

  • 检查 nginx_upstream_check_module 是否正确编译到 nginx 中
  • 检查 nginx.conf 配置语法是否正确
  • 查看 Nginx 错误日志获取详细信息

Q3: 后端服务器被误判为不健康

解决方案

  • 调整 risefall 参数,增加容错性
  • 检查后端服务器的响应时间和状态码
  • 确认 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 文件

相关资源


相关推荐
林疏safe1 天前
信息系统安全突发事件应急预案
运维·服务器·网络
UCH1HA1 天前
mysqlbinlog基本用法
linux·运维·mysql
鸽鸽程序猿1 天前
【JavaEE】【SpringCloud】负载均衡_LoadBalancer
spring cloud·java-ee·负载均衡
工程师老罗1 天前
Ubuntu下怎么将u盘格式化为ext4?
linux·运维·ubuntu
study_小达人1 天前
ubuntu 22.04设置limit不生效
linux·运维·ubuntu
烈焰飞鸟1 天前
华为云前后端部署实战手册
运维·前端·vue.js·后端·华为云
少云清1 天前
【接口测试】7_接口测试 _Jenkins源码管理问题
运维·jenkins
qinyia1 天前
如何安全清理以 amis 开头的容器与镜像
运维·数据库·人工智能·mysql·ssh
Data_agent1 天前
Eastmallbuy模式淘宝/1688代购系统搭建指南
java·运维·数据库