美文网首页
nginx基础

nginx基础

作者: 胡志强 | 来源:发表于2021-01-31 15:04 被阅读0次

    一、请求nginx默认页面

    1、流程

    请求nginx默认页面

    二、nginx.conf配置

    nginx.conf配置

    listen 监听端口。server_name 代表ip地址。location 映射地址

    二、nginx的进程模型

    Nginx的初始化过程:
    解析配置文件,这是Nginx初始化最重要的一个环节
    调用各个配置指令回调函数,完成各个模块的配置、相互关联等
    建立listen 的 socket(listenfd)
    准备工作都完成后,fork worker子进程和cache子进程

    image.png

    nginx默认有两个工作模型,父进程和子进程。
    master进程:也是父进程,负责worker进程的管理和发送信号。
    信号分类

    TERM/INT,立刻停止进程;
    QUIT,优雅的退出,等请求处理完才退出;
    HUP,重载配置文件;
    USR1,重新打开日志文件,做日志文件的切割;
    USR2,热升级第一阶段,启动新进程。旧的 Nginx 主进程 Master 将会把自己的进程文件改名为 .oldbin,然后执行新版 Nginx。此时新旧 Nginx 进程会同时运行,共同处理请求;
    WINCH,热升级第二阶段,停止老进程。逐步停止旧版 Nginx 的 Worker 进程就都会随着任务执行完毕而退出,新版的 Nginx 的 Worker 进程会逐渐取代旧版 Worker 进程。
    

    子进程分两类:一种是 Worker 进程,另一种是 Cache 相关的进程。
    worker进程:也是子进程,worker进程一般配置成与服务器的CPU核数相同,worker进程用来处理具体的请求的。和接收信号:TERM/INT、QUIT、USR1、WINCH。
    cache进程:也是子进程,包括cache manager(缓存管理)和cache loader(缓存加载),主要是反向代理时做缓存使用。

    nginx命令对应信号:
    reload: HUP;
    reopen: USR1;
    stop: TERM;
    quit: QUIT。

    worker进程数量修改


    conf中修改worker进程数量

    /sbin/nginx -t 可以查看参看配置有没有问题

    nginx进程工作方式

    进程之间相互不影响,不公用内存,受到攻击容易处理

    worker抢占机制

    惊群现象
    主进程(master 进程)首先通过 socket() 来创建一个 sock 文件描述符用来监听,然后fork生成子进程(workers 进程),子进程将继承父进程的 sockfd(socket 文件描述符),之后子进程 accept() 后将创建已连接描述符(connected descriptor)),然后通过已连接描述符来与客户端通信。
    由于所有子进程都继承了父进程的 sockfd,那么当连接进来时,所有子进程都将收到通知并“争着”与它建立连接,这就叫“惊群现象”。大量的进程被激活又挂起,只有一个进程可以accept() 到这个连接,这当然会消耗系统资源。
    Nginx 提供了一个 accept_mutex 这个东西,这是一个加在accept上的一把共享锁。即每个 worker 进程在执行 accept 之前都需要先获取锁,获取不到就放弃执行 accept()。有了这把锁之后,同一时刻,就只会有一个进程去 accpet(),这样就不会有惊群问题了。accept_mutex 是一个可控选项,我们可以显示地关掉,默认是打开的。

    抢占机制

    nginx事件处理机制

    传统服务器事件处理

    传统服务器事件处理采用同步阻塞AIO机制(例如Apache),当客户端请求进来后,worker1处理请求,此时worker1会阻塞,无法处理其他请求。针对于高并发的场景,则需要生产大量的worker。


    传统服务器事件处理 传统服务器事件处理
    传统服务器事件处理

    Nginx事件处理机制

    Nginx采用了Linux的epoll模型,异步非阻塞。单个worker可以同时处理几万个请求的,具体取决于CPU和内存。当多个client请求worker1,假设client1的请求阻塞,由于异步非阻塞机制,worker1仍可以去处理其他客户端请求。epoll 工作模型 1个worker可以处理6-8万个请求


    nginx事件处理机制 nginx事件处理机制 nginx事件处理机制 nginx事件处理机制

    epoll原理 https://blog.csdn.net/daaikuaichuan/article/details/83862311?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

    nginx.conf文件结构

    image.png
    '##代码块中的events、http、server、location、upstream等都是块配置项##
    ##块配置项可以嵌套。内层块直接继承外层快,例如:server块里的任意配置都是基于http块里的已有配置的##
     
    ##Nginx worker进程运行的用户及用户组 
    #语法:user username[groupname]    默认:user nobody 
    #user用于设置master进程启动后,fork出的worker进程运行在那个用户和用户组下。当按照"user username;"设置时,用户组名与用户名相同。
    #若用户在configure命令执行时,使用了参数--user=usergroup 和 --group=groupname,此时nginx.conf将使用参数中指定的用户和用户组。
    #user  nobody;
    user root;
     
    ##Nginx worker进程个数:其数量直接影响性能。
    #每个worker进程都是单线程的进程,他们会调用各个模块以实现多种多样的功能。如果这些模块不会出现阻塞式的调用,那么,有多少CPU内核就应该配置多少个进程,反之,有可能出现阻塞式调用,那么,需要配置稍多一些的worker进程。
    worker_processes  1;
     
    ##ssl硬件加速。
    #用户可以用OpneSSL提供的命令来查看是否有ssl硬件加速设备:openssl engine -t
    #ssl_engine device;
     
    ##守护进程(daemon)。是脱离终端在后台允许的进程。它脱离终端是为了避免进程执行过程中的信息在任何终端上显示。这样一来,进程也不会被任何终端所产生的信息所打断。##
    ##关闭守护进程的模式,之所以提供这种模式,是为了放便跟踪调试nginx,毕竟用gdb调试进程时最繁琐的就是如何继续跟进fork出的子进程了。##
    ##如果用off关闭了master_proccess方式,就不会fork出worker子进程来处理请求,而是用master进程自身来处理请求
    #daemon off;   #查看是否以守护进程的方式运行Nginx 默认是on 
    #master_process off; #是否以master/worker方式工作 默认是on
     
    ##error日志的设置#
    #语法: error_log /path/file level;
    #默认: error_log / log/error.log error;
    #当path/file 的值为 /dev/null时,这样就不会输出任何日志了,这也是关闭error日志的唯一手段;
    #leve的取值范围是debug、info、notice、warn、error、crit、alert、emerg从左至右级别依次增大。
    #当level的级别为error时,error、crit、alert、emerg级别的日志就都会输出。大于等于该级别会输出,小于该级别的不会输出。
    #如果设定的日志级别是debug,则会输出所有的日志,这一数据量会很大,需要预先确保/path/file所在的磁盘有足够的磁盘空间。级别设定到debug,必须在configure时加入 --with-debug配置项。
    #error_log  logs/error.log;
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;
     
    ##pid文件(master进程ID的pid文件存放路径)的路径
    #pid        logs/nginx.pid;
     
    events {
     #仅对指定的客户端输出debug级别的日志: 语法:debug_connection[IP|CIDR]
     #这个设置项实际上属于事件类配置,因此必须放在events{……}中才会生效。它的值可以是IP地址或者是CIRD地址。
        #debug_connection 10.224.66.14;  #或是debug_connection 10.224.57.0/24
     #这样,仅仅以上IP地址的请求才会输出debug级别的日志,其他请求仍然沿用error_log中配置的日志级别。
     #注意:在使用debug_connection前,需确保在执行configure时已经加入了--with-debug参数,否则不会生效。
        worker_connections  1024;
    }
     
    ##核心转储(coredump):在Linux系统中,当进程发生错误或收到信号而终止时,系统会将进程执行时的内存内容(核心映像)写入一个文件(core文件),以作为调试只用,这就是所谓的核心转储(coredump).
     
    http {
    ##嵌入其他配置文件 语法:include /path/file
    #参数既可以是绝对路径也可以是相对路径(相对于Nginx的配置目录,即nginx.conf所在的目录)
        include       mime.types;
        default_type  application/octet-stream;
        #log_format  main  '$remote_addr -(客户端IP地址) $remote_user(用户端名称)
     
    [$time_local] (时间)
    "$request" (请求内容 )
    '$status请求状态 
    $body_bytes_sent "
    $http_referer"(用于记录用户在哪个链接跳转过来的) 
    '"$http_user_agent"用户代理
    "$http_x_forwarded_for"客户端ip';
    #access_log  logs/access.log  main; 用户请求记录
    sendfile        on; 用于进行文件高效传输
    #tcp_nopush     on;和sendfile配合使用,数据包累计一定大小一起处理
    #keepalive_timeout  0;客户端链接超时时间
    keepalive_timeout  65;tcp使用完不会立即消除,会保存一段时间,提高效率
    #gzip  on;压缩
     
    server {
    ##listen监听的端口
    #语法:listen address:port [ default(deprecated in 0.8.21) | default_server | [ backlog=num | rcvbuf=size | sndbuf=size | accept_filter=filter | deferred | bind | ssl ] ]
    #default_server: 如果没有设置这个参数,那么将会以在nginx.conf中找到的第一个server块作为默认server块
    listen       8080;
    #主机名称:其后可以跟多个主机名称,开始处理一个HTTP请求时,nginx会取出header头中的Host,与每个server中的server_name进行匹配,以此决定到底由那一个server来处理这个请求。有可能一个Host与多个server块中的server_name都匹配,这时会根据匹配优先级来选择实际处理的server块。server_name与Host的匹配优先级见文末。
    server_name  localhost;
    #charset koi8-r;
    #access_log  logs/host.access.log  main;
    #location / {
    #    root   html;
    #    index  index.html index.htm;
    #}
     
    ##location 语法: location [=|~|~*|^~] /uri/ { ... }
    # location的使用实例见文末。
    #注意:location时有顺序的,当一个请求有可能匹配多个location时,实际上这个请求会被第一个location处理。
        location / {
        proxy_pass http://192.168.1.60;
            }
     
            #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 the PHP scripts to Apache listening on 127.0.0.1:80
            #
            #location ~ \.php$ {
            #    proxy_pass   http://127.0.0.1;
            #}
     
            # 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_index  index.php;
            #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
            #    include        fastcgi_params;
            #}
     
            # deny access to .htaccess files, if Apaches document root
            # concurs with nginxs one
            #
            #location ~ /\.ht {
            #    deny  all;
            #}
        }
     
     
     
        # another virtual host using mix of IP-, name-, and port-based configuration
        #
        #server {
        #    listen       8000;
        #    listen       somename:8080;
        #    server_name  somename  alias  another.alias;
     
        #    location / {
        #        root   html;
        #        index  index.html index.htm;
        #    }
        #}
     
     
        # HTTPS server
        #
        #server {
        #    listen       443 ssl;
        #    server_name  localhost;
     
        #    ssl_certificate      cert.pem;
        #    ssl_certificate_key  cert.key;
     
        #    ssl_session_cache    shared:SSL:1m;
        #    ssl_session_timeout  5m;
     
        #    ssl_ciphers  HIGH:!aNULL:!MD5;
        #    ssl_prefer_server_ciphers  on;
     
        #    location / {
        #        root   html;
        #        index  index.html index.htm;
        #    }
        #}
     
    
    

    如果出现pid 找不到问题,就重新创建目录 pid无效从新指定pid 示例如下

    pid 找不到问题 pid 找不到问题
    pid 找不到问题

    nginx 常用指令

    start nginx:打开 nginx
    nginx -t :测试配置文件是否有语法错误
    nginx -s reopen:重启Nginx
    nginx -s reload:重新加载Nginx配置文件,然后以优雅的方式重启Nginx
    nginx -s stop:强制停止Nginx服务
    nginx -s quit:优雅地停止Nginx服务(即处理完所有请求后再停止服务)
    nginx -v 版本号
    nginx -V具体信息
    nginx -?帮助文档
    nginx -c 指定特定的配置文件

    nginx 日志分割

    Nginx 日志切割-手动
    现有的日志都会存在 access.log 文件中,但是随着时间的推移,这个文件的内容会越来越多,体积会越来越大,不便于运维人员查看,所以我们可以通过把
    文件切割为多份不同的小文件作为日志,切割规则可以以天为单位,如果每天有几百G或者几个T的日志的话,则可以按需以每半天或者每小时对日志切割一
    具体步骤如下:
    1. 创建一个shell可执行文件: cut_my_log.sh ,内容为:
    #!/bin/bash
    LOG_PATH="/var/log/nginx/"
    RECORD_TIME=$(date -d "yesterday" +%Y-%m-%d+%H:%M)
    PID=/var/run/nginx/nginx.pid
    mv ${LOG_PATH}/access.log ${LOG_PATH}/access.${RECORD_TIME}.log
    mv ${LOG_PATH}/error.log ${LOG_PATH}/error.${RECORD_TIME}.log
    #向Nginx主进程发送信号,用于重新打开日志文件
    kill -USR1 `cat $PID`
    2. 为cut_my_log.sh 添加可执行的权限:
    chmod +x cut_my_log.sh
    3. 测试日志切割后的结果:
    ./cut_my_log.sh
    

    自动切割

    Nginx 日志切割-定时
    使用定时任务
    1. 安装定时任务:
    yum install crontabs
    2. crontab -e 编辑并且添加一行新的任务:
    */1 * * * * /usr/local/nginx/sbin/cut_my_log.sh
    3. 重启定时任务:
    service crond restart
    附:常用定时任务命令:
    service crond start //启动服务
    service crond stop //关闭服务
    service crond restart //重启服务
    service crond reload //重新载入配置
    crontab -e // 编辑任务
    crontab -l // 查看任务列表
    定时任务表达式:
    Cron表达式是,分为5或6个域,每个域代表一个含义,如下所示:
    分时日月星期几年(可选)
    取值范围0-59 0-23 1-31 1-12 1-7 2019/2020/2021/…
    常用表达式:
    每分钟执行:
    */1 * * * *
    每日凌晨(每天晚上23:59)执行:
    59 23 * * *
    每日凌晨1点执行:
    0 1 * * *
    参考文献:
    每天定时为数据库备份:https://www.cnblogs.com/leechenxiang/p/7110382.html
    
    例子: image.png

    使用nginx提供静态资源服务器

    配置conf文件修改server


    image.png

    设置别名


    image.png

    文件压缩

    目的提高传输效率,节约带宽


    image.png

    刷新:command+shfit+r 不会出现缓存

    location匹配规则

    location匹配命令
    
    ~      #波浪线表示执行一个正则匹配,区分大小写
    *代表不区分大小写
    ~*    #表示执行一个正则匹配,不区分大小写
    ^~    #^~表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录
    =      #进行普通字符精确匹配
    @     #"@" 定义一个命名的 location,使用在内部定向时,例如 error_page, try_files
    
    location 匹配的优先级(与location在配置文件中的顺序无关)
    = 精确匹配会第一个被处理。如果发现精确匹配,nginx停止搜索其他匹配。
    普通字符匹配,正则表达式规则和长的块规则将被优先和查询匹配,也就是说如果该项匹配还需去看有没有正则表达式匹配和更长的匹配。
    ^~ 则只匹配该规则,nginx停止搜索其他匹配,否则nginx会继续处理其他location指令。
    最后匹配理带有"~"和"~*"的指令,如果找到相应的匹配,则nginx停止搜索其他匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。
    
    location 优先级官方文档
    
    Directives with the = prefix that match the query exactly. If found, searching stops.
    All remaining directives with conventional strings, longest match first. If this match used the ^~ prefix, searching stops.
    Regular expressions, in order of definition in the configuration file.
    If #3 yielded a match, that result is used. Else the match from #2 is used.
    =前缀的指令严格匹配这个查询。如果找到,停止搜索。
    所有剩下的常规字符串,最长的匹配。如果这个匹配使用^〜前缀,搜索停止。
    正则表达式,在配置文件中定义的顺序。
    如果第3条规则产生匹配的话,结果被使用。否则,使用第2条规则的结果。
     
    location  = / {
      # 只匹配"/".
      [ configuration A ] 
    }
    location  / {
      # 匹配任何请求,因为所有请求都是以"/"开始
      # 但是更长字符匹配或者正则表达式匹配会优先匹配
      [ configuration B ] 
    }
    location ^~ /images/ {
      # 匹配任何以 /images/ 开始的请求,并停止匹配 其它location
      [ configuration C ] 
    }
    location ~* .(gif|jpg|jpeg)$ {
      # 匹配以 gif, jpg, or jpeg结尾的请求. 
      # 但是所有 /images/ 目录的请求将由 [Configuration C]处理.   
      [ configuration D ] 
    }
    

    例:精准匹配、只匹配这个


    image.png

    DNS域名解析

    nginx跨域问题

    image.png
    image.png

    解决方式


    image.png

    nginx配置静态资源防盗链


    image.png

    nginx模块化体系

    image.png
    
    
         nginx core实现了底层的通讯协议,为其他模块和Nginx进程构建了基本的运行时环境,并且构建了其他各模块的协作基础。
    
         http模块和mail模块位于nginx core和各功能模块的中间层,这2个模块在nginx core之上实现了另外一层抽象,分别处理与http协议和email相关协议(SMTP/IMAP/POP3)有关的事件,并且确保这些事件能被以正确的顺序调用其它的一些功能模块。
    
        nginx功能模块基本上分为如下几种类型:
    
       (1) event module:搭建了独立于操作系统的事件处理机制的框架,以及提供了各具体事件的处理,包括ngx_event_module、ngx_event_core_module和ngx_epoll_module等,Nginx具体使用何种事件处理模块,这依赖于具体的操作系统和编译选项。
    
        (2) phase handler:此类型的模块也被直接称为handler模块,主要负责处理客户端请求并产生待响应内容,比如ngx_http_module模块,负责客户端的静态页面请求处理并将对应的磁盘文件准备为响应内容输出。
    
         (3) output filter:也称为filter模块,主要是负责对输出的内容进行处理,可以对输出进行修改,比如可以实现对输出的所有html页面增加预定义的footbar一类的工作,或者对输出的图片的URL进行替换之类的工作。
    
         (4) upstream:实现反向代理功能,将真正的请求转发到后端服务器上,并从后端服务器上读取响应,发回客户端,upstream模块是一种特殊的handler,只不过响应内容不是真正由自己产生的,而是从后端服务器上读取的。
    
         (5) load-balancer:负载均衡模块,实现特定的算法,在众多的后端服务器中,选择一个服务器出来作为某个请求的转发服务器。
    
          (6) extend module:根据特定业务需要编写的第三方模块。
    
    三、请求处理
    
        下面将会以http请求处理为例来说明请求、配置和模块是如何串起来的。
    
         当Nginx读取到一个HTTP Request的header时,首先查找与这个请求关联的虚拟主机的配置,如果找到了则这个请求会经历以下几个阶段的处理(phase handlers):
    
        NGX_HTTP_POST_READ_PHASE: 读取请求内容阶段
    
        NGX_HTTP_SERVER_REWRITE_PHASE: Server请求地址重写阶段
    
        NGX_HTTP_FIND_CONFIG_PHASE:配置查找阶段
    
        NGX_HTTP_REWRITE_PHASE:Location请求地址重写阶段
    
        NGX_HTTP_POST_REWRITE_PHASE:请求地址重写提交阶段
    
        NGX_HTTP_PREACCESS_PHASE: 访问权限检查准备阶段
    
        NGX_HTTP_ACCESS_PHASE: 访问权限检查阶段
    
        NGX_HTTP_POST_ACCESS_PHASE: 访问权限检查提交阶段
    
        NGX_HTTP_TRY_FILES_PHASE: 内容产生阶段
    
        NGX_HTTP_LOG_PHASE:日志模块处理阶段
    
        在内容产生阶段,为了给一个request产生正确的response,Nginx必须把这个请求交给一个合适的content handler去处理。如果这个request对应的location在配置文件中被明确指定了一个content handler,那么Nginx就可以通过对location的匹配,直接找到这个对应的handler,并把这request交给这个content handler去处理。这样的配置指令包括perl、flv、proxy_pass、mp4等。
    
        如果一个request对应的location并没有直接配置的content handler,那么Nginx依次作如下尝试:
    
       (1) 如果一个location里面有配置random_index on,那么随即选择一个文件发送给客户端。
    
       (2) 如果一个location里面有配置index指令,那么发送index指令指定的文件给客户端。
    
       (3) 如果一个location里面有配置autoindex on,那么就发送请求地址对应的服务端路径下的文件列表给客户端。
    
       (4) 如果这个request对应的location上有设置gzip_static on,那么就查找是否有对应的.gz文件存在,如果有的话,就发送这个客户端(客户端支持gzip的情况下).
    
       (5) 请求的URI如果对应的一个静态文件,static module就发送静态文件的内容到客户端。
    
       内容产生阶段完成以后,生成的输出会被传递到filter模块去进行处理。filter模块也是与location相关的。所有的filter模块都被组织成了一条链。输出会依次穿越所有的filter,直到有一个filter模块的返回值表明已经处理完成。 接下来就可以发送response给客户端了。
    

    相关文章

      网友评论

          本文标题:nginx基础

          本文链接:https://www.haomeiwen.com/subject/gfflzktx.html