详细编译过程记录及调优
CentOS7 下 Openresty-1.17.8 的编译安装
- openResty (也称为 ngx_openresty)是一个全功能的 Web 应用服务器,它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。 OpenResty 通过汇聚各种设计精良的 Nginx 模块, 从而将 Nginx 有效的变成一个强大的 Web 应用服务器, 这样, Web 开发人员可以使用 Lua 脚本语言调动 nginx 支持的各种 C 以及 Lua 模块, 快速构造出足以胜任 10K+ 并发连接响应的超高性能 Web 应用系统。
- openresty 可以使用 Linux 的包管理器直接安装(需配置额外的源),可以编译安装;前者较为便捷,但是不便于个性化定制和大范围部署时的版本统一管理;生产环境还是建议自行编译安装,以下为 Openresty-1.17.8 的编译安装说明,为嘛选择 1.17.8 而不是最新的 1.19?个人觉得次新版既能保证新的特性,又经过较长时间的验证,更适合生产环境使用;
- 在编译 openresty 的时候一定注意和官方 nginx 的区别:openresty 内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项,且默认编译(如需禁用使用–without 选项禁用),所以有些在编译 nginx 时需要使用–add-module 参数额外添加的 module 在编译 openresty 的时候时不需要的;
- 以下主配置文件中并未启用本地使用缓存功能,因为 Nginx 本地使用缓存功能且使用 CDN 回源的时候,发布了静态资源后可能导致不能及时回源,建议在这种场景下关闭缓存,毕竟 CDN 已经起到了缓存的作用且离用户更近;
一、基础知识:
1、部分内置模块说明:
可用:
./configure --help
查看当前版本支持启用/禁用的模块列表
- ========** 启用模块 **=======
- –with-compat:启用动态加载模块兼容模式,不需要替换 nginx 文件即可增加第三方扩展(只有部分模块支持该特性)
- –with-threads:启用多线程支持
- –with-file-aio:启用文件的异步 IO 支持,对大文件采用 aio 线程池进行发送,提高内存利用效率;
- –with-http_v2_module:开启 http1.2 支持
- –with-http_ssl_module:启用 HTTPS 支持
- –with-pcre:强制使用 pcre(兼容 perl),用以支持 rewrite 重写
- –with-pcre-jit:正则表达式引擎 pcre 启用 JIT(即时编译)支持,比不使用快好几倍
- –with-http_realip_module:该模块允许更改请求头中的客户端的 IP;可以过滤掉 Nginx 服务前的代理服务器,获得客户端的真实 IP;
- –with-http_addition_module:用以支持在响应之前或者之后追加文本内容
- –with-http_gunzip_module:启用压缩支持,用以支持静态文件压缩;
- –with-http_gzip_static_module:启用在线实时压缩输出数据流支持
- –with-http_auth_request_module:使 nginx 可以基于后端 http 响应状态码做权限控制;使允许添加第三方的认证源,如 LDAP
- –with-http_random_index_module:开启随机目录索引支持()
- –with-http_secure_link_module:指定并允许检查请求的链接的真实性以及保护资源免遭未经授权的访问,用于实现防盗链
- –with-http_slice_module:可以将一个 http 请求拆分为多个,每个请求返回响应内容的一部分,使大文件的缓存更有效率
- –with-http_iconv_module:为 nginx 添加 set_iconv 命令,用以支持编码字符转换
- –with-http_degradation_module:服务降级,允许在内存不足的情况下返回 204 或 444 码,在负载均衡的情况下可以为调度提供依据
- –with-http_stub_status_module:用于监控 nginx 当前的连接信息等状态
- –with-stream=dynamic:启用 tcp/udp 代理模块,dynamic 参数表示动态加载:即可以 make 编译后不用 install 替换原 nginx 可执行文件,通过 load_module 导入模块
- –with-stream_ssl_module
- –with-stream_realip_module
- –with-stream_geoip_module=dynamic
- –with-stream_ssl_preread_module
- ========** 禁用模块 **=======
- –without-lua_resty_memcached:不编译 Memcached 客户端模块
- –without-http_memcached_module:不编译 Memcached 操作支持模块
- –without-lua_resty_mysql:不编译 MySQL 操作支持模块
- –without-lua_redis_parser:不编译 redis 支持模块
- –without-lua_resty_redis:不编译 redis 支持模块
- –without-http_redis_module:不编译 redis 支持模块
- –without-http_redis2_module:不编译 redis2 支持模块
- –without-lua_rds_parser:不编译 DBD-Stream 格式的数据解析为 Lua 数据结构模块
- –without-http_rds_csv_module:不编译 DBD-Stream 格式转 cvs 格式模块
- –without-http_rds_json_module:不编译 DBD-Stream 格式转 JSON 格式模块
- –without-mail_pop3_module:不编译邮件支持模块
- –without-mail_imap_module:不编译邮件支持模块
- –without-mail_smtp_module:不编译邮件支持模块
2、第三方模块(https://www.nginx.com/resources/wiki/modules/):
- ngx_devel_kit:使其他模块可以基于 Nginx 核心功能模块快速二次开发
- 该模块 openresty 默认内置且默认打开,无需再–add-module 添加(添加编译会报错:multiple definition);如需禁用:configure 添加–without-ngx_devel_kit_module 参数
- 参考:https://github.com/vision5/ngx_devel_kit
- nginx-lua-prometheus(该模块不用编译安装):用于通过 lua 将 nginx 指标接入 prometheus 监控,依赖 lua-nginx-module 模块(Openresty 已经默认内置)
- 参考:https://opm.openresty.org/package/knyar/nginx-lua-prometheus/
- ngx_req_status:用来展示 nginx 请求状态信息,如有哪些请求、以及各 url 域名所消耗的带宽是多少等;nginx 自带的模块只能显示连接数等信息(编译前需要打 patch);
- openresty 打 patch 操作实例:
cd /opt/openresty-1.17.8.2/bundle/nginx-1.17.8 patch -p1 < /opt/extra_modules/ngx_req_status-master/write_filter-1.7.11.patch
- 参考:https://github.com/zls0424/ngx_req_status/
- openresty 打 patch 操作实例:
- ngx_http_consistent_hash:用来支持通过一致性哈希算法来选择合适的后端节点
- 参考:https://github.com/replay/ngx_http_consistent_hash
二、详细编译过程
- 如果已有 nginx 可执行文件有的话,备份(重命名添加.backup 后缀):
# search
whereis nginx
# backup
[[ -f /usr/sbin/nginx && ! -L /usr/sbin/nginx ]] && mv /usr/sbin/nginx{,.backup}
- 预安装编译环境:
yum install readline-devel pcre-devel openssl-devel gcc perl -y
- 添加进程用户(不创建家目录,不允许登录):
groupadd nginx && useradd -s /sbin/nologin -M -g nginx nginx
- 下载源码:
# 安装包下载地址:http://openresty.org/cn/download.html
cd /opt && wget https://openresty.org/download/openresty-1.17.8.2.tar.gz
- 解压:
tar -zxvf openresty-1.17.8.2.tar.gz
- 准备需要的第三方模块源码目录和安装文件
mkdir /opt/extra_modules && cd /opt/extra_modules
# 从各个模块的Github仓库下载对应源码的zip包解压即可,这里就不贴了
- 安装 ngx_req_status 模块前需要打 patch:
cd /opt/openresty-1.17.8.2/bundle/nginx-1.17.8
patch -p1 < /opt/extra_modules/ngx_req_status-master/write_filter-1.7.11.patch
- 执行编译:
# 切换编译目录:
cd /opt/openresty-1.17.8.2
# configure(各选项说明参见上文)
./configure --prefix=/usr/local/openresty \
--user=nginx \
--group=nginx \
--pid-path=/var/run/nginx.pid \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--with-threads \
--with-file-aio \
--with-pcre \
--with-pcre-jit \
--with-http_v2_module \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_secure_link_module \
--with-http_degradation_module \
--with-http_iconv_module \
--with-http_stub_status_module \
--without-lua_resty_memcached \
--without-http_memcached_module \
--without-lua_resty_mysql \
--without-lua_redis_parser \
--without-lua_resty_redis \
--without-http_redis_module \
--without-http_redis2_module \
--without-lua_rds_parser \
--without-http_rds_csv_module \
--without-http_rds_json_module \
--without-mail_pop3_module \
--without-mail_imap_module \
--without-mail_smtp_module \
--add-module=/opt/extra_modules/ngx_http_consistent_hash-master \
--add-module=/opt/extra_modules/ngx_req_status-master
# make
gmake
# make install
gmake install
- 功能或易用性配置:
# 创建可执行文件软连接:
ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/sbin/nginx
# 创建相关目录并授权:
mkdir /var/cache/nginx/ && chown -R nginx:nginx /var/cache/nginx/
# 创建被包含的子配置目录以及lua脚本目录:
mkdir /usr/local/openresty/nginx/conf/conf.d && mkdir /usr/local/openresty/nginx/conf/lua
# 修改日志目录权限:
chown -R nginx:nginx /var/log/nginx
- 初始化主配置文件:
cat >/usr/local/openresty/nginx/conf/nginx.conf << EOF
# 指定启动nginx使用的用户(不指定为nobody)
user nginx nginx;
# 定义作为web服务器/反向代理服务器时的 worder process 进程数
worker_processes auto;
# 开启多核支持,且自动根据CPU个数均匀分配 worder process 进程数
worker_cpu_affinity auto;
# 指定一个nginx进程可以打开的最多文件描述符数目
worker_rlimit_nofile 65535;
# error_log配置,等级类型:[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log notice;
# nginx的进程pid位置;
pid /var/run/nginx.pid;
# 连接处理相关设置
events{
# 使用epoll的 I/O 模型,必开项,极其有利于性能
use epoll;
# 设置是否允许一个worker可以接受多个请求,默认是off;
# 值为OFF时,一个worker process进程一次只接收一个请求,由master进程自动分配worker(nginx精于此道,故建议设置为off);
# 值为ON则一次可接收所有请求,可避免master进程额外调度,但是在高瞬时值的情况下可能导致tcp flood;
multi_accept off;
# 每个工作进程的并发连接数(默认为1024)
# 理论上nginx最大连接数 = worker_processes * worker_connections
worker_connections 65535;
}
http {
# mime.types 指定了nginx可以接受的 Content-Type,该文件默认位于nginx.conf的同级目录
include mime.types;
# 设置默认文件类型,application/octet-stream 表示未知的应用程序文件,浏览器一般不会自动执行或询问执行
default_type application/octet-stream;
# 设置日志的记录格式
log_format main escape=json '{ "time": "\$time_iso8601", '
'"remote_addr": "\$remote_addr", '
'"status": "\$status", '
'"bytes_sent": "\$bytes_sent", '
'"host": "\$host", '
'"request_method": "\$request_method", '
'"request_uri": "\$request_uri", '
'"request_time": "\$request_time", '
'"response_time": "\$upstream_response_time",'
'"http_referer": "\$http_referer", '
'"body_bytes_sent": "\$body_bytes_sent", '
'"http_user_agent": "\$http_user_agent", '
'"http_x_forwarded_for": "\$http_x_forwarded_for", '
'"cookie": "\$http_cookie" '
'}';
# 用来指定日志文件的存放路径及内容格式
access_log /var/log/nginx/access.log main;
# 不记录404错误的日志
log_not_found off;
# 隐藏nginx版本号
server_tokens off;
# 开启0拷贝,提高文件传输效率
sendfile on;
# 配合 sendfile 使用,启用后数据包会累计到一定大小之后才会发送,减小额外开销,提高网络效率;
tcp_nopush on;
# 启用后表示禁用 Nagle 算法,尽快发送数据
# 与 tcp_nopush 结合使用的效果是:先填满包,再尽快发送
# Nginx 只会针对处于 keep-alive 状态的 TCP 连接才会启用 tcp_nodelay
tcp_nodelay on;
# 指定客户端与服务端建立连接后发送 request body 的超时时间,超时Nginx将返回http 408
client_body_timeout 10;
# 开启从client到nginx的连接长连接支持,指定每个 TCP 连接最多可以保持多长时间
# keepalive_timeout的值应该比 client_body_timeout 大
keepalive_timeout 60;
# keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接将被关闭
keepalive_requests 1000;
# 客户端请求头部的缓冲区大小,设置等于系统分页大小即可,如果header过大可根据实际情况调整;
# 查看系统分页:getconf PAGESIZE
client_header_buffer_size 32k;
# 设置客户端请求的Header头缓冲区大小,如果客户端的Cookie信息较大,按需增加
large_client_header_buffers 4 64k;
# 优化读取\$request_body变量时的I/O性能
client_body_in_single_buffer on;
# 设定request body的缓冲大小,仅在 Nginx被设置成使用内存缓冲时有效(使用文件缓冲时该参数无效)
client_body_buffer_size 128k;
# 开启proxy忽略客户端中断,避免499错误
proxy_ignore_client_abort on;
# 默认的情况下nginx引用header变量时不能使用带下划线的变量,设置underscores_in_headers为 on取消该限制
underscores_in_headers on;
# 默认的情况下nginx会忽略带下划线的变量,设置ignore_invalid_headers为off取消该限制
ignore_invalid_headers off;
# 设置客户端向服务端发送一个完整的 request header 的超时时间,优化弱网场景下nginx的性能
client_header_timeout 10;
# 设置向客户端传输数据的超时时间
send_timeout 60;
# 用于启用文件功能时用限制文件大小;
client_max_body_size 50m;
# 文件压缩配置,对文本文件效果较好,对图像类应用效果一般反而徒增服务器资源消耗
gzip on;
# 兼容http 1.0
gzip_http_version 1.0;
# 压缩比,数值越大:压缩的程度越高、空间占用越低、压缩效率越低、资源消耗越大
gzip_comp_level 6;
# 设置压缩门限,小于该长度将不会进行压缩动作(数据过小的情况下,压缩效果不明显)
gzip_min_length 1k;
# 用于在nginx作为反向代理时,根据请求头中的“Via”字段决定是否启用压缩功能,默认值为off,any表示对所有请求启动压缩;
gzip_proxied any;
# 用于在启动gzip压缩功能时,在http响应中添加Vary: Accept-Encoding头字段告知接收方使用了gzip压缩;
gzip_vary on;
# 当Agent为IE6时禁用压缩:IE6对Gzip不友好,所以不压缩
gzip_disable msie6;
# 设置系统用于存储gzip的压缩结果数据流的缓存大小(4 4k 代表以4k为单位,按照原始数据大小以4k为单位的4倍申请内存)
gzip_buffers 4 64k;
# 指定需要压缩的文件mime类型
gzip_types text/xml text/plain text/css application/javascript application/x-javascript application/xml application/json application/rss+xml;
# 作为反向代理服务器配置
# 当请求未携带“Host”请求头时将Host设置为虚拟主机的主域名
proxy_set_header Host \$host;
# 设置真实客户端IP
proxy_set_header X-Real-IP \$remote_addr;
# 简称XFF头,即HTTP的请求端真实的IP,在有前置cdn或者负载均衡可能会被修改;如果要提取客户端真实IP,需要根据实际情况调整,如若后端程序获得对X-Forwarded-For兼容性不好的话(没有考虑到X-Forwarded-For含有多个IP的情况),建议设置为:\$http_x_forwarded_for
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
# 启用nginx和后端server(upstream)之间长连接支持(必设项,否则很影响nginx性能),HTTP协议中从1.1版本才支持长连接;启用时需要评估upstream的keepalive参数(默认是关闭的,比较懒的同学可以设置为500)
proxy_http_version 1.1;
# 为了兼容老的协议以及防止http头中有Connection close导致的keepalive失效,需要及时清掉HTTP头部的Connection;
# 该参数决定了访问完成后,后端server后如何处理本次连接,默认配置是主动close(会给后端server带来大量的TIME_WAIT连接,降低后端server性能),设置为""结合proxy_http_version设置连接保持(长连接);
proxy_set_header Connection "";
# 用于对发送给客户端的URL进行修改,使用不到的话可以关闭
proxy_redirect off;
# 设置缓冲区的大小和数量,用于放置被代理的后端服务器取得的响应内容
proxy_buffers 64 8k;
# 设置和后端建立连接的超时时间,单位秒
proxy_connect_timeout 60;
# 设置Nginx向后端被代理服务器发送read请求后,等待响应的超时时间,默认60秒
proxy_read_timeout 60;
# 设置Nginx向后端被代理服务器发送write请求后,等待响应的超时时间,默认60秒
proxy_send_timeout 60;
# 用于配置存放HTTP报文头的哈希表容量,默认为512个字符。一般都设置为1024,这个大小是哈希表的总大小,
#设定了这个参数Nginx不是一次全部申请出来,需要用的时候才会申请;
#但是当真正需要使用的时候也不是一次全部申请,而是会设置一个单次申请最大值(proxy_headers_hash_bucket_size)
proxy_headers_hash_max_size 1024;
# 用于设置Nginx服务器申请存放HTTP报文头的哈希表容量的单位大小,默认为64个字符。一般配置为128。
#这个大小是单次申请最多申请多大,也就是每次用需要申请,但是每次申请最大申请多少,整个哈希表大小不可超过上面设置的值。
proxy_headers_hash_bucket_size 128;
# 设置缓存临时目录
proxy_temp_path /var/cache/nginx/proxy_temp;
# 设置缓存目录、目录结构及缓存数据保留策略
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=cache_one:512m inactive=1d max_size=2g;
# 预防 DDOS 攻击配置策略
#limit_req_zone \$binary_remote_addr zone=req:20m rate=3r/s;
#limit_req zone=req burst=60;
#limit_zone conn \$binary_remote_addr 20m;
#limit_conn conn 5;
#limit_rate 50k;
# 设置nginx可以捕获的服务器名字(server_name)的最大数量
server_names_hash_max_size 1024;
# 设置nginx中server_name支持的最大长度
server_names_hash_bucket_size 128;
include conf.d/*.conf;
}
EOF
- 配置检验与启动:
# 配置校验
nginx -t
# 启动:
systemctl start nginx
- 实际使用: 创建 conf.d 目录,并在创建响应 conf 文件,重启 nginx 检查响应端口监听状态及应用接口是否正常;
mkdir /usr/local/openresty/nginx/conf/conf.d
三、设置日志轮转:
默认情况下 nginx 的日志只写不删,长期运行可能会耗尽磁盘空间导致运行故障,我们使用 logrotate 工具对 nginx 日志进行限期保存(7 天),配置如下:
cat > /etc/logrotate.d/nginx << EOF
/var/log/nginx/*.log {
daily
dateext
create
rotate 7
notifempty
sharedscripts
prerotate
if [ -d /etc/logrotate.d/nginx ]; then run-parts /etc/logrotate.d/nginx; fi
endscript
postrotate
[ ! -f /var/run/nginx.pid ] || kill -USR1 \`cat /var/run/nginx.pid\`
endscript
}
EOF
四、设置开机自启
只有 root 用户有权限监听 1024 以下端口号,为了监听 80 和 443,我们使用 root 用户启动 nginx 主进程
cat > /etc/systemd/system/nginx.service << EOF
[Unit]
Description=Nginx(OpenResty ) - high performance web server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
User=root
Group=root
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/local/openresty/nginx/sbin/nginx -t -c /usr/local/openresty/nginx/conf/nginx.conf
ExecStart=/usr/local/openresty/nginx/sbin/nginx -c /usr/local/openresty/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP \$MAINPID
ExecStop=/bin/kill -s TERM \$MAINPID
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
# 重载 systemctl
systemctl daemon-reload && systemctl enable nginx
五、配置监控
常用的监控方案有两种:
- 一种是通过 nginx-module-vts 模块:能获取到某个模块的分域名请求数量、1xx 2xx 的请求占比,和 nginx 的进出流量;因为只能获取到简要的统计数据,如果要进行详细分析的话就显得力不从心了;
- 还有一种就是通过 nginx-lua-prometheus 模块的方式,通过 lua 脚本进行数据收集,有两种开源参考做法:
- 【No.1】:https://github.com/zrbcool/prometheus-lua-nginx (指标更详细,自己提取 lua 和 conf 配置文件到非 docker 环境即可)
- Grafana dashboard ID:10442、10443、10444、10445
- 【No.2】: https://github.com/knyar/nginx-lua-prometheus (官方收录)
- Grafana dashboard ID:10223
- 【No.1】:https://github.com/zrbcool/prometheus-lua-nginx (指标更详细,自己提取 lua 和 conf 配置文件到非 docker 环境即可)
- 基于https://github.com/zrbcool/prometheus-lua-nginx的非容器化改造,假设已有Prometheus + Grafana 环境:
- 创建 lua 配置目录:
[[ -d /usr/local/openresty/nginx/conf/lua ]] || mkdir /usr/local/openresty/nginx/conf/lua
- 在 nginx.conf 主配置文件 include 的配置目录(此处为 conf.d)中创建配置文件:
touch counter.conf
,内容参考:https://github.com/zrbcool/prometheus-lua-nginx/blob/master/workdir/conf.d/counter.conf- 改动 1:luapackage_path 的值改为:“/usr/local/openresty/nginx/conf/lua/?.lua;;”;_
- 改动 2:luacode_cache 的值修改为: _on;
lua_code_cache 设置为 off 的话,修改完代码后,不用 reload Nginx 就可以生效(OpenResty 会给每个请求创建新的 Lua VM。由于没有 Lua module 的缓存,新的 VM 会去加载刚最新的 Lua 文件);生产环境下建议设置为 on;
- 在 lua 配置目录中创建 counter.lua 和 prometheus.lua 配置文件,内容参考(直接复制即可): https://github.com/zrbcool/prometheus-lua-nginx/tree/master/workdir/lua
- 配置语法测试:
nginx -t
- 重启 nginx:
systemctl restart nginx
- 验证 metric 接口:
curl "http://127.0.0.1:9145/metrics"
初始化情况下只会输出一个 nginx_metric_errors_total 为 0 的 metric,运行一段时间后会丰富起来;
- promtheus 配置增加四个记录规则文件:nginx.counter.rule、nginx.errrate.rule、nginx.latency.rule、nginx.qps.rule(必选,否则 Grafana 一部分图表没有数据);一个告警规则(可选):nginx.alert.rule,文件内容参考: https://github.com/zrbcool/prometheus-lua-nginx/tree/master/docker/prometheus
- 在 prometheus 配置文件的 rule_files 配置块中加载上述规则文件:
- "nginx.*.rule"
- 在 Grafana 中创建 dashboard(导入对应 id);nginx 运行一段时间后看监控效果;
- 创建 lua 配置目录: