2.1 nginx 基础知识

前置知识

1.什么是代理
实践中客户端无法直接跟服务端发起请求的时候,我们就需要代理服务。代理可以实现客户端服务端之间的通信,我们的Nginx也可以实现相应的代理服务。代理分为正向代理反向代理
2.正向代理

正向代理

正向代理示意图

3.反向代理
反向代理示意图

总的来说就是,正向代理和反向代理代理的对象是不同的,正向代理,代理的是客户端,反向代理代理的是服务器

安装Nginx服务器

Nginx 进程模型解析

进程模型设计

ps -ef|grep nginx

进程模型

nginx模型有两种进程,master进程和worker进程。master进程主要用来管理worker进程。
管理包含:
1.接收来自外界的信号,
2.向各worker进程发送信号,
3.监控worker进程的运行状态,
4.当worker进程退出后(异常情况下),会自动重新启动新的worker进程
而基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。
一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的。
/etc/nginx/nginx.conf

worker_processes 2;
配置之后的结果集

怎样操作Nginx?

如上所知,master进程主要是用来管理worker进程的,所以操作Nginx只需要操作master进程就好,我们通过发送信号的方式来操作master进程master进程会接收来自外界发送来的消息,然后 master进程给子worker进程发送信号,worker进程收到信号后执行相关操作,如启动、关闭等
nginx -s reload 命令为例,来说说nginx的处理流程

1.向 master 进程发送 HUP 信号
2.master进程先检测 nginx.conf 文件是否配置正确
3.master进程打开新的监听端口
4.master进程用新配置启动新的 Worker 进程
5.master进程向老的 Worker进程发送 QUIT 信号
6.老worker进程关闭监听句柄,处理完正在进行的请求后结束进程

worker 抢占机制

Nginx处理http请求

worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?
首先,每个worker进程都是从master进程fork(继承)过来,在master进程里面,先建立好需要listensocket之后,然后再fork出多个worker进程,这样每个worker进程都可以去accept这个socket(当然不是同一个socket,只是每个进程的这个socket会监控在同一个ip地址与端口,这个在网络协议里面是允许的)。
一般来说,当一个连接进来后,所有在accept在这个socket上面的进程,都会收到通知,而只有一个进程可以accept这个连接,其它的则accept失败,这是所谓的惊群现象
当然,nginx也不会视而不见,所以nginx提供了一个accept_mutex这个东西,从名字上,我们可以看这是一个加在accept上的一把共享锁。有了这把锁之后,同一时刻,就只会有一个进程在accpet连接,这样就不会有惊群问题了。accept_mutex是一个可控选项,我们可以显示地关掉,默认是打开的。
当一个worker进程accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。

如何实现高并发?

/etc/nginx/config/nginx.conf

 events {
     # 默认使用epoll
     usr epoll;
     # 每个worker允许连接的客户端最大连接数
     worker_connections 10240;
 } 

传统服务器的事件处理

同步阻塞

1.当客户端Client 1发送请求,同时该请求因为某种原因(跟我一样后端写的很渣),导致该请求被阻塞。
2.此时Client2,Client3也发送了请求到worker 1,此时由于Client1一直被阻塞,导致worker 1还被阻塞着,所以没办法处理Client1Client2发送的请求。
Client1和Client2阻塞之后

3.此时Master看不下去了,又fork出了一个worer 2,接下来由worker 2去处理Client 2Client 3发送的请求
Client 2 阻塞之后

4.``worker 2去处理Client 2Client 3发送的请求时,发现Client 2 发送的请求也会导致阻塞,没办法Masterfork出了一个worker 3

Nginx服务器的事件处理
nginx采用了异步非阻塞的方式来处理请求,也就是说,nginx是可以同时处理成千上万个请求的(据说单个worker进程就可以处理6-8万个并发请求)。

Nginx事件处理

