准备工作
Linux操作系统
首先我们需要一个内核为Linux 2.6及以上版本的操作系统,因为Linux 2.6及以上内核才支持epoll,而在Linux上使用select或poll来解决事件的多路复用,是无法解决高并发压力问题的。
$ uname -a
Linux localhost.localdomain 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
内核版本是3.10.0,满足
使用nginx的必备软件
# gcc、g++编译器
yum install -y gcc # 安装gcc编译器
yum install -y gcc-c++ # 安装g++编译器
# PCRE库
yum install -y pcre pcre-devel
# zlib库
yum install -y zlib zlib-devel
# OpenSSL开发库
yum install -y openssl openssl-devel
(1)GCC/G++编译器
(2)PCRE库
- PCRE(Perl Compatible Regular Expressions,Perl兼容正则表达式)是由Philip Hazel开发的函数库,目前为很多软件所使用,该库支持正则表达式。它由RegEx演化而来,实际上,Perl正则表达式也是源自于Henry Spencer写的RegEx。
- 如果我们在配置文件nginx.conf里使用了正则表达式,那么在编译Nginx时就必须把PCRE库编译进Nginx,因为Nginx的HTTP模块要靠它来解析正则表达式。当然,如果你确认不会使用正则表达式,就不必安装它。
- pcre-devel是使用PCRE做二次开发时所需要的开发库,包括头文件等,这也是编译Nginx所必须使用的。
(3)zlib库
- zlib库用于对HTTP包的内容做gizp格式的压缩,如果我们在nginx.conf里配置了gzip on,并指定对于某些类型(context-type)的HTTP响应使用gzip来进行压缩以减少网络传输量,那么,在编译时候就必须把zlib编译进Nginx
- 同理,zlib是直接使用的库,zlib-devel是二次开发所需要的库。
(4)OpenSSL开发库
- 如果我们的服务器不只是需要支持http,还需要在更安全的ssl协议上传输http,那么就需要安装OpenSSL。
- 另外,如果我们想要使用MD5、SHA1等散列函数,那么也需要安全它
说明:
- 上面所列的四个库只是完成Web服务器最基本功能所必须的。
- nginx是高度自由化的web服务器,它的功能是由很多模块来支持的。而这些模块可以根据我们的使用需求来定制,如果某些模块不需要使用则完全不必理会它。
linux内核参数的优化(待验证)
下面仅针对最通用的,使得nginx支持更多并发请求的TCP网络参数做说明。
(1)首先,需要修改/etc/sysctl.conf来更改内核参数。例如,最常用的配置:
fs.file-max = 999999
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 1024 61000
net.ipv4.tcp_rmem = 4096 32768 262142
net.ipv4.tcp_wmem = 4096 32768 262142
net.core.netdev_max_backlog = 8096
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 2097152
net.core.wmem_max = 2097152
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn.backlog=1024
- file-max:这个参数表示进程可以同时打开的最大句柄数,这个参数直接限制最大并发连接数,需要根据实际情况配置
- tcp_tw_reuse :这个参数设置为1,表示允许将TIME_WAIT状态的socket重新用于新的TCP连接,这对于服务器来说很有意义,因为服务器上总会有大量TIME-WAIT状态的连接
- tcp_keepalive_time:这个参数表示当前keepalive启用时,TCP发送keepalive消息的额度,默认是2小时,如果将其设置的小一些,可以更快的清理无效的连接
- tcp_fin_timeout :这个参数表示当服务器主动关闭连接时,socket保持在FIN-WAIT-2状态的最大时间
- tcp_max_tw_buckets:这个参数表示操作系统允许TIME_WAIT套接字数量的最大值,如果超过这个数字,TIME_WAIT套接字将累计被清除并打印警告信息。该参数默认为18000,过多的TIME_WAIT套接字将会使得web服务器变慢
- tcp_max_syn_backlog:这个参数表示TCP三次握手建立节点接收SYN请求队列的最大长度,默认为1024,将其设置的大一些可以使出现的nginx繁忙来不及accept新连接的情况时,linux不至于丢失客户端发起的连接请求
- ip_local_port_range:这个参数定义了在UDP和TCP连接中本地(不包括连接的远端)端口的取值范围
- net.ipv4.tcp_rmem:这个参数定义了TCP接收缓存(用于TCP接收滑动窗口)的最小值、默认值、最大值。
- net.ipv4.tcp_wmem:这个参数定义了TCP发送缓存(用于TCP发送滑动窗口)的最小值、默认值、最大值。
- netdev_max_backlog:当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。这个参数表示该队列的最大值
- rmem_default:这个参数表示内核套接字接收缓存区默认的大小。
- wmem_default:这个参数表示内核套接字发送缓存区默认的大小。
- rmem_max:这个参数表示内核套接字接收缓冲区的最大大小
- wmem_max:这个参数表示内核套接字发送缓冲区的最大大小
- tcp_syncookies:该参数与性能无关,用于解决TCP的SYN攻击。
注意:滑动窗口的大小与套接字缓冲区会在一定程度上影响并发连接的数字。每个TCP连接都会为维护TCP滑动窗口而消耗内存,这个窗口会根据服务器的处理速度收缩或扩张。
- 参数wmem_max的设置,需要平衡物理内存的总大小、Nginx并发处理的最大连接数量(由nginx.conf中的worker_processes和worker_connections参数决定)而确定。
- 当然,如果仅仅为了提高并发量使服务器不出现Out Of Memory问题而去降低滑动窗口大小,那么并不合适,因为滑动窗口过小会影响大数据量的传输速度。
- rmem_default、wmem_default、rmem_max、wmem_max这4个参数的设置需要根据我们的业务特性以及实际的硬件成本来综
合考虑
(2)然后执行sysctl-p命令,使上述修改生效。
开始安装
需要准备的目录
(1)Nginx源代码存放目录:
- 该目录用于放置从官网上下载的Nginx源码文件,以及第三方或我们自己所写的模块源代码文件
(2)Nginx编译阶段产生的中间文件存放目录
- 该目录用于放置在configure命令执行后所生成的源文件及目录,以及make命令执行后生
成的目标文件和最终连接成功的二进制文件。 - 默认情况下,configure命令会将该目录命名为objs,并放在Nginx源代码目录下。
(3)部署目录
- 该目录存放实际Nginx服务运行期间所需要的二进制文件、配置文件等
- 默认情况下,该目录为/usr/local/nginx。
(4)日志文件存放目录
- 日志文件通常会比较大,当研究Nginx的底层架构时,需要打开debug级别的日志
- 这个级别的日志非常详细,会导致日志文件的大小增长得极快,需要预先分配一个拥有更大磁盘空间的目录
下载源码
- 下载地址。下载的版本是 nginx-1.20.2.tar.gz,放在我们准备的【Nginx源代码存放目录】下,并解压
$ ls
nginx-1.20.2.tar.gz
$ tar -zvxf nginx-1.20.2.tar.gz
解压之后得到的目录是:
$ cd nginx-1.20.2/
$ ls -l
总用量 792
drwxr-xr-x. 6 oceanstar oceanstar 4096 3月 18 10:24 auto
-rw-r--r--. 1 oceanstar oceanstar 312251 11月 16 22:44 CHANGES
-rw-r--r--. 1 oceanstar oceanstar 476577 11月 16 22:44 CHANGES.ru
drwxr-xr-x. 2 oceanstar oceanstar 168 3月 18 10:24 conf
-rwxr-xr-x. 1 oceanstar oceanstar 2590 11月 16 22:44 configure
drwxr-xr-x. 4 oceanstar oceanstar 72 3月 18 10:24 contrib
drwxr-xr-x. 2 oceanstar oceanstar 40 3月 18 10:24 html
-rw-r--r--. 1 oceanstar oceanstar 1397 11月 16 22:44 LICENSE
drwxr-xr-x. 2 oceanstar oceanstar 21 3月 18 10:24 man
-rw-r--r--. 1 oceanstar oceanstar 49 11月 16 22:44 README
drwxr-xr-x. 9 oceanstar oceanstar 91 3月 18 10:24 src
- auto/:包含了很多会在configure进行编译配置时调用的检测代码
- CHANGES:nginx的版本更新细节记录,英文版
- CHANGES.ru:nginx的版本更新细节记录,俄文版
- conf/:nginx提供的一些默认配置文件
- configure:根据系统环境设置nginx编译选项的执行脚本
- contrib/:网友贡献的一些有用脚本
- html/:提供了两个默认的HTML页面,比如index,html的welcome to nginx
- LICENSE:许可协议
- man/:nginx的man手册,可以用vi打开
- README:内容很简单,告知了一下官网地址
- src/:源码地址
编译安装nginx。
$ ./configure
$ make
$ make install
configure命令做了大量的幕后工作,包括检测操作系统内核和已经安装的软件、参数的解析、中间目录的生成以及根据各种参数生成一些C源码文件,Makefile文件等
configure详解
configure的命令参数
使用help命令可以查看configure包含的参数。
./configure --help
参数主要分为五大类
路径相关的参数
编译相关的参数
依赖软件的相关参数
模块相关的参数
除了少量核心代码外,nginx完全是由各种功能模块组成的。这些模块会根据配置参数决定自己的行为。这也可以分为五大类
-
事件模块
-
默认即编译进入nginx的HTTP模块
-
默认不会编译进入nginx的HTTP模块
-
邮件代理服务器相关的mail模块
-
其他参数
其他参数
configure执行流程
configure由shell脚本编写。中间会调用<nginx-source>/auto/
目录下的脚本。
当configure执行成功时会生成objs目录,其内容如下
$ ls -l
总用量 3916
-rw-rw-r--. 1 oceanstar oceanstar 18538 3月 18 10:29 autoconf.err
-rw-rw-r--. 1 oceanstar oceanstar 40144 3月 18 10:29 Makefile
-rwxrwxr-x. 1 oceanstar oceanstar 3883384 3月 18 10:30 nginx
-rw-rw-r--. 1 oceanstar oceanstar 5537 3月 18 10:30 nginx.8
-rw-rw-r--. 1 oceanstar oceanstar 6842 3月 18 10:29 ngx_auto_config.h
-rw-rw-r--. 1 oceanstar oceanstar 657 3月 18 10:29 ngx_auto_headers.h
-rw-rw-r--. 1 oceanstar oceanstar 5856 3月 18 10:29 ngx_modules.c
-rw-rw-r--. 1 oceanstar oceanstar 32728 3月 18 10:30 ngx_modules.o
drwxrwxr-x. 9 oceanstar oceanstar 91 3月 18 10:29 src
- autoconf.err:保存configure执行过程中产生的结果。
- Makefile:./configure生成的编译脚本
- src/:用于存放编译时产生的目标文件
- ngx_auto_headers.h和ngx_auto_config.h:保存了一些宏,这两个头文件会被src/core/ngx_config.h及src/os/unix/ngx_linux_*引用
- ngx_modules.c是一个关键文件,我们需要看看它的内部结构。一个默认配置下生成的ngx_modules.c文件内容如下
- 可以看出来它就是用来定义ngx_modules数组的。
- ngx_modules数组是个非常关键的数组,它指明了每个模块在nginx中的优先级
#include <ngx_config.h>
#include <ngx_core.h>
extern ngx_module_t ngx_core_module;
extern ngx_module_t ngx_errlog_module;
......
ngx_module_t *ngx_modules[] = {
&ngx_core_module,
&ngx_errlog_module,
......
NULL
};
char *ngx_module_names[] = {
"ngx_core_module",
"ngx_errlog_module",
......
NULL
};
nginx的命令行控制
在linux中,需要使用命令行来控制nginx服务器的启动与停止、重新配置文件、回滚日志文件、平滑升级等行为。
默认情况下:
- nginx被安装在目录/usr/local/nginx/下
- 二进制文件路径为/usr/local/nginc/sbin/nginx
- 配置文件路径为/usr/local/nginx/conf/nginx.conf
nginx支持多种命令控制:
(1)默认配置文件启动(读取默认配置路径下的配置文件/usr/local/nginx/conf/nginx.conf):
/usr/local/nginx/sbin/nginx
(2)可以用-c参数指定配置文件
/usr/local/nginx/sbin/nginx -c tmpnginx.conf
(3)可以通过-g参数临时指定一些全局配置项,以使新的配置项生效
/usr/local/nginx/sbin/nginx -g "pid var/nginx/test.pid;"
- 上面命令会把pid文件写到
var/nginx/test.pid;
中 -g
参数的约束条件是指定的配置项不能与默认路径下的nginx.conf的配置项向冲突,否则无法启动。- 另一个约束条件是,以
-g
方式启动的Nginx服务执行其他命令行时,需要把-g参数也带上,否则可能出现配置项不匹配的情形。例如,如果要停止Nginx服务,那么需要执行下面代码:
/usr/local/nginx/sbin/nginx -g "pid var/nginx/test.pid;" -s stop
- 如果不带上
var/nginx/test.pid;
,那么找不到pid文件,也会出现无法提供服务的情况
(4)在不启动nginx的情况,使用-t
参数仅测试配置文件是否有错误
$ /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
- 测试配置选项时,使用-q参数可以不把error级别以下的信息输出到屏幕
$ /usr/local/nginx/sbin/nginx -t -q
(5)显示版本信息
$ /usr/local/nginx/sbin/nginx -v
nginx version: nginx/1.20.2 //Nginx的版本信息
$ /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.20.2 // Nginx的版本信息
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) //GCC编译器的版本、操作系统的版本
configure arguments: //执行configure时的参数
(6)快速停止服务
- 方法1:使用
-s stop
强制停止nginx服务:-s
参数是告诉nginx程序向正在运行的nginx服务发送信号量,nginx程序通过nginx.pid文件得到master进程的进程ID,再向运行中的master进程发送TERM信号来快速关闭nginx服务
$ /usr/local/nginx/sbin/nginx -s stop
- 方法2:先找出master的进程ID,然后通过kill命令来发送信号
$ ps -ef | grep nginx
root 54852 1 0 11:15 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nobody 54855 54852 0 11:15 ? 00:00:00 nginx: worker process
root 54865 54585 0 11:16 pts/1 00:00:00 grep --color=auto nginx
$ kill -s SIGTERM 54852 #还可以是kill -s SIGINT 54852
这两种关闭方法的效果是一样的
(7)优雅的停止服务
“优雅的”和“快速”停止服务是由区别的:
- 当快速停止服务时,worker进程与master进程在收到信号后会立即跳出循环,退出进程
- 当优雅停止服务时,首先会关闭监听端口,停止接收新的连接,然后把当前正在处理的连接全部处理完,最后在退出进程。
方法也有两个
- 方法1:
$ /usr/local/nginx/sbin/nginx -s quit
- 方法2:
kill -s SIGQUIT <nginx master pid>
如果不想退出主进程,只想优雅的停止某个worker进程,怎么办呢?
kill -s SIGWINCH <nginx worker pid>
(8)使得运行中的nginx重读配置项并生效
- 方法1:
usr/local/nginx/sbin/nginx -s reload
- 方法2:
kill -s SIGHUP <nginx master pid>
原理:nginx会先检测新的配置项来是否正确,如果全部正确就先“优雅”关闭,然后再重新启动nginx来实现这个目的
(9)日志文件回滚
- 方法1:
usr/local/nginx/sbin/nginx -s reopen
- 方法2:
kill -s SIGUSR1 <nginx master pid>
主要原理是:先把当前日志文件改名或者转移到其他目录中进行备份,再重新打开就会生成新的日志文件。目的是使得日志文件不至于过大
(10)平滑升级Nginx(待测试)
当nginx服务升级到新的版本时,必须要将旧的二进制文件nginx替换掉,nginx支持不停机的情况下完成新版本的平衡升级。步骤如下:
步骤一:用户向master进程发送USR2信号,通知正在运行的就版本nginx准备升级。
kill -s SIGUSR2 <nginx master pid>
这时运行中的nginx会将pid文件重命名,比如将usr/local/nginx/logs/nginx.pid重命名为usr/local/nginx/logs/nginx.pid.oldbin
步骤二:用户启动新版本nginx。这时通过ps命令可以看到新旧版本的nginx在同时运行
步骤三:通过kill命令向旧版本的master进程发送SIGQUIT信号。随后将只有新版本的Nginx服务运行,此时平滑升级完毕。