对于 Nginx 来说,它不像其它很多别的工具一样,有很多的命令行参数,比如我们刚刚学习完的 Redis 中的 redis-cli 或者 redis-server 。Nginx 的命令行参数只有几个,相信不少同学也经常会用到,所以总体来说,今天学习的内容并不是特别的复杂。
关于 Nginx 是什么,怎么安装,咱们也不多解释了,直接就开始正式的学习。毕竟现在 Nginx 已经是事实上的主流服务器应用了。可能很多国外的排行上它还比 Apache 低,但是,就我们目前的行业情况来看,使用 Apache 的才是凤毛麟角,甚至我在找工作的过程中,已经很多年没见过有哪个公司是使用 Apache 的了。不得不说,我们永远的朋友(俄罗斯)们做的软件真的是简单粗暴,但却那么好用,值得学习。
安装完成之后,如果是手动安装的,需要自己添加环境变量,如果不添加,那就找到安装目录,然后直接运行 nginx 这个命令就可以了。
➜ ~ nginx
➜ ~ ps -ef | grep nginx
501 12719 1 0 9:34上午 ?? 0:00.00 nginx: master process nginx
501 12720 12719 0 9:34上午 ?? 0:00.00 nginx: worker process
现在服务已经启动了。默认情况下,它会监听一个 8080 端口,然后指向的程序目录会是自己安装目录下的一个 www 目录。如果你和我一们使用的是 Mac 的话,那么可以使用 brew 方便地安装。安装之后它指向的文件目录是 /usr/local/var/www/ ,配置文件目录是 /usr/local/etc/nginx/ ,程序目录是 /usr/local/Cellar/nginx/1.21.6_1/bin/ 。
默认情况下,它会加载一个配置文件,这个配置文件的目录如果是编译安装的,可以在 configure 时通过 --conf-path=/usr/local/etc/nginx/nginx.conf
指定。当然,你也可以在运行时通过 -c
这个参数指定。
nginx -c </path/to/config>
对于要查看某个软件的命令行参数,通常来说都是通过 help 之类的命令来查看,Nginx 也不例外。
➜ ~ nginx -h
nginx version: nginx/1.23.0
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
[-e filename] [-c filename] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /usr/local/Cellar/nginx/1.21.6_1/)
-e filename : set error log file (default: /usr/local/var/log/nginx/error.log)
-c filename : set configuration file (default: /usr/local/etc/nginx/nginx.conf)
-g directives : set global directives out of configuration file
是的,你没看错,就这么一点,没了。接下来我们就一个一个的学习一下。
通过 -v
参数,就可以看到当前 nginx 的版本信息。
➜ ~ nginx -v
nginx version: nginx/1.23.0
另外还有一个大写的 -V
可以看到更完整的信息,以及编译时的 configure 信息。
➜ ~ nginx -V
nginx version: nginx/1.21.6
built by clang 13.0.0 (clang-1300.0.29.30)
built with OpenSSL 1.1.1m 14 Dec 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/Cellar/nginx/1.21.6_1 --sbin-path=/usr/local/Cellar/nginx/1.21.6_1/bin/nginx --with-cc-opt='-I/usr/local/opt/pcre2/include -I/usr/local/opt/openssl@1.1/include' --with-ld-opt='-L/usr/local/opt/pcre2/lib -L/usr/local/opt/openssl@1.1/lib' --conf-path=/usr/local/etc/nginx/nginx.conf --pid-path=/usr/local/var/run/nginx.pid --lock-path=/usr/local/var/run/nginx.lock --http-client-body-temp-path=/usr/local/var/run/nginx/client_body_temp --http-proxy-temp-path=/usr/local/var/run/nginx/proxy_temp --http-fastcgi-temp-path=/usr/local/var/run/nginx/fastcgi_temp --http-uwsgi-temp-path=/usr/local/var/run/nginx/uwsgi_temp --http-scgi-temp-path=/usr/local/var/run/nginx/scgi_temp --http-log-path=/usr/local/var/log/nginx/access.log --error-log-path=/usr/local/var/log/nginx/error.log --with-compat --with-debug --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_degradation_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-ipv6 --with-mail --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module
从这里,我们就可以看到当前 Nginx 默认的一些配置目录在哪里,也能看到当前的 Nginx 中都安装了哪些模块。不同的模块的配置将是我们未来学习的重点。
对于 Nginx 来说,配置文件非常重要,刚刚也说了,未来的学习主要就是针对配置文件中各种配置的学习。如果配置文件出现了问题,那么 Nginx 的运行也会有各种问题。因此,它专门提供了一个 -t
参数用来检查配置文件是否有错误。
➜ ~ nginx -t
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
这两行信息表示配置文件是正常的,没有任何问题。现在我们来模拟测试一下写错了配置文件会怎么样,直接打开我们的配置文件,然后随便乱写点东西。
➜ ~ vim /usr/local/etc/nginx/nginx.conf
………………
jj # 随便乱加
………………
接着再次运行 -t
进行测试。
➜ ~ nginx -t
nginx: [emerg] unknown directive "jj" in /usr/local/etc/nginx/nginx.conf:12
nginx: configuration file /usr/local/etc/nginx/nginx.conf test failed
很明显,配置文件中的错误语法被识别了出来。记住,每次自己手动修改完配置文件之后,一定要使用 -t
测试一下,否则服务启动不起来了,或者出现严重问题了,那可就吃不了兜着走了。
对于配置文件检查来说,也有一个大写的 -T
参数,它的作用也是类似的,只不过它还会把当前所有加载到的配置文件内容也打印出来。
➜ ~ nginx -T
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
# configuration file /usr/local/etc/nginx/nginx.conf:
#user nobody;
worker_processes 1;
………………
# configuration file /usr/local/etc/nginx/mime.types:
………………
# configuration file /usr/local/etc/nginx/servers/huanbao.conf:
………………
# configuration file /usr/local/etc/nginx/fastcgi_params:
………………
# configuration file /usr/local/etc/nginx/servers/xxx.conf:
………………
………………
关于这些配置是干嘛的,我们后面再慢慢学习,现在你只要知道这个参数能够看到所有的配置文件信息就好了。
接下来,我们学习 Nginx 的重启和停止。前面我们已经学过了 Nginx 如何启动运行,记住,没有什么 start 之类的参数,直接不带参数的运行 nginx 命令就是启动服务了。这时,如果你再次运行 nginx ,它会显示出一些端口已被绑定的信息。
➜ ~ nginx
nginx: [emerg] bind() to 0.0.0.0:8080 failed (48: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (48: Address already in use)
其实从这里也可以看出,如果我们再指定一个新的配置文件,只要配置文件中的端口号和之前已经运行的 Nginx 服务中的端口号不同,那么是可以再开新的 Nginx 实例的,是这样吗?大家可以自己试试,但今天咱们还是以命令行参数为主。
好吧,明显的,nginx 命令直接运行是不能去重启或者关闭服务的。那么我们要怎么重启和关闭呢?其实不少小伙伴应该早就知道了:-s
参数嘛。
nginx -s <signal>
注意到后面这个 ,它是信号的意思。它有下面这些值。
stop
快速关闭quit
优雅关闭reload
重截配置文件reopen
重新打开日志文件小伙伴们用得最多的应该就是 nginx -s reload
这个命令吧,毕竟大家没事的时候可不会直接去关闭服务玩。如果自己写过日志分割的,应该也用过 reopen 。咱们还是一个一个好好来解释下。
stop 和 quit 都是停止服务,退出 Nginx 程序,但是,stop 是直接关闭,而 quit 是优雅的关闭。如果你学习过 Go 语言,那一定会接触过优雅停机这个概念。意思就是在关闭服务的时候,如果有未执行完成的请求,那么这个请求还会继续执行完成,新的请求不会再进来。当所有请求都执行完毕后,正式关闭服务。对应的,stop 就是不管你的请求有没有执行完,直接就关闭服务,你的页面马上就会展示出报错信息。生产环境中,当然是推荐 quit 啦,但某些特殊情况下,比如网站在被爬,或者已经严重拖累数据库了,马上需要关闭服务的情况下,就不用考虑那么多了。可以使用 php 进行 sleep() 操作来测试 quit 和 stop 的不同。
reload 是当你的配置文件有修改后,直接重裁这个配置文件,同样的,如果你学习过 Go ,那么 Viper 也是可以支持配置文件的监听的,意思是一样的。Nginx 会让新的请求开一个新的工作进程,它们会走新的配置文件,同时老的请求也会通过优雅的方式在处理完成之后被关闭。注意,再次提醒,reload 之前 ,一定要先 -t
检查啊。
reopen 就是重新打开对日志文件的读写句柄,常用于日志分割时。特别是对于访问日志,也就是默认的那个 access_log ,如果你的网站访问量比较大,这个日志文件每天也会生成非常多的信息,这时,就可以写一个定时脚本,每天半夜去进行日志分割,然后再 reopen 让今天的日志记录到新的文件中。后面我们也会学习到怎样自己写一个简单的日志分割脚本。
好用吧,也非常方便吧,但其实,这些命令的底层其实是走的 Nginx 的信号控制流程。关于 Linux 程序的信号控制,在之前学习 Swoole 的时候我们就接触过,不记得的小伙伴可以移步 【Swoole3.4】进程间通信https://mp.weixin.qq.com/s/uftbLUHeQ1hzChpN2D-g7A 。当时我们是使用信号来进行进程间通信,同样的,信号也可以通过编码,让程序来执行许多功能。
➜ ~ ps -ef | grep nginx
501 12789 1 0 9:35上午 ?? 0:00.00 nginx: master process nginx
501 12790 12789 0 9:35上午 ?? 0:00.00 nginx: worker process
➜ ~ kill -s QUIT 12789
我们给 Nginx 的主进程发送了一个 QUIT 信号,其实它的意思就和 nginx -s quit
一样,让 Nginx 优雅关机。我们还可以这样写,用原生的信号语法。
➜ ~ kill -QUIT 12985
是不是感觉很高大上。还有其它的信号参数。
nginx -s stop
nginx -s quit
nginx -s reload
nginx -s reopen
大家注意到没,下面的两个信号是我们 -s
命令中所没有的。USR2 可以用于平滑升级 Nginx 版本,相当强大。WINCH 则可以用于优雅关闭主进程。这两个配置是需要配合使用的,先编译安装好新的 Nginx ,然后 USR2 让正在运行的主进程 A 生成以新的版本文件运行的一个进程 B ,这个 B 进程目前还是老的进程 A 的子进程,但它会标识为 master 。接着,使用 WINCH 去关闭老的进程 A 。在这中间,整个 Nginx 的服务是不会中断的,如果有老的请求还没有完成,那么老的进程还会继续处理完,就像 reload 一样平滑的完成整个程序版本的升级重启。
不过,说实话,很少有去升级 Nginx 的,真的非常少,为什么呢?就像 2/8 定律一样。其实我们大部分情况下用到的只是 Nginx 中最核心的那 20% 功能,这些功能很少会更新的,漏洞也比较少。反而如果你经常用一些非常新的功能,则有可能因为各种问题而带来经常的更新切换。
当然,也不是说新版本不好,如果是线上环境,使用最新的稳定版本就好了。大部分情况下,用个几年升不升级的也没啥影响。
另外还有几个参数,咱们简单看一下,平常使用的不多。
-e file
使用指定的错误日志文件来存储日志,而不是默认文件(1.19.5)。特殊值 stderr 选择标准错误文件。-g directives
动态设置一些配置文件中的全局配置信息-p prefix
设置 Nginx 程序的运行目录,一般是起保护作用-q
在测试期间抑制非错误的信息今天的内容重点就是信号控制以及配置文件检查,这两块相信也是大家经常会使用到的部分。关于 Nginx 中,命令行的部分就学完了,是的,就这么一篇,就这么一点点内容。后面我们将学习到的内容基本都是配置文件里面的东西,如果有牵涉到命令行相关的内容,也会直接给出示例。
后续的学习就是 Nginx 中各个模块的配置,有的配置可能一篇文章写不完,反正还是以官方文档为基础,例行刷文档。没有进阶部分,直接就在学习的过程中穿插一些原理和常见面试八股文的学习,大家不要急,夯实基础才是不断向上最稳妥的方案。
好了,Nginx 的学习旅程就这样愉快的开始了,没别的废话,上来就是干,加油吧,少年们!