1.当客户端Client 1发送请求,同时该请求因为某种原因,导致该请求被阻塞。
2.此时Client2Client3也发送了请求到worker 1,虽然Client1发送的请求仍然被阻塞的,但是由于Nginx采用的异步非阻塞的模型,Client1Client2发送的请求仍然会被处理,不会再开启新的线程(worker
由于其事件模型的架构,可以似的Nginx能处理的请求更多

为什么采用异步非阻塞的方式?

首先我们回顾一下一个请求过来的处理过程,请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据。具体到系统底层,就是读写事件,而当读写事件没有准备好时,必然是不可操作的,如果不用非阻塞的方式来调用,那就得阻塞调用了,事件没有准备好,那就只能等了,等事件准备好了再继续。
阻塞调用会进入内核等待,cpu就会让出去给别人用了,对单线程的worker来说,显然不合适,当网络事件越多时,大家都在等待,cpu空闲下来没人用,cpu利用率自然上不去了,更别谈高并发了。
好吧,你说加进程数,这跟apache的线程模型有什么区别,注意,别增加无谓的上下文切换 ?所以,在nginx里面,最忌讳阻塞的系统调用了。不要阻塞,那就非阻塞喽。非阻塞就是,事件没有准备好,马上返回EAGAIN,告诉你,事件还没准备好,过会再来吧。好吧,你过一会,再来检查一下事件,直到事件准备好了为止,在这期间,你就可以先去做其它事情,然后再来看看事件好了没。
虽然不阻塞了,但你得不时地过来检查一下事件的状态,你可以做更多的事情了,但带来的开销也是不小的。
所以,才会有了异步非阻塞的事件处理机制,它们提供了一种机制,让你可以同时监控多个事件,调用他们是阻塞的,但可以设置超时时间,在超时时间之内,如果有事件准备好了,就返回。

nginx.conf 的配置结构

nginx.conf配置结构

nginx.conf 配置详解

user nginx; # 进程运行的用户
worker_processes 2;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    # 默认使用epoll
    usr epoll;
    # 每个worker允许连接的客户端最大连接数
    worker_connections 10240;
}

http {
    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  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}

user nginx

配置 user nginx

sendfile
指令说明

语法: sendfile on | off;
默认值: sendfile off;
上下文: http,server,location,if in location

指定是否使用sendfile系统调用来传输文件。
sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝。

原理解释
read/write
在传统的文件传输方式(readwrite/send方式),具体流程细节如下:

调用read函数,文件数据拷贝到内核缓冲区
read函数返回,数据从内核缓冲区拷贝到用户缓冲区
调用write/send函数,将数据从用户缓冲区拷贝到内核socket缓冲区
数据从内核socket缓冲区拷贝到协议引擎中
在这个过程当中,文件数据实际上是经过了四次拷贝操作:
硬盘—>内核缓冲区—>用户缓冲区—>内核socket缓冲区—>协议引擎

sendfile
sendfile系统调用则提供了一种减少拷贝次数,提升文件传输性能的方法。
sendfile系统调用利用DMA引擎将文件数据拷贝到内核缓冲区,之后数据被拷贝到内核socket缓冲区中
DMA引擎将数据从内核socket缓冲区拷贝到协议引擎中
这里没有用户态和内核态之间的切换,也没有内核缓冲区和用户缓冲区之间的拷贝,大大提升了传输性能。
这个过程数据经历的拷贝操作如下:
硬盘—>内核缓冲区—>内核socket缓冲区—>协议引擎

带有DMA收集拷贝功能的sendfile
对于带有DMA收集拷贝功能的sendfile系统调用,还可以再减少一次内核缓冲区之间的拷贝。具体流程如下:

sendfile系统调用利用DMA引擎将文件数据拷贝到内核缓冲区,之后,将带有文件位置和长度信息的缓冲区描述符添加到内核socket缓冲区中
DMA引擎会将数据直接从内核缓冲区拷贝到协议引擎中

tcp_nodelay
怎么可以强制socket在它的缓冲区里发送数据?

一个解决方案是 TCP 堆栈的 tcp_nodelay 选项。这样就可以使缓冲区中的数据立即发送出去。

Nginxtcp_nodelay 选项使得在打开一个新的 socket 时增加了tcp_nodelay选项。

但这时会造成一种情况:
终端应用程序每产生一次操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据以及40个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞。

