启动nginx之后,可以通过日志来查看进程的相关信息
[root@idea-centos nginx]# ./sbin/nginx [root@idea-centos nginx]# ps -ef|grep nginx root 11059 1 0 16:34 ? 00:00:00 nginx: master process ./sbin/nginx nobody 11060 11059 0 16:34 ? 00:00:00 nginx: worker process root 11062 8193 0 16:34 pts/1 00:00:00 grep --color=auto nginxmaster process 主要是负责日志的更新,热装载主进程
worker process 工作进程 处理客户端的连接,处理请求
在nginx的log文件夹底下,我们在重新访问服务器之后,相应的access日志就会增加新的属性内容。
这里面的日志寻找,实际上是根据对象句柄来进行查找指定的文件。
nginx里的高性能主要归咎于其相应特有的io多路复用。每当有请求发送过来的时候,请求的都会被放入到一个select队列里面,专门存储客户端的http链接信息,然后通过一个专门的选择器来处理轮询,监听客户端是否有发送请求的数据(一直轮询,直到有数据发送过来的时候才会发生堵塞),一旦当接收到发送的数据时,selector就会做出指定的处理。
当我们启动了nginx之后,会有两类型进程出现,分别是master进程和worker进程,而客户端发送的请求通常只是和master进程进行通信,master进程负责接收这些请求,然后分发给不同的worker进程进行处理。
其实本质上,worker进程是从master进程这边fork出来的,在master的进程里面,需要先建立好被监听的socket之后,再fork出多个worker进程,多个worker进程(多核cpu环境下)会争抢accept_mutex互斥锁,抢锁成功的进程就会注册相应的事件对任务进行处理。这种独立进程处理事件的好处在于避免了原本的加锁开销,同时当进程中出现了bug异常的时候,不会影响其他的进程,降低了风险。
nginx处理高并发的方式又是如何的呢?当采用多个worker来处理请求的时候,每个worker里面都只有一个主线程,但是这样处理并发数非常有限,那当并发数量大的时候,是否又需要创建成千上万的线程来实现请求的处理呢?
nginx的设计高明之处就在于了这一点上了,它的机制有点类似于linux里面的epoll这样的系统调度。处理的响应线程(暂命名为A)只有一个,当请求过来的事件处理完毕的时候,会主动通知A , 不会对堵塞的请求等待操作。这样的设计避免了A主动去轮询和等待事件处理的所带来的事件消耗。
相比于传统的apache服务器,每一个连接,apache就会创建一个进程,每个进程内单线程,apache最多能创建256个进程。对于一个负载相对较高的网站来说,256的进程,也就是256个线程,因为线程处理请求时,是同步阻塞模式,接收请求之后,会一直等待该请求读取程序文件(IO)(同步),执行业务逻辑,返回客户端,所有操作完成之后才能处理下一个请求(阻塞)如果服务器已经达到256的极限,那么接下去的访问就需要排队这也就是为什么某些服务器负载不高的原因了。
每个worker进程都是单线程的模式
每个io链接都是基于异步非堵塞的模型建立的。
worker进程的数目结合服务器的cpu数量来进行设置,可以达到调优的效果
nginx在处理请求的时候,更多的是会把这些请求组成一条请求链,链上的各个模块都会进行不同功能的处理。例如说对于请求的解压和压缩处理,对于ssl的处理模块等。总的来说,nginx的基本模块我总结为了以下几项:
event module 事件处理机制模块,提供了各种事件的具体处理框架。nginx具体采用何种事件来处理,依赖于操作系统和编译设置项,例如ngx_event_core_module和ngx_epoll_module。
phase handler 主要负责处理客户端请求并产生待响应内容,ngx_http_static_module就是其中之一,该module主要是将nginx请求转往读取一些磁盘上边的数据,然后做出输出响应,例如说:uri 是以 / 结尾,则会交由 index 模块来链接上完整的路径名然后通过内部调用的方式来调用本模块。
output filter 该模块可以对响应的输出内容做出指定的修改,例如对页面的某些特定url进行替换操作。
upstream 这一模块相信大家都很熟悉,该模块主要是做反向代理的工作。
load-balancer 此模块主要是负责负载均衡功能,在集群中选择任意一台服务器作为请求的处理。
首先来查看一份最为基础的nginx基本配置:
events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; #标识使用零拷贝 keepalive_timeout 65; #标识采用长连接 server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }例如说我们在/usr/local/www/文件夹底下创建了一份html页面,然后需要通过nginx来进行访问,nginx在匹配server的location路径的时候,会先按照全路径,再从左往右,再从右往左匹配的顺序。
server { listen 80; server_name www.idea.com *.idea.com idea.*; location / { root /usr/local/www/; } }注意,这里面的root配置是存在继承关系的,location里面的root会继承location外边的root信息。如果location里面有写root,就会按照location里面的root来判断。server外>server内>location内。
所谓的动静分离实质上是指我们对于nginx配置里面的动态请求和静态文件都做了一定的分离。例如以下的配置信息:
server { listen 80; server_name www.idea.com *.idea.com idea.*; root /usr/local/www; #这里面添加映射static的记录 location /static { root /usr/local/static/; } location / { root /usr/local/www/; index idea.html; } }图片的实际存储位置是:
/usr/local/static/img/logo.jpg
按照上述的配置来讲,访问的方式是:
http://www.idea.com/static/img/logo.jpg
但是这种情况下,我们通过nginx来访问图片的方式是不会成功的,原因是这个地址会被nginx处理成为:前往root地址+static的最终地址进行查询:
/usr/local/static/static
为了避免这种情况,通常会用别名alias来进行匹配,具体配置如下:
server { listen 80; server_name www.idea.com *.idea.com idea.*; root /usr/local/www; location /static { alias /usr/local/static/; } location / { root /usr/local/www/; index idea.html; } }这个时候,我们再去访问 http://www.idea.com/static/img/logo.jpg 就会访问成功了。
同样对于别名我们可以进行更加复杂一些的逻辑操作案例:
假设我们需要访问static底下的文件内容,这个时候不需要携带相应的名称,直接通过访问 http://www.idea.com/static/css/test.css 就可以访问到 /usr/local/www/static/css/ 底下的内容了
那么,假如说有很多种类型的静态文件需要进行映射该如何配置呢?这个时候可以引入正则表达式的配置:
server { listen 80; server_name www.idea.com *.idea.com idea.*; root /usr/local/www; location /static { alias /usr/local/static/; } #这里的~是指忽略大小写 location ~* \.(gif|png|jpg|css|js) { root /usr/local/static/; } location / { root /usr/local/www/; index idea.html; } }加入了这段正则表达式的配置之后(~* .(gif|png|css|js)$) 通过访问该路径:http://www.idea.com/css/test.css 我们就可以访问到/usr/local/static/css/底下的文件内容了。
nginx还提供了一个非常灵活的代理访问机制,供我们通过代理的方式来进行访问location
通过nginx配置完全匹配代理进行页面跳转:
server { listen 80; server_name www.idea.com *.idea.com idea.*; root /usr/local/www; location /static { alias /usr/local/static/; } location ~* \.(gif|png|jpg|css|js) { alias /usr/local/static/; } location =/idea-serach { proxy_pass http://www.baidu.com } location / { root /usr/local/www/; index idea.html; } }通过proxy_pass配置来提供代理的请求转发,当我们访问http://www.idea.com/idea-serach的时候,就会匹配到访问百度的页面。
nginx对于访问的常见配置支持以下几种:
通过全路径访问location
通过关键字static匹配来访问location
通过正则表达式来访问location
通过反向代理进行访问location
设置某些链接只允许在固定的网站站点进行访问,防止某些特殊的域名进行ip访问之后盗取本网站的资源文件,因此可以设置这个防盗链的功能。具体配置如下:
server { listen 80; server_name www.idea.com *.idea.com idea.*; root /usr/local/www/; location /static { alias /usr/local/static/; } # 防盗链配置 location ~* \.(gif|png|jpg|css|js) { valid_referers none blocked *.idea.com; if ($invalid_referer) { return 403; } root /usr/local/static/; } location =/idea-serach { proxy_pass http://www.baidu.com; } location / { root /usr/local/www/; } }黑名单的配置比较简单,只需要先创建好黑名单文件,然后在http块里面引入就好了
# 创建黑名单文件 echo 'deny 192.168.0.132;' >> balck.ip #http 配置块中引入 黑名单文件 include black.ip;记得配置成功之后要让nginx reload一下,同时请求的时候查看是否是203,如果是的话说明是缓存请求。
当我们需要对于客户端发送的数据进行一些详细信息的查看时候,需要对nginx进行日志的记录,相应的可选参数有以下几点:
log_format格式变量: $remote_addr #记录访问网站的客户端地址 $remote_user #远程客户端用户名 $time_local #记录访问时间与时区 $request #用户的http请求起始行信息 $status #http状态码,记录请求返回的状态码,例如:200、301、404等 $body_bytes_sent #服务器发送给客户端的响应body字节数 $http_referer #记录此次请求是从哪个连接访问过来的,可以根据该参数进行防盗链设置。 $http_user_agent #记录客户端访问信息,例如:浏览器、手机客户端等 $http_x_forwarded_for #当前端有代理服务器时,设置web节点记录客户端地址的配置,此参数生效的前提是代理服务器也要进行相关的x_forwarded_for设置将日志配置放在http块里面即可。
通常我们会将日志的配置放置于http模块当中,例如下边的这组案例:
events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }客户机和服务器之间加入一层proxy代理机器,当发生请求的时候,由代理服务器去请求server端。最常见的正向代理案例有:vpn,局域网里面的上网客户端工具等。
举个栗子来讲:当我们需要通过路径匹配到 $host: $port /baidu.html的时候,被代理请求百度页面,可以进行以下的配置:
location =/baidu.html { proxy_pass http://www.baidu.com; }当客户端请求服务端的时候,实际上在服务端的接入层有一个代理机器进行请求的转发,而这一层请求的转发相对于客户端而言是透明的。
反向代理请求内部的服务器,虽然配置相似,但是功能不同,配置案例如下:
location =/baidu.html { proxy_pass http:/127.0.0.1:8088; }nginx里面有个叫做upstream的模块,专门用于配置负载均衡的内容,upstream里面提供有以下的相关参数:
service 反向服务地址 加端口
weight 权重
max_fails 失败多少次 认为主机已挂掉则,踢出
fail_timeout 移除server之后重新请求的时间 当服务挂了之后,这段时间内重新连接
backup 备用服务 (当服务全部都挂了,那么就会请求这里的服务)
max_conns 允许最大连接数
slow_start 当节点恢复,不立即加入,而是等待 slow_start 后加入服务对列。
相应参数的具体配置如下:
upstream backend { server 192.168.43.191:8080 weight=5 fail_timeout=10s; server 192.168.43.191:8089 weight=5 fail_timeout=10s; }ngixn里面默认支持的负载均衡策略是轮询加权重的方式,除此之外,nginx自身还支持额外的多种负载均衡策略:
ll+weight:轮询加权重 (默认)容易出现失重的情况,例如说某一台机器的访问过慢,容易导致请求堆积。
ip_hash : 基于Hash 计算 ,常用于保持session 一至性基于hash计算的时候,可以根据ip进行hash计算请求到指定的服务器。 (通常session一致性在分布式中最好的处理手段是将session存储在第三方的存储中心)首先对ip进行hash计算之后,将该值和服务器个数进行取模运算。
url_hash: 静态资源缓存,节约存储,加快速度可以根据图片的url请求到指定的服务器,比较好理解。
least_conn : 最小链接数每次请求都只会请求到最少客户端连接数的那台服务器去。
least_time :最小的响应时间计算节点平均响应时间,然后取响应最快的那个,分配权重更高
通过使用ip进行哈希计算的方式来请求后端服务器
upstream backend { ip_hash; server 192.168.43.191:8080 weight=1; server 192.168.43.191:8089 weight=8 fail_timeout=10s; } location / { #root html; index index.html index.htm; proxy_pass http://backend; }