nginx详解
1.什么是nginx
nginx有两个作用
1)web服务器(接收HTTP请求,解析HTTP请求,响应HTTP请求)
2)代理服务器(中间人,客户端和目标服务器之间通过代理服务器访问)
2.代理服务器
代理服务器分为两种,正向代理和反向代理
1)正向代理
客户端A==代理服务器B==服务器C
客户端A访问服务器C,实际上是先访问的代理服务器B,服务器B再去访问服务器C;
服务器C返回响应给服务器B,服务器B再将响应返回给服务器A
2)反向代理
客户端A==代理服务器B==服务器C
客户端A访问服务器B,服务器B再将请求转发给服务器C;
服务器C返回响应给服务器B,服务器B再将响应返回给服务器A
3.nginx作为反向代理服务器
nginx作为反向代理服务器的网络拓扑图如下所示:
这是一种常见的负载均衡的技术,首先,大量的并发访问或数据流量分担到多台节点设备上分别处理,减少用户等待响应的时间;其次,单个重负载的运算分担到多台节点设备上做并行处理,系统处理能力得到大幅度提高。
nginx作代理服务器的特点:
1)与后端web服务器无需长连接
2)接收用户请求是异步的,即将用户请求全部接收下来,再一次性发送给后端web服务器,极大的减轻后端web服务器的压力
3)发送响应报文时,是边接收来自后端web服务器的数据,边发送给客户端的
4.nginx作web服务器
nginx可像IIS,Apache一样作为一个web服务器来使用
nginx作为web服务器有以下特点:
1)跨平台
可在Unix like OS编译运行,也有Windows的移植版本
2)非阻塞,高并发
关于IO四种模型的介绍分析,参见:
http://www.cnblogs.com/shijingjing07/p/6111655.html
http请求的基本过程:建立连接---接收数据---发送数据,上述过程在系统底层是IO输入输出事件。
阻塞模式下,IO第一阶段数据没有准备好时,不能进行第二阶段,读写事件。nginx进程会阻塞。cpu就会让出去给其他的进程用了,当有越来越多的请求阻塞时,nginx进程基本上一直处于阻塞状态,更别谈高并发了。
非阻塞模式下,nginx进程不断轮询检查事件的状态,判断数据有没有准备好,没有马上返回EAGAIN,进程可以去做其他的事情,过一会,再来检查一下事件,直到事件准备好了为止。
非阻塞模式要不断轮询事件状态,同样是笔很大的开销。
异步非阻塞模式(根据IO模型的介绍,觉得是IO multiplexing:多Socket连接IO更准确),像select/poll/epoll/kqueue这样的系统调用,优势在于可以监控多个事件,这样就可以处理高并发的情况了,nginx进程使用的是epoll调用,epoll会不断的轮询所负责的所有socket,当某个数据达到了,就通知用户进程。在这个过程中,nginx进程一直是被epoll函数block的。
这里指的并发请求,是指未处理完的请求,线程只有一个,所以同时能处理的请求只有一个,只是在请求间进行不断地切换而已,切换也是因为异步事件未准备好,而主动让出的。
与多线程相比,这种事件处理方式有很多的优势,不需要创建线程,每个请求占用的内存也很少,没有上下午切换,并发数再多也不会导致武威的资源浪费(上下文切换)
5.nginx内部进程模型
nginx是以多进程的方式来工作的,nginx启动后,会有一个master进程和多个worker进程
1)master进程,管理worker进程,接收外界新信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。
2)worker进程,处理基本的网络事件,各worker进程之间是对等的,一般我们设置worker进程数和cpu核数一致,这样不会导致进程来竞争cpu资源,从而带来不必要的上下文切换。nginx为了更好地利用多核特性,提供了cpu亲缘性绑定,可将某个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。
3)master进程接收到信号后的处理(./nginx -s reload),首先重新加载配置文件,然后启动新的worker进程,向老的worker进程发信号,告诉他们可以光荣退休了。
4)worker进程如何处理请求,在master进程中,会先建立好需要listen的socket,然后fork出多个worker进程,这样worker进程都可以去accept这个socket(不是同一个socket,但不同socket监听同一个ip和端口,是允许的)。这样,当一个连接进来后,所有在accept这个socket上面的进程,都会收到通知,只有一个进程可以accept这个连接,其他的accept失败。nginx提供了一个accept_mutex共享锁,有了这个锁之后,就只会有一个进程在accept连接。当worker进程accept这个连接后,就开始读取请求,解析请求,处理请求,返回响应给客户端,最后断开连接。请求就完成了,一个请求只在一个worker进程中处理。
5)nginx进程模型的好处,worker进程间独立,一个进程退出,其他进程还在工作,服务不会中断。
6.nginx处理请求的过程
1)解析配置文件,得到需要监听的IP地址和端口
2)在master进程中,初始化这个监控的socket
3)fork多个worker进程
4)客户端向nginx发起连接请求
5)worker进程与客户端三次握手,建立连接
6)创建nginx对连接的封装,即ngx_connection_t结构体
7)设置读写事件处理函数并添加读写事件来与客户端进行数据的交换
8)nginx或客户端主动关掉连接,连接结束。
nginx作为代理服务器时,nginx是作为客户端来请求其他服务器的数据的(如upstream模块),此时,与其他server创建的连接,也封装在ngx_connection_t中,然后创建socket,并设置socket的属性(非阻塞)。然后再通过添加读写事件,调用connect/read/write来调用连接,最后关掉连接,并释放ngx_connection_t。
7.nginx连接池
ngxin是通过一个连接池来管理的,每个worker进程都有一个独立的连接池,连接池的大小是worker_connections,这里的连接池里面保存的不是真实的连接,它只是一个worker_connections大小的ngx_connection_t结构的数组。并且nginx会通过一个链表free_connections来保存所有的空闲ngx_connection_t,每次获取一个连接时,就从空闲链表中获取一个,用完后,再放回空闲连接链表里面。
所以,一个nginx能建立的最大连接数,应该是worker_connections*worker_processes,这个连接数是针对nginx作web服务器时。
如果nginx是作反向代理,那么最大并发量应是worker_connections*worker_processes/2,因为每个并发会建立与客户端的连接和与后端服务器的连接两个连接。
8.nginx作web服务器,反向代理的具体配置
#定义Nginx运行的用户和用户组
user www www;
#nginx进程数,建议设置为等于CPU总核心数。
worker_processes 8;
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log ar/loginx/error.log info;
#进程文件
pid ar/runinx.pid;
#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,
所以建议与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;
#工作模式与连接数上限
events
{
#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,
如果跑在FreeBSD上面,就用kqueue模型。
use epoll;
#单个进程最大连接数(最大连接数=连接数*进程数)
worker_connections 65535;
}
#设定http服务器
http
{
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型
#charset utf-8; #默认编码
server_names_hash_bucket_size 128; #服务器名字的hash表大小
client_header_buffer_size 32k; #上传文件大小限制
large_client_header_buffers 4 64k; #设定请求缓
client_max_body_size 8m; #设定请求缓
sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,
可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。
tcp_nopush on; #防止网络阻塞
tcp_nodelay on; #防止网络阻塞
keepalive_timeout 120; #长连接超时时间,单位是秒
#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
#gzip模块设置
gzip on; #开启gzip压缩输出
gzip_min_length 1k; #最小压缩文件大小
gzip_buffers 4 16k; #压缩缓冲区
gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_comp_level 2; #压缩等级
gzip_types text/plain application/x-javascript text/css application/xml;
#压缩类型,默认就已经包含textml,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
gzip_vary on;
#limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用
upstream blog.ha97.com {
#upstream的负载均衡,weight是权重,可以根据机器配置定义权重。weigth参数表示权值,权值越高被分配到的几率越大。
server 192.168.80.121:80 weight=3;
server 192.168.80.122:80 weight=2;
server 192.168.80.123:80 weight=3;
}
#虚拟主机的配置
server
{
#监听端口
listen 80;
#域名可以有多个,用空格隔开
server_name www.ha97.com ha97.com;
index index.html index.htm index.php;
root /data/www/ha97;
location ~ .*.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
#图片缓存时间设置
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 10d;
}
#JS和CSS缓存时间设置
location ~ .*.(js|css)?$
{
expires 1h;
}
#日志格式设定
log_format access '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $http_x_forwarded_for';
#定义本虚拟主机的访问日志
access_log ar/loginx/ha97access.log access;
#对 "/" 启用反向代理
location / {
proxy_pass http://127.0.0.1:88;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#以下是一些反向代理的配置,可选。
proxy_set_header Host $host;
client_max_body_size 10m; #允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k;
#设定缓存文件夹大小,大于这个值,将从upstream服务器传
}
#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file confpasswd;
#htpasswd文件的内容可以用apache提供的htpasswd工具来产生。
}
#本地动静分离反向代理配置
#所有jsp的页面均交由tomcat或resin处理
location ~ .(jsp|jspx|do)?$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
}
#所有静态文件由nginx直接读取不经过tomcat或resin
location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$
{ expires 15d; }
location ~ .*.(js|css)?$
{ expires 1h; }
}
}