nginx简介
Nginx 是一款轻量的(相比 Apache、Lighttpd 而言)、高性能的 HTTP 服务器,同时也可以用作反向代理、负载平衡器和 HTTP 缓存。Nginx 采用了模块化、事件驱动的架构设计,使用了异步非阻塞
的事件处理机制处理请求,使得在高负载下也能提供更可靠的性能。
Nginx
的内部结构是由核心部分和一系列的功能模块所组成。Nginx Core
实现底层的通讯协议,为其他模块构建了基本的运行时环境,并且构建了其他各模块的协作基础。
Nginx
程序在启动后,会以守护进程的方式在系统后台中运行,后台进程包含一个 master
进程和多个 worker
进程。
master 进程负责管理 Nginx 本身和其他 worker 进程,包含:接收来自外界的信号、向各 worker 进程发送信号、监控 worker 进程的运行状态、当 worker 进程退出后(异常情况下),会自动重新启动新的 worker 进程等。
worker 进程主要处理基本的网络事件,多个 worker 进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,完全由 worker 进程来处理,而且只在一个 worker 进程中处理。worker 进程的个数是可以设置的,一般我们会设置与机器 cpu 核数一致,这里面的原因与 Nginx 的进程模型以及事件处理模型是分不开的。
nginx安装与命令
安装方法
yum安装rpm包会比编译安装简单很多,默认会安装许多模块,但缺点是如果你想以后安装第三方模块那就没办法了。可参考:https://nginx.org/en/linux_packages.html#RHEL-CentOS
1 | cat >/etc/yum.repos.d/nginx.repo <<EOF |
这样就安装好了。如果要选择版本安装,可以使用yum list nginx --enablerepo=nginx --showduplicates
来查看可用的版本。
而编译安装会复杂很多,也比较麻烦,但是优点是比较灵活,可以随意添加自己想要的模块。方法在:centos7编译安装LNMP:nginx1.16+mysql5.7+php7.2
nginx相关命令
有如下参数:
1 | Options: |
控制nginx的相关的主要命令有:
- 启动:
nginx -c /etc/nginx/nginx.conf
- 关闭:
nginx -s stop
,等同于kill -s TERM $(cat /var/run/nginx.pid)
- 优雅关闭:
nginx -s quit
,等同于kill -s QUIT $(cat /var/run/nginx.pid)
,所有的工作进程会停止接受新的连接,并继续服务旧的连接请求直到所有的请求完成后才退出。 - 加载配置文件:
nginx -s reload
,等同于kill -s HUP $(cat /var/run/nginx.pid)
- 重新打开日志文件:
nginx -s reopen
,等同于kill -USR1 $(cat /var/run/nginx.pid)
reload是有做了以下操作:当nginx主进程接收到重载配置文件的命令后,它会先检查新配置文件语法,然后载入该配置文件到内存中并解析。然后,主进程fork一系列新的worker进程,并发送QUIT信号给旧的worker进程(graceful stop)。旧的工作进程接收到QUIT信号后,会停止接受新的连接请求,并继续处理旧的连接直到请求处理完成后才退出。如下work进程的pid是有发生了变化:
1 | [root@localhost ~]# ps aux |grep nginx |
nginx版本升级
在说明如何稳定安全地升级、降级已经在运行中的nginx之前,需要先了解nginx支持的几种信号。可以通过man nginx
来查看到具体的含义:
1 | SIGINT, SIGTERM 立即杀掉nginx主进程(即所有进程) |
版本升级时,第一步是先编译好新版本的nginx,再发送 kill -USR2 $(cat /var/run/nginx/nginx.pid)
信号,该信号提示nginx旧的主进程要升级,并执行新的nginx程序。发送该信号后将会切换pid文件,旧的pid文件被重命名为nginx.pid.oldbin,记录的是旧的nginx主进程pid值,新的pid文件为nginx.pid,记录的是新启动的nginx的主进程pid值。然后再发送 kill -QUIT $(cat /var/run/nginx/nginx.pid.oldbin)
来向旧的主进程号发送QUIT信号,该信号将使得主进程以graceful的方式关闭。这将使得旧的主进程、旧的worker进程不再接受任何新请求,但却会把正在处理过程中的请求处理完毕,然后被销毁退出。
下载新版本,然后按原来的编译参数进行编译:
1
2
3
4
5
6
7
8
9
10
11
12[root@VM_0_6_centos ~]# nginx -V
nginx version: nginx/1.16.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.1.1d 10 Sep 2019
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-stream --with-stream_ssl_module --with-openssl=/usr/local/src/lnmp1.6/src/openssl-1.1.1d --with-openssl-opt='enable-weak-ssl-ciphers'
[root@VM_0_6_centos ~]# wget http://nginx.org/download/nginx-1.17.7.tar.gz
[root@VM_0_6_centos ~]# tar zxf nginx-1.17.7.tar.gz && cd nginx-1.17.7
复制configure arguments的参数过来,原先的参数一定要一样,但可以添加新的模块
[root@VM_0_6_centos nginx-1.17.7]# ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-stream --with-stream_ssl_module --with-openssl=/usr/local/src/lnmp1.6/src/openssl-1.1.1d --with-openssl-opt='enable-weak-ssl-ciphers'
[root@VM_0_6_centos nginx-1.17.7]# makemake完以后,不需要执行make install,否则会覆盖安装,nginx服务会出现各种问题。
替换执行文件
1
2
3
4[root@VM_0_6_centos nginx-1.17.7]# mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
[root@VM_0_6_centos nginx-1.17.7]# cp objs/nginx /usr/local/nginx/sbin/
[root@VM_0_6_centos nginx-1.17.7]# nginx -v
nginx version: nginx/1.17.7使用
make upgrage
命令进行升级。我们可以先打开Makefile
文件看一下是做了什么操作:
1 | upgrade: |
跟我们上面说的过程是一样的。开始运行:
1 | [root@VM_0_6_centos nginx-1.17.7]# make upgrade |
此方法同样可以适用于降级操作。整个升级期间是网站都是可以访问的,这是最安全的升级方式。
nginx基础配置详解
nginx配置文件主要分为六个区域: main(全局设置)、events(nginx工作模式)、http(http设置)、 sever(主机设置)、location(URL匹配)、upstream(负载均衡服务器设置)。如下结构:
1 | main |
注意:nginx具体的配置后面必须加逗号结尾,不然会报错。所有web站点的配置都是要放在http模块里面的。
main模块
main是一个全局的设置,不需要{},如下:
1 | user www www; |
user
来指定Nginx Worker进程运行用户以及用户组worker_processes
来指定了Nginx要开启的子进程数。每个Nginx进程平均耗费10M~12M内存。根据经验,一般指定1个进程就足够了,如果是多核CPU,建议指定和CPU的数量一样的进程数即可。error_log
用来定义全局错误日志文件。日志输出级别有debug、info、notice、warn、error、crit可供选择,其中,debug输出日志最为最详细,而crit输出日志最少。pid
用来指定进程id的存储文件位置。worker_rlimit_nofile
用于指定一个nginx进程可以打开的最多文件描述符数目,也可以理解为一个ningx进程所能处理的最大的连接数。
events 模块
events模块来用指定nginx的工作模式和工作模式及连接数上限。
1 | events |
use
用来指定Nginx的工作模式。Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll。其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平台上,而kqueue用在BSD系统中,因为Mac基于BSD,所以Mac也得用这个模式,对于Linux系统,epoll工作模式是首选。worker_connections
用于定义Nginx每个进程的最大连接数,即接收前端的最大请求数,默认是1024。最大客户端连接数由worker_processes
和worker_connections
决定,即Max_clients=worker_processes*worker_connections
,在作为反向代理时,Max_clients变为:Max_clients = worker_processes * worker_connections/2
。
http 模块
http模块可以说是最核心的模块了,它负责HTTP服务器相关属性的配置,它里面的server和upstream子模块,至关重要。
1 | http{ |
include
加载 mime.type 文件,用于帮助 Nginx 识别文件的 MIME 类型;default_type
指定文件默认的 MIME 类型。例如,在没有配置 asp 的环境时,Nginx 是不予解析的,此时,浏览器访问 asp 文件就会出现 下载 的提示了;log_format
设置日志的格式和记录哪些参数;access_log
设置 access_log 日志文件地址;sendfile
开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,减少用户空间到内核空间的上下文切换。对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。keepalive_timeout
设置客户端连接保持活动的超时时间,在超过这个时间之后,服务器会关闭该连接;gzip
是否开启 gzip 压缩,这将会减少我们发送的数据量;gzip_min_length 1k
: 设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。默认值是20。建议设置成大于1k的字节数,小于1k可能会越压越大。gzip_buffers 4 16k
: 设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。4 16k代表以16k为单位,安装原始数据大小以16k为单位的4倍申请内存。gzip_http_version 1.0
: 用于识别 http 协议的版本,早期的浏览器不支持 Gzip 压缩,用户就会看到乱码,所以为了支持前期版本加上了这个选项,如果你用了 Nginx 的反向代理并期望也启用 Gzip 压缩的话,由于末端通信是 http/1.0,故请设置为 1.0。gzip_comp_level 6
: gzip压缩比,1压缩比最小处理速度最快,9压缩比最大但处理速度最慢(传输快但比较消耗cpu)gzip_types
:匹配mime类型进行压缩,无论是否指定,”text/html”类型总是会被压缩的。gzip_proxied any
: Nginx作为反向代理的时候启用,决定开启或者关闭后端服务器返回的结果是否压缩,匹配的前提是后端服务器必须要返回包含”Via”的 header头。gzip_vary on
: 和http头有关系,会在响应头加个 Vary: Accept-Encoding ,可以让前端的缓存服务器缓存经过gzip压缩的页面,例如,用Squid缓存经过Nginx压缩的数据
client_max_body_size
允许客户端请求的最大单文件字节数。如果上传较大文件,请增加它的限制值;client_body_buffer_size
允许客户端请求的最大缓冲区字节数;proxy_connect_timeout
设置与后端服务器连接超时时间。
server 模块
server 模块是http的子模块,它用来定一个虚拟主机。就是用来建立多个网站的意思。一个server就是对应一个网站。
1 | server { |
listen
设置监听端口,默认 80,小于 1024 的要以root
用户启动。可以为listen *:80
、listen 127.0.0.1:80
等形式;server_name
设置域名,多个域名之间用空格分开;root
设置虚拟主机的默认网站根目录;index
定义默认访问的文件名;charset
设置网页的默认编码格式;error_page
设置错误页面,相对于上面的root
目录。
root与alias区别
root指的是网站的根目录,而alias指的是别名。先看下例子:
1 | nginx有如下配置: |
配置root的时候,访问 http://localhost/test/a.txt
时,访问的文件是 /tmp/test/a.txt
。
将nginx的配置由root
修改为alias
之后,再次访问 http://localhost/test/a.txt
1 | [root@localhost ~]# curl http://localhost/test/a.txt |
这时访问的文件是/tmp/a.txt,这时就可以实现URL的重写。
location详解
location 根据它字面意思就知道是来定位的,定位URL,解析URL,所以,它也提供了强大的正则匹配功能,也支持条件判断匹配,用户可以通过location指令实现Nginx对动、静态网页进行过滤处理。像我们的php环境搭建就是用到了它。
locaiton有以下几种类型的匹配规则:
模式 | 含义 |
---|---|
location = /uri | = 表示精确匹配,只有完全匹配上才能生效,优先级最高 |
location ^~ /uri | ^~ 开头对URL路径进行前缀匹配,优先级比 = 次之,但比正则的优先级更高 |
location ~ pattern | 开头表示区分大小写的正则匹配 |
location ~* pattern | 开头表示不区分大小写的正则匹配 |
location /uri | 不带任何修饰符,也表示前缀匹配,但是在正则匹配之后 |
location / | 通用匹配,任何未匹配到其它location的请求都会匹配到 |
其匹配的顺序如下:
- ^~和普通匹配。使用前缀匹配,不支持正则表达式,如果有多个location匹配成功的话,不会终止匹配过程,会记忆表达式最长的那个
- 如果上一步得到的最长的location为^~类型,则表示阻断正则表达式,不再匹配正则表达式
- 如果上一步得到的最长的location不是^~类型,继续匹配正则表达式,只要有一个正则成功,则使用这个正则的location,立即返回结果,并结束解析过程
实例如下:
- ^~优先级并不比普通匹配高:访问/test_1,返回的状态码为400,这是由于最长匹配的结果。
1 | nginx配置 |
- 普通匹配、^~、~三者混合使用:
1 | nginx配置 |
访问
http://192.168.1.61/test_1
,返回的是402,此时^~和普通匹配只记住了最长一个location /test_1
,不会阻止正则访问
http://192.168.1.61/test
,,返回401,此时^~和普通匹配只记住了最长一个location ^~ /test
,会阻止正则- 访问
http://192.168.1.61/test1
,,返回401,此时匹配到了^~,并没有匹配上~ - return 400一直是匹配不上的。