为了避免这种情况,TCP堆栈实现了等待数据 0.2秒钟,因此操作后它不会发送一个数据包,而是将这段时间内的数据打成一个大的包。这一机制是由Nagle算法保证。

Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为默认配置了,但有些场合下把这一选项关掉也是合乎需要的。现在假设某个应用程序发出了一个请求,希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。

如果我们马上发送数据,那么交互性的以及客户/服务器型的应用程序将极大地受益。如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的 tcp_nodelay = on 选项来完成,这样就禁用了Nagle 算法。(不需要等待0.2s)

tcp_nopush
nginx 中,tcp_nopush 配置和 tcp_nodelay "互斥"。它可以配置一次发送数据的包大小。也就是说,它不是按时间累计 0.2 秒后发送包,而是当包累计到一定大小后就发送。在 nginx 中,tcp_nopush 必须和sendfile 搭配使用

keepalive_timeout
keepalive_timeout参数是一个请求完成之后还要保持连接多久,不是请求时间多久,目的是保持长连接,减少创建连接过程给系统带来的性能损耗,类似于线程池,数据库连接池。
当完成此次响应之后,服务端又发来新的请求,nginx就会复用该连接。
gzip
nginx中gzip的主要作用就是用来减轻服务器的带宽问题,经过gzip压缩后的页面大小可以变为原来的30%甚至更小,这样用户浏览页面时的速度会快很多。gzip的压缩页面需要浏览器和服务器双方都支持,实际上就是服务器端压缩,传到浏览器后浏览器解压缩并解析。目前的大多数浏览器都支持解析gzip压缩过的页面。
参数说明:
gzip

语法:gzip on | off;
默认值:gzip off;
作用域:http, server, location, if in location
说明:
启用或禁用gzip压缩模块,on表示启用,off表示禁用

gzip_min_length

语法:gzip_min_length length;
默认值:gzip_min_length 20;
作用域:http, server, location
说明:
设置允许压缩的页面最小字节数,页面字节数从header头中的Content-Length中进行获取。因为过小的文件内容压缩之后效果不明显,甚至会比不压缩时更大,所以一般建议长度不小于1000或1k。

响应头响应浏览器使用gzip解压
gzip_buffers

语法:gzip_buffers number size;
默认值:gzip_buffers 32 4k|16 8k;
作用域:http, server, location
说明:
设置response响应的缓冲区大小。32 4k代表以4k为单位将响应数据以4k的32倍(128k)的大小申请内存。如果没有设置,缓冲区的大小默认为整个响应页面的大小。

gzip_comp_level

语法:gzip_comp_level level;
默认值:gzip_comp_level 1;
作用域:http, server, location
说明:
设置gzip的压缩级别,可接受的范围是从1到9,数字越大压缩率越高,但更消耗CPU,一般设置6即可。

gzip_types

语法:gzip_types mime-type …;
默认值:gzip_types text/html;
作用域:http, server, location
说明:
指定哪些类型的相应才启用gzip压缩,多个用空格分隔。通配符”*”可以匹配任意类型。不管是否指定”text/html”类型,该类型的响应总是启用压缩。一般js、css等文本文件都启用压缩,如application/x-javascript text/css application/xml 等。具体的文件类型对应的mimi-type可以参考conf/mime.types文件。

gzip_http_version

语法:gzip_http_version 1.0 | 1.1;
默认值:gzip_http_version 1.1;
作用域:http, server, location

说明:
设置gzip压缩所需要的请求的最小HTTP版本,低于该版本不使用gzip压缩。一般不用修改,默认即可。

浏览器和服务器进行gzip压缩的请求和处理返回过程


请求处理过程

整个请求过程来看,开启gzip和不开启gip功能,其http的请求和返回过程是一致的,不同的是参数。
当开启HTTP的gzip功能时,客户端发出http请求时,会通过headers中的Accept-Encoding属性告诉服务器“我支持gzip解压,解压格式(算法)deflate,sdch为:”。Accept-Encoding:gzip,deflate,sdch
注意,不是request说自己支持解压,Nginx返回response数据的时候就一定会压缩。这还要看本次Nginx返回数据的格式是什么,如果返回数据的原始数据格式,和设置的gzip_types相符合,这时Nginx才会进行压缩。

nginx 常用指令

/usr/sbin
./nginx -s stop  强制关闭
./nginx -s quit  用户无感知关闭,服务当前的正在请求的http请求,阻止新的http请求,直到无http请求时,才将nginx服务器进行关闭
[root@VM_0_12_centos sbin]# ./nginx -h
nginx version: nginx/1.12.2
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-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/share/nginx/)
  -c filename   : set configuration file (default: /etc/nginx/nginx.conf)
  -g directives : set global directives out of configuration file
指令详情

日志切割

./nginx -V
默认配置

手动切割

1.在目录/usr/sbin下增加脚本nginxlog.sh

#/bin/bash 

cutlog_path='/var/log/cutnginx'
nglog_path='/var/log/nginx'

if [ ! -d ${cutlog_path} ]
then
mkdir -p ${cutlog_path}
fi

mv $nglog_path/access.log  $cutlog_path/access.$(date -d "yesterday" +%Y-%m-%d+%H:%M).log
mv  $nglog_path/error.log  $cutlog_path/error.$(date -d "yesterday" +%Y-%m-%d+%H:%M).log
# 向nginx主进程发送信号,用于重新打开日志文件
kill -USR1 `cat /var/run/nginx.pid`

也可设置为

mv $nglog_path/access.log  $cutlog_path/access.$(date -d "yesterday" +%Y-%m-%d).log
mv $nglog_path/error.log  $cutlog_path/error.$(date -d "yesterday" +%Y-%m-%d).log

2.为脚本赋予权限

chmod +x nginxlog.sh
运行脚本后生成的已分割的脚本

定时任务切割

1.安装定时任务插件

yum install crontabs # 安装定时任务插件

2.查看当前定时任务列表

crontab -l 

3.添加定时任务

crontab -e
*/1 * * * * /usr/sbin/nginxlog.sh

4.重启定时任务

service crond restart
定时任务表达式

常用的定时任务命令

service crond start
service crond stop
service crond restart
crontab -e # 编辑任务
crontab -e # 任务列表

常用表达式

*/1 * * * *  #每分钟执行
59 23 * * * #每天晚上23:59执行
0 1 * * * #每天凌晨1点执行

静态资源服务器

imooc.conf

server {
        listen       90; 
        server_name  localhost;  

        location / { 
            root /home/foodie-shop;
            index index.html;
        }   
        location /imooc { 
            root /home;
        }   
        error_page 404 /404.html;
            location = /40x.html {
        }   

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }   
    }   

alias:别名 增加路径的安全性

        location /static { 
            alias /home/imooc;
        }   
使用别名后效果不变,但安全性增加

静态文件压缩

server {
        listen       90;
        server_name  localhost;  

        location / { 
            root /home/foodie-shop;
            index index.html;
        }   
        location /static { 
            gzip on; # 开启gzip 压缩功能,目的:提高传输效率,节约带宽成本
            gzip_min_length 1; # 限制最小压缩的文件大小 小于该字节不压缩
            gzip_comp_level 3; # 压缩级别 1-9 文件越大 压缩的越小 但是CPU占用会增多
            gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png image/jpg;
            alias /home/imooc;
        }   
        error_page 404 /404.html;
            location = /40x.html {
        }   

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }   
    }   
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容

  • 转载别人的文章,nginx调优。链接如下:http://blog.csdn.net/xifeijian/artic...
    Alex_ct阅读 954评论 0 1
  • I/O模型: 阻塞型、非阻塞型、复用型、信号驱动型、异步 同步/异步:关注消息通知机制 消息通知:同步:等待对方返...
    Net夜风阅读 2,001评论 0 1
  • 一.I/O介绍 httpdMPM perfork:一个master进程开启多个子进程,master只负责读取配置文...
    分享一些文档阅读 393评论 0 0
  • I/O模型Nginx介绍Nginx的安装和目录结构Nginx的配置Nginx的编译安装 一、I/O模型 (一)I/...
    哈喽别样阅读 890评论 0 4
  • 什么是Nginx? Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器N...
    jiangmo阅读 2,537评论 1 9