写在前面
nginx是一个高性能的http和反向代理服务器,也是IMAP/POP3/SMTP服务器,由俄国大牛开发,于2004年10月4日发布第一个版本。目前,Nginx与Apache、IIS三分天下,约占全球web服务市场的三成。国内很多大型网站,如百度、京东、新浪、网易、腾讯、淘宝均采用nginx。
nginx的特点:占用内存少、并发能力强、系统稳定、功能集丰富,随着时代的发展,还支持均衡负载、缓存加速、SSL、流媒体(FLV/mp4)服务。
淘宝基于nginx开发了tengine,继承了Nginxx-1.8.1的所有特性,并兼容Nginx的配置,在此基础上,针对大访问量网站的需求,添加了很多高级功能和特性。
从这则笔记开始,详细整理nginx的相关用法。
nginx 安装
nginx既可以使用yum安装,也可以使用源码包安装,两者各有利弊。
yum安装一行命令行就可以搞定,必须在线安装,缺点是安装的版本比较老,且不能够自定义启用或禁用指定的模块。
源码包安装相对复杂,但是可以根据需要下载指定版本,自定义启用或者禁用功能模块。同时,如果安装机器不能上网的话,只能使用源码包进行安装。
yum安装nginx最新稳定版本
注:yum最新的稳定版本是1.14,最便捷的方式是通过yum工具进行安装。
- 使用epel源进行安装(只能安装nginx1.12)
1 | yum install -y epel-release |
- 使用nginx官方源进行安装
1 | vi /etc/yum.repos.d/nginx.repo |
安装完成后,执行以下命令启动服务
1 | systemctl start nginx |
TroubleShooting:如果服务无法启动,检查防火墙设置,是否开启的80端口。
源码包安装
- 编译安装
1 | //下载源码包 |
- 设置开机启动
1 | //编辑启动脚本 |
nginx常用编译选项说明
编译选项 | 含义 |
---|---|
–prefix=PATH | 指定nginx的安装目录,默认 /usr/local/nginx |
–conf-path=PATH | 设置nginx.conf配置文件的路径。nginx允许使用不同的配置文件启动,通过命令行中的-c选项。默认为prefix/conf/nginx.conf |
–sbin-path=PATH | 指定nginx二进位制可执行文件的路径,如果不指定,则会依赖于prefix路径。 |
–user=username | 设置nginx工作进程的用户。安装完成后,可以随时在nginx.conf配置文件更改user指令。默认的用户名是nobody。 |
–with-pcre | 设置PCRE库的源码路径,如果已通过yum方式安装,使用–with-pcre自动找到库文件。使用–with-pcre=PATH时,需要从PCRE网站下载pcre库的源码并解压,剩下的就交给Nginx的./configure和make来完成。perl正则表达式使用在location指令和 ngx_http_rewrite_module模块中。 |
–with-zlib=PATH | 指定 zlib的源码解压目录。在默认就启用的网络传输压缩模块ngx_http_gzip_module时需要使用zlib 。 |
–with-http_ssl_module | 使用https协议模块。默认情况下,该模块没有被构建。前提是openssl与openssl-devel已安装 |
–with-http_stub_status_module | 用来监控 Nginx 的当前状态 |
–with-http_realip_module | 通过这个模块允许我们改变客户端请求头中客户端IP地址值(例如X-Real-IP 或 X-Forwarded-For),意义在于能够使得后台服务器记录原始客户端的IP地址 |
–add-module=PATH | 添加第三方外部模块,如nginx-sticky-module-ng或缓存模块。每次添加新的模块都要重新编译(Tengine可以在新加入module时无需重新编译) |
nginx 配置文件
根据安装方式的不同,源码包安装的nginx配置目录在/usr/local/nginx/conf
;通过yum安装的配置目录在/etc/nginx/conf/
其中,主要包括四个部分:
global:全句配置
events:网络连接相关
http:与http协议相关的部分
server:虚拟主机相关的部分,在http当中;
nginx.conf全局配置
- user nobody;
1 | 定义运行nginx服务的用户,还可以加上组,如 user nobody nobody; |
- worker_processes 1;
1 | 定义nginx子进程数量,即提供服务的进程数量,该数值建议和服务cpu核数保持一致。 |
- error_log logs/error.log;
1 | 定义错误日志的路径,可以是相对路径(相对prefix路径的),也可以是绝对路径。 |
- error_log logs/error.log notice;
1 | 定义错误日志路径以及日志级别. |
- pid logs/nginx.pid;
1 | 定义nginx进程pid文件所在路径,可以是相对路径,也可以是绝对路径。 |
- worker_rlimit_nofile 100000;
1 | 定义nginx最多打开文件数限制。如果没设置的话,这个值为操作系统(ulimit -n)的限制保持一致。把这个值设高,nginx就不会有“too many open files”问题了。 |
- include文件
1 | include /usr/local/nginx/conf/vhost/*.conf |
events配置部分
- worker_connections 1024;
1 | 定义每个work_process同时开启的最大连接数,即允许最多只能有这么多连接。 |
- accept_mutex on;
1 | 默认为on。当某一个时刻只有一个网络连接请求服务器时,会对多个Nginx进程(worker processer)接收连接时进行序列化,只有一个进程被唤醒即可,防止多个进程争抢资源,节约系统资源。 |
- multi_accept on;
1 | 默认为off,即每个worker process一次只能接收一个新到达的网络连接。 |
- use epoll;
1 | Nginx服务器提供了多个事件驱动器模型来处理网络消息。支持的类型有: |
http配置部分
文件识别及日志相关
- MIME-Type
1 | include mime.types; |
- log_format
1 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' |
- access_log logs/access.log main;
1 | 定义日志的路径以及采用的日志格式,该参数可以在server配置块中定义。 |
socket相关
- sendfile on;
1 | 是否调用sendfile函数传输文件,默认为off,使用sendfile函数传输,可以减少user mode和kernel mode的切换,从而提升服务器性能。 |
- sendfile_max_chunk 128k;
1 | 该参数限定Nginx worker process每次调用sendfile()函数传输数据的最大值,默认值为0,如果设置为0则无限制。 |
- tcp_nopush on;
1 | 当tcp_nopush设置为on时,会调用tcp_cork方法进行数据传输,即:当应用程序产生数据时,内核不会立马封装包,而是当数据量积累到一定量时才会封装,然后传输。这样有助于解决网络堵塞问题。 |
client buffer
- keepalive_timeout 65 60;
1 | 该参数有两个值,第一个值设置nginx服务器与客户端会话结束后仍旧保持连接的最长时间,单位是秒,默认为75s。 |
- send_timeout
1 | 发送响应的超时时间,即Nginx服务器向客户端发送了数据包,但客户端一直没有去接收这个数据包,超过send_timeout定义的超时时间,那么Nginx将会关闭这个连接。 |
- client_max_body_size 10m;
1 | 限制发送http包的大小,浏览器在发送含有较大HTTP包体的请求时,其头部会有一个Content-Length字段,client_max_body_size是用来限制Content-Length所示值的大小的。 |
- gzip on; 以下几项都是与网页压缩相关的配置
1 | 是否开启gzip压缩。 |
- gzip_min_length 1k;
1 | 设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。默认值是20。建议设置成大于1k的字节数,小于1k可能会越压越大。 |
- gzip_buffers 4 16k;
1 | 设置系统获取几个单位的buffer用于存储gzip的压缩结果数据流。4 16k代表分配4个16k的buffer。 |
- gzip_http_version 1.1;
1 | 用于识别 http 协议的版本,早期的浏览器不支持 Gzip 压缩,用户会看到乱码,所以为了支持前期版本加上了这个选项。 |
- gzip_comp_level 6;
1 | gzip压缩比,1压缩比最小处理速度最快,9压缩比最大但处理速度最慢,因此去中间值。 |
- gzip_types mime-type … ;
1 | 匹配mime类型进行压缩,无论是否指定,”text/html”类型总是会被压缩的。在conf/mime.conf里查看对应的type。 |
- gzip_proxied any;
1 | Nginx作为反向代理的时候启用,决定开启或者关闭后端服务器返回的结果是否压缩,匹配的前提是后端服务器必须要返回包含”Via”的 header头。 |
- gzip_vary on;
1 | 和http头有关系,会在响应头加个 Vary: Accept-Encoding ,可以让前端的缓存服务器缓存经过gzip压缩的页面,例如,用Squid缓存经过Nginx压缩的数据。 |
proxy buffer 代理模块相关
- proxy_buffering
1 | 默认为 on,定义是否开启对后端response的缓冲 |
默认为60秒,指定一个连接到代理服务器的超时时间,单位为秒,需要注意的是这个时间最好不要超过75秒。1
2
- proxy_read_timeout
默认为60秒,决定读取后端服务器应答的超时时间,单位为秒,它决定nginx将等待多久时间来取得一个请求的应答。超时时间是指两次连续读操作之间的超时时间。某些情况下代理服务器将花很长的时间来获得页面应答(例如如当接收一个需要很多计算的报表时),可以在不同的location里面设置不同的值。1
2
- proxy_send_timeout
默认为60秒,设置代理服务器转发请求的超时时间,单位为秒,超时时间为两次连续写操作之间的超时时间,如果超过这个时间代理服务器没有数据转发到被代理服务器,nginx将关闭连接1
2
- proxy_buffer_size
缓存response的第一部分,通常是header,默认proxy_buffer_size 被设置成 proxy_buffers 里一个buffer 的大小,当然可以设置更小些。1
2
- proxy_buffers
默认proxy_buffers 8 4k或8k;
前面一个是num,后面一个是每个buffer的size.Nginx将会尽可能的读取后端服务器的数据到buffer,直到proxy_buffers设置的所有buffer们被写满或者数据被读取完(EOF),此时Nginx开始向客户端传输数据,会同时传输这一整串buffer们。如果数据很大的话,Nginx会接收并把他们写入到temp_file里去,大小由proxy_max_temp_file_size 控制。1
2
3
- proxy_max_temp_file_size
默认情况下proxy_max_temp_file_size值为1024MB,也就是说后端服务器的文件不大于1G都可以缓存到nginx代理硬盘中,如果超过1G,那么文件不缓存,而是直接中转发送给客户端.如果proxy_max_temp_file_size设置为0,表示不使用临时缓存。1
2
- proxy_busy_buffers_size
一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处 在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户端的buffer数量的。1
2
- proxy_temp_file_write_size
指定每次写temp file的大小1
2
- proxy_temp_path
指定缓冲代理服务器response的临时文件夹1
2
3
4
5
6
7
### server部分配置
server{} 包含在http{}内部,每一个server{}都是一个虚拟主机配置文件(站点)。
以下为nginx.conf配置文件中server{}部分的内容。
server {
listen 80; //监听端口为80,可以自定义其他端口,也可以加上IP地址,如,listen 127.0.0.1:8080;
server_name localhost; //定义网站域名,可以写多个,用空格分隔。
#charset koi8-r; //定义网站的字符集,一般不设置,而是在网页代码中设置。
#access_log logs/host.access.log main; //定义访问日志,可以针对每一个server(即每一个站点)设置它们自己的访问日志。
##在server{}里有很多location配置段
location / {
root html; //定义网站根目录,目录可以是相对路径也可以是绝对路径。
index index.html index.htm; //定义站点的默认页。
}
#error_page 404 /404.html; //定义404页面
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html; //当状态码为500、502、503、504时,则访问50x.html
location = /50x.html {
root html; //定义50x.html所在路径
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#定义访问php脚本时,将会执行本location{}部分指令
#location ~ \.php$ {
# proxy_pass http://127.0.0.1; //proxy_pass后面指定要访问的url链接,用proxy_pass实现代理。
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000; //定义FastCGI服务器监听端口与地址,支持两种形式,1 IP:Port, 2 unix:/path/to/sockt
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; //定义SCRIPT_FILENAME变量,后面的路径/scripts为上面的root指定的目录
# include fastcgi_params; //引用prefix/conf/fastcgi_params文件,该文件定义了fastcgi相关的变量
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht { //访问的url中,以/.ht开头的,如,www.example.com/.htaccess,会被拒绝,返回403状态码。
# deny all; //这里的all指的是所有的请求。
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000; //监听8000端口
# listen somename:8080; //指定ip:port
# server_name somename alias another.alias; //指定多个server_name
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl; //监听443端口,即ssl
# server_name localhost;
### 以下为ssl相关配置
# ssl_certificate cert.pem; //指定pem文件路径
# ssl_certificate_key cert.key; //指定key文件路径
# ssl_session_cache shared:SSL:1m; //指定session cache大小
# ssl_session_timeout 5m; //指定session超时时间
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2; //指定ssl协议
# ssl_ciphers HIGH:!aNULL:!MD5; //指定ssl算法
# ssl_prefer_server_ciphers on; //优先采取服务器算法
# location / {
# root html;
# index index.html index.htm;
# }
#}
`
Nginx的工作原理
web请求机制
nginx支持高并发,是一种非常高效的http服务器。要理解他的web请求机制,需要先了解数据通信机制和进程调用的相关内容。
通信机制
可以分为同步、异步两种方式。 同步、异步发生在当客户端发起请求后,服务端处理客户端的请求时。
同步机制,是指客户端发送请求后,需要等待服务端(内核)返回信息后,再继续发送下一个请求。在这种模式中,所有的请求在服务器端得到同步,即发送方和接收方对请求的处理步调是一致的。
异步机制,是指客户端发出一个请求后,不等待服务端(内核)返回信息,就继续发送下一个请求。在异步机制中,所有来自发送方的请求形成一个队列,接收方处理完后再通知发送方。
进程调用
进程调用有两种状态,阻塞与非阻塞,发生在IO调度过程中。
阻塞方式下,进程/线程在获取最终结果之前,被系统挂起了,也就是所谓的阻塞了,在阻塞过程中该进程什么都干不了,直到最终结果反馈给它时,它才恢复运行状态。
非阻塞方式和阻塞相反,进程/线程在获取最终结果之前,并没有进入被挂起的状态,而是继续执行新的任务。当有最终结果时,进程再把结果交给客户端。
Nginx之所以支持高并发,是因为采用了异步非阻塞的机制,依靠事件驱动模型来实现这种机制的。
事件驱动模型中,一个进程(线程)就可以了。
对于web服务器来说,客户端A的请求连接到服务端时,服务端的某个进程(Nginx worker process)会处理该请求,此进程在没有返回给客户端A结果时,它又去处理了客户端B的请求。
服务端把客户端A以及客户端B发来的请求作为事件交给了“事件收集器”,而“事件收集器”再把收集到的事件交由“事件发送器”发送给“事件处理器”进行处理。
最后“事件处理器”处理完该事件后,通知服务端进程,服务端进程再把结果返回给客户端A、客户端B。
在这个过程中,服务端进程做的事情属于用户级别的,而事件处理这部分工作属于内核级别的。也就是说,事件驱动模型是需要操作系统内核来作为支撑的。
Nginx的事件驱动模型,支持select、poll、epoll、rtsig、kqueue、/dev/poll、eventport等。其中,linux平台上最常用的poll和epoll。
nginx组织机构
Nginx服务器使用 master/worker 多进程模式。
主进程(Master process)启动后,会接收和处理外部信号;
主进程启动后通过fork() 函数产生一个或多个子进程(work process),每个子进程会进行进程初始化、模块调用以及对事件的接收和处理等工作。
具体而言,
主进程主要负责:
读取Nginx配置文件并验证其有效性和正确性
建立、绑定和关闭socket
按照配置生成、管理工作进程
接收外界指令,比如重启、关闭、重载服务等指令
日志文件管理
子进程主要负责:
接收客户端请求
将请求依次送入各个功能模块进行过滤处理
IO调用,获取响应数据
与后端服务器通信,接收后端服务器处理结果
数据缓存,访问缓存索引,查询和调用缓存数据
发送请求结果,响应客户端请求
接收主进程指令,如重启、重载、退出等