• Nginx系列4之基础配置


    preface

    公司跑得大多数是LNMP平台,所以借此机会多多了解下Nginx。下面主要说说Nginx下面几点:

    1. 防盗链
    2. 日志切割
    3. 负载均衡
    4. 虚拟主机
    5. location匹配解释
    6. substatus状态模块
    7. 平滑重启

    what's the difference in nginx and apache

    the same
    1 都采用模块化设计,支持通用的语言接口,如php,perl,python
    2 都支持正向反向代理,虚拟主机,url重写,压缩传输,ssl加密等。

    different
    1 apache 处理速度慢,采用select模型,占用很多的资源
    2 apache所有模块支持动静编译,而nginx支持静态编译。
    3 apache对FCGI支持不太好,而Nginx对FCGI支持很好。

    About Module

    nginx模块从结构上分为核心模块、基础模块和第三方模块,HTTP模块、event模块和MAIL模块等属于核心模块,HTTP Access模块、HTTP FastCGI模块、HTTP proxy模块和HTTP Rewrite属于基础模块。而HTTP upstream Request Hash模块、Notice模块和HTTP Access Key模块属于第三方模块。用户根据自己的需要开发的模块都是属于第三方模块,正是有了这些第三方模块,Nginx功能才会强大。

    Nginx模块从功能上分为三类:

    • Handlers(处理器模块)
      此类模块直接处理请求,并进行输出内容和修改headers信息等操作,Handlers处理器模块一般只能有一个。
    • Filters(过滤器模块)
      这类模块主要针对其他处理器模块输出的内容进行修稿操作,最后由Nginx输出。
    • Proxies(代理类模块)
      这类模块是Nginx的HTTP Upstream之类的模块,这些模块主要与后端一些服务,比如FastCGI等进行交互,实现服务反向代理和负载均衡等功能。

    Nginx模块处理HTTP的请求流程图如下所示:

    在工作模式上,nginx分为单工作进程和多工作进程模式。在单工作进程模式下,除主进程之外,还有一个工作进程,工作进程都是单线程的;在多工作进程模式下,每个工作进程包含多个线程。Nginx默认为单工作进程模式。
    Nginx的模块直接被编译进Nginx,因此属于静态编译的方式。启动Nginx后,Nginx 的模块自动加载,不像Apache一样,首先将模块编译为一个so文件,然后在配置文件中指定是否加载,在解析配置文件的时候,Nginx的每个模块都有可能去处理某个请求,但是同一个处理请求只能是一个模块来完成的。

    正常执行起来后的Nginx会有多个进程,最基本的有Master process(即监控进程,也叫主进程)和worker process(即工作进程),还可能有cache相关进程。这些进程之间相互通信,以 传递一些信息(主要是监控进程往工作进程传递)。除了自身进程之间的相互通信,Nginx还凭借强悍的功能模块与外界四通八达,比如通过upstream与后端Web服务器通信、依靠factcgi与后端应用程序服务器进行通信。一个简单的的整体框架结构。
    image

    Nginx配置文件的内部关系。

    nginx配置文件分为4部分,main(全局设置),server(主机配置),upstream(负载均衡服务器配置),和location(URL匹配特定位置的设置)

    main设置的指令将影响其他的所有设置;server部分的指令主要用于指定的主机和端口,upstream主要用户负载均衡,设置一系列的后端服务器;location部分用于匹配网页的位置,这四者关系如下:
    server继承main,location继承server,upstream既不会继承其他的设置,也不会被继承。
    配置文件结构顺序如下:
    image

    配置文件解读

    events和main

    user  nginx;
    worker_processes  1;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    • user
      是主模块指令,指定Nginx worker进程运行的用户和用户组,默认是nobody运行
    • work_processes
      是主模块指令,指定了nginx要开启的进程数,每个nginx进程平均耗费10MB-12MB内存,根据经验,一般指定一个进程就足够了,如果是多核CPU,建议指定和CPU的数量一样多的进程数即可。
    • error_log:
      主要模块指令用来定义全局错误日志文件,日志输出级别有debug,info,notice,warn,error,crit可选择,debug日志最为详细,而crit输出日志最少。
    • work_rlimit_nofile:
      用于绑定worker进程和CPU的
    • events
      用来设定nginx的工作模式和连接数上限。
    • use
      是个事件模块指令,用来指定nginx的工作模式,。nginx支持select,poll,kqueue,epoll,rtsig和/dev/poll。其中select和poll是标准的工作模式。kqueue和epoll是高效的工作模式。需要注意的是epoll是在linux平台上的,而kqueue用在BSD系统中。
    • work_connections
      也是事件模块指令。用于定义nginx每个进程的最大连接数,默认1024,最大的客户端连接数由worker_processes和worker_connectons决定。即max_client = worker_processes * worker_connections,在作为反向代理时,变为max_clients = worker_processes * worker_connections/4
      进程的最大连接数受Linux系统进程的最大打开文件数限制,在执行操作系统命令ulimit -n 65536 后,worker_connections 的设置才能生效。

    http

    http {
        include       /etc/nginx/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"';
        log_format download"   '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status  $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$"';
        access_log  /var/log/nginx/access.log  main;
    
        sendfile        on;
        tcp_nopush     on;
        tcp_nodelay  on;
    
        client_max_body_size 20m;
        client_header_buffer_size 32k;
        large_client_header_buffers 4 32k;
        keepalive_timeout  65;
    
        #gzip  on;
    
        include /etc/nginx/conf.d/*.conf;
        client_header_timeout 10;
        client_body_timeout 10;
        send_timeout   10;
    }
    
    • default_type
      属于http核心模块的指令,这里设定的默认类型为二进制流,也就是当文件类型未定义时使用这种方式,例如在没有配置php环境时,Nginx是不予解析的,此时,用浏览器访问php文件就会出现下载窗口。
    • log_format main
      是Nginx的httplog模块指令,用于指定Nginx日志的输出格式。main为此日志输出格式的名称,可以在下面的access_log指令中引用。
    • client_max_body_size
      用来设置允许客户端请求的最大单个文件字节数。
    • client_header_buffer_size
      用于指定来客户端请求头的headerbuffer大小。对于大多数请求,1KB的缓冲区大小已经足够了,如果自定义了消息头或者有更大的cookie,可以增加缓冲区大小。这里设置为32KB.
    • large_client_header_buffers
      用来指定客户端请求中较大的消息头的缓存最大数量和大小,4为个数,128k 为大小,最大缓存为4个128KB。
    • sendfile
      参数用来开启高效文件传输模式。将tcp_nopush 和 tcp_nodely两个指令设置为on,用于防止网络堵塞。
      keepalive_timeout用于设置客户端连接保持活动的超时时间,如果超过这个时间后,服务器会关闭这个连接。
    • client_header_timeout
      用于设置客户端请求头预读取超时时间。如果超过这个时间,客户端还没有发送任何数据,Nginx将返回“Request time out(408)”错误。
    • client_body_timeout
      用于设置客户端请求主体读取超时时间,默认值为60.如果超过这个时间,客户端还没有发送任何数据,Nginx将返回“request time out(408)”错误。
    • send_timeout
      用于指定响应客户端的超时时间。这个超时仅限与两个连接活动之间的时间,如果超过这个时间,客户端没有任何活动,nginx将会关闭这个连接。

    关于location匹配

    localtion既可以支持正则表达,也可以支持条件判断。

    1. 匹配后缀名
      通过后缀名来匹配(.gif,jpg,jpeg,png)等交给nginx处理,expires过期时间为30天
    location ~ .*.(gif|jpg|png|bmp)$ {
    root /web/baidu;
    expires 30d;
    }
    
    1. 匹配url路径
      将upload和html下所有文件交给Nginx来处理。
    location ~ ^/(upload|html)/ {
    root /var/www/;
    expires 30d;
    }
    
    1. 动静分离(把动态的交给tomcat)
      把jsp结尾的动态网页交给本地的开放8080端口处理。
    location ~ .*.jsp$ {
    index index.jsp;
    proxy_pass http://localhost:8080;
    }
    

    下面说说location匹配第一个参数的意思

    • ~
      波浪线表示执行一个正则匹配,区分大小写
    • ~*
      表示执行一个正则匹配,不区分大小写
    • ^~
      ^~表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录
    • =
      进行普通字符精确匹配
    • @
      "@" 定义一个命名的 location,使用在内部定向时,例如 error_page,try_files

    location 匹配的优先级(与location在配置文件中的顺序无关)
    = 精确匹配会第一个被处理。如果发现精确匹配,nginx停止搜索其他匹配。
    普通字符匹配,正则表达式规则和长的块规则将被优先和查询匹配,也就是说如果该项匹配还需去看有没有正则表达式匹配和更长的匹配。
    ^~ 则只匹配该规则,nginx停止搜索其他匹配,否则nginx会继续处理其他location指令。
    最后匹配理带有"~"和"~*"的指令,如果找到相应的匹配,则nginx停止搜索其他匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。

    Nginx常用模块

    Gzip model

    nginx如何查看是否安装了HttpGzip模块:

    [root@salt ~]# nginx -V
    nginx version: nginx/1.10.1
    此处省略一万字.............  如果包含了--with-http_gzip_static_module 表示启用了gzip模块。
    gzip on;  ------>  on表示开启了gzip压缩功能
    gzip_min_length 1k;
    gzip_buffers  4  16k;
    gzip_http_version 1.1;
    gzip_comp_level 2;
    gzip_type text/plain application/x-javascript text/css application/xml;
    gzip_vary on;
    
    • gzip_min_length
      用于设置允许压缩的页面最小字节数,页面字节数从header头的Content-Length中获取。默认值是0,不管页面多大都进行压缩。建议设置成大于1K的字节数,小于1K可能越压越大。
    • gzip_buffers
      表示申请4个单位为16k的内存作为压缩结果流缓存,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果。
    • gzip_http_version
      用于设置识别HTTP协议版本,默认是1.1,目前大部分浏览器已经支持gzip解压了,使用默认即可。。
    • gzip_comp_level
      用来指定gzip压缩比,1压缩比最小,处理数据最快,9压缩比最大,传输速度最慢,但处理最慢,也比较消耗CPU资源。
    • gzip_types
      用来指定压缩类型,无论是否指定,“text/html”类型总是会被压缩的。
    • gzip_vary
      选项可以让前端的缓存服务器缓存经过gzip压缩的页面,例如,用squid缓存经过Nginx压缩的数据

    upstream模块

    pstrem  baidu.com{
     	ip_hash:
                    server 192.168.1.1:80;
                    server 192.168.1.2:80  down;
        server 192.168.1.3:80  max_fails=3    fail_timeout=20s;	
    }
    

    upstream 是Nginx的http upstream模块,这个模块通过调度算法来实现负载均衡。上诉实例配置中,upstream指定了一个负载均衡器的名称是baidu.com。这个名称可以任意指定,在后面需要调度的地方直接调用即可。
    目前有4中调度算法。

    1. 轮询(默认的),后台宕机后自动剔除
    2. Weight。加权,权重越高,接收到的流量也越大。
    3. ip_hash ,每个请求按照访问IP的hash结果分配,这样来自一个ip的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题(此时不能使用weight和backup的。)。
    4. fair。这是比上面2个更加智能的负载均衡算法。这种算法可以依据页面大小和加载时间长短智能的进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应快的优先分配。。nginx本身不支持fair,如果需要这种调度算法,必须下载Nginx的upstream_fair模块。
    5. url_hash 。 此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器。进一步提供后端缓存服务器的效率。本身不知道这种url_hash的。。如果需要使用这种调度算法。必须安装Nginx的hash软件包。

    除了定义调度算法,还可以设定后端服务器在调度中的状态。常用的状态有:

    1. down: 表示不参与负载均衡
    2. backup,备份服务器,当所有的非backup服务器响应差或者宕机后,才会请求backup服务器。
    3. max_fails: 允许请求的失败的次数,默认为1.当超过最大次数时,返回proxy_next_upstream模块定义的错误。
    4. fail_timeout。在经历了max_fails次失败后,暂停服务器的时间,max_fails和failtimeout一起使用。

    虚拟主机

    server {
    listen 80;
    server_name 192.168.12.188  www.baidu.com;
    index index.html index.htm index.jsp;
    root /web/www/html;
    charset gb2312;
    }
    include /etc/nginx/nginx_vhost2.conf
    
    • server
      表示虚拟主机开始,
    • listen
      用于指定虚拟主机的服务器端口。
    • server_name
      用来指定ip地址或者域名,多个域名空格隔开。
    • index
      用于设置默认首页。
    • root
      表示指定虚拟主机的网页根目录,既可以觉得路径,也可以相对路径。
    • charset
      设置网页的默认编码。

    一般使用include来包含虚拟机配置文件,方便管理。

    status模块

    stubstatus模块能够获取nginx自上次启动依赖的工作状态,此模块非核心模块,需要编译安装。
    以下配置是启动nginx工作状态的功能。

    location /NginxStatus {
    stub_status	on;	---> 表示启用stubstatus砖头统计功能。
    access_log 	logs/NginxStatus.log;
    auth_basic	"NginxStatus";
    auth_basic_user_file 	../httppasswd;
    }
    
    
    • auth_basic
      是nginx的一种认证机制;
    • auth_user_file
      用来指定认证的密码文件,用于Nginx的auth_basic认证采用的是与Apache兼容的密码文件,因此需要用Apache的htpasswd命令来生成密码,如果没有htpasswd命令,请先安装httpd。,例如添加一个webadmin用户,采用下面方式生出密码文件:
    [root@salt ~]# htpasswd -c /var/www/html/httppasswd webadmin
    New password: 
    Re-type new password: 
    Adding password for user webadmin
    

    然后启动nginx,我们访问http://server_ip/NginxStatus,输入刚才创建的用户名密码,就能看到状态信息了。

    notice:
    设置了虚拟主机错误信息会返回页面,通过error_page指令可以定制各种错误信息的返回页面,在默认情况下,Nginx会在主目录的html目录中查找指定的返回页面,特别注意的是,错误页面大小一定要大于512kb,否则会被IE浏览器替换成IE默认的错误页面.

    error_page 404	/404.html;
    error_page 501 502 503  /50x.html;
    location = /50x.html {
    root html;
    }
    

    Nginx的启动,关闭,平滑重启

    1. nginx基本配置文件检查
    1 nginx基本配置文件检查;
    [root@salt ~]# nginx -t
    [root@salt ~]# nginx -t -c /etc/nginx/nginx.conf 
    
    1. 版本信息和编译信息检测
    [root@salt ~]# nginx -V
    
    1. 信号灯
      nginx 对进程的控制能力非常强大,可以通过信号指令控制进程。常用的信号有
    • QUIT 关闭进程
    • HUP 表示重新加载配置,也就是关闭原有的进程,开启新的进程。此操作不会中断用户的访问请求,因此可以通过此信号平滑重启Nginx。
    • USR1 用于Nginx的日志切换,也就是重新打开一个日志文件。例如每天要生成一个新的日志文件时,可以使用这个信号来控制。
    • USR2 用于平滑升级可执行程序
    • WINCH 从容关闭工作进程。
    [root@salt ~]# ps -ef |grep nginx
    root     121833 120871  0 Aug15 ?        00:00:00 nginx: master process nginx
    1000     124785 121833  0 00:39 ?        00:00:00 nginx: worker process
    1000     124786 121833  0 00:39 ?        00:00:00 nginx: worker process
    1000     124787 121833  0 00:39 ?        00:00:00 nginx: worker process
    1000     124788 121833  0 00:39 ?        00:00:00 nginx: worker process
    root     124794 122312  0 00:39 pts/3    00:00:00 grep nginx
    [root@salt ~]# kill -HUP  121833		#平滑重启nginx
    

    实践之配置负载均衡实例

    
    http{
        upstream myserver{
            server 192.168.1.1:80 weight=3 max_fails=3 fail_timeout=20s;
            server 192.168.1.2:80 weight=1 max_fails=1 fail_timeout=30s;
            server 192.168.1.3:80 weight=5 max_fails=3 fail_timeout=30s;
    }
        server{
            listen 80;
            server_name    www.baidu.com 192.168.1.100;
            index index.html index.htm;
            root /var/www/html;
        }
        location / {
            proxy_pass http://myserver;
            proxy_next_upstream http_500 http_503 error timeout invalid_header;
            include /etc/nginx/proxy.conf;
        }
    }
    

    配置讲解:
    在上面配置实例中,先定义了一个负载均衡组myserver,然后在location部分通过proxy_pass http://myserver 来调用负载功能,其中

    • proxy_pass 指令用来指定代理的后端服务器地址和端口,地址是主机名或者IP地址,也可以是通过upstream指令设置的负载均衡组名称。
    • proxy_next_upstream用来定义故障转移策略,当后端服务器节点返回500,502,503 和执行超时等错误时,自动将请求转发到upstream负载均衡组中的另一台服务器,实现故障转移。

    最后通过include指令包含进来一个proxy.conf的文件。
    接下来看看proxy.conf文件内容:

    [root@salt ~]# cat /etc/nginx/proxy.conf
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    client_body_buffer_size 128k;
    proxy_connect_timeout	90;
    proxy_send_timeout 90;
    proxy_buffer_size 4k;
    proxy_buffers 4 32k;
    proxy_busy_buffers_size 64k;
    proxy_temp_file_write_size 64k;
    

    Nginx的代理功能是通过http proxy模块来实现的。默认是安装Nginx时候已经安装好了http proxy模块,因此可以直接使用http proxy模块,详解proxy.conf内容:

    • proxy_set_header:
      设置后端的服务器器获取主机名或者真实IP地址,以及代理者的真实IP地址;
    • client_body_buffer_size:
      指定客户端请求主体缓冲区大小,可以理解为先保存到本地再传给用户。
    • proxy_connect_timeout:
      表示与后端服务器连接的超时时间,即发起握手等候响应的超时时间。
    • proxy_send_timeout:
      表示后端服务器的数据回传时间,即在规定时间之内后端服务器必须传完所有的数据,否则,Nginx断开这个连接。
    • proxy_read_timeout:
      设置Nginx从后代理的后端服务器获取信息的时间,表示连接建立成功后,Nginx等待后端服务器的响应时间,其实是Nginx已经进入后端的排队之中等候处理。
    • proxy_buffer_size:
      设置缓冲区大小,默认该缓冲区大小等于指令proxy_buffers设置大小
    • proxy_buffers:
      设置缓冲区的数量和大小。Nginx从代理的后端服务器获取响应的信息,会放置到缓冲区。
    • proxy_busy_buffers_size:
      用于设置系统很忙时可以使用的proxy_buffers的大小,官方推荐的大小为proxy_buffers * 2
    • proxy_temp_file_write_size:
      指定proxy缓存临时的文件的大小。

    防盗链配置

    nginx防盗链功能也特别强大,在默认配置下,只需要简单配置既可以实现防盗链功能。

    location ~*  .(jgp|gif|png|swf|flv|wma)$ {
        valid_referers none blocked *.ljf.com  ljf.com;
        if ( $invalid_referer){
            rewrite ^/ http://www.ixdba.net/img/error.gif;
        }
    }
    

    在上面的配置中,对jgp,gif,png,swf,flv,wma后缀的进行防盗链处理。
    表示从这个域名来的请求可以正常访问,后则跳转到rewrite指定的页面。
    if(){}是说,如果上面的地址不是指定的地址,那就跳转到通过rewrite指定的地址,也可以直接return403错误。
    倘若还需要做更复杂的防盗链处理,可以使用Nginx的HttpAccessKeyModule模块来实现,具体参考官网。

    不进行正则匹配,只要是/images就行

    location /images {
        root /opt/nginx/html;
        valid_referers none blocked *.ljf.com  ljf.com;
        if ($invalid_referer){
            return 403;
        }
    }
    

    在上面的配置中,对jgp,gif,png,swf,flv,wma后缀的进行防盗链处理。
    表示从这个域名来的请求可以正常访问,后则跳转到rewrite指定的页面。
    if(){}是说,如果上面的地址不是指定的地址,那就跳转到通过rewrite指定的地址,也可以直接return403错误。
    倘若还需要做更复杂的防盗链处理,可以使用Nginx的HttpAccessKeyModule模块来实现,具体参考官网。

    日志切割

    Nginx没有没有类似于apache的cronolog日志分割处理的功能,但是如果通过Nginx的信号控制功能可以实现日志的切割,我们通过这个方式来写一个脚本,如下所示:

    #/bin/bash
    savepath_log = '/home/nginx/logs'
    nglogs = '/opt/nginx/logs'
    
    mkdir -p $savepath_log/$(date +%Y)/$(date +%m)
    mv $nglogs/access.log   $savepath_log/$(date +%Y)/$(date +%m)/access.$(date +%Y%m%d).log
    mv $nglogs/access.log   $savepath_log/$(date +%Y)/$(date +%m)/error.$(date +%Y%m%d).log
    kill -USER1 nginx's_pid
    

    把nginx's_pid 换成nginx的pid,就可以实现日志切割了。通过nginx的USR1实现日志的自动切换功能。

  • 相关阅读:
    MySQL 之 Metadata Locking 研究
    Spring, MyBatis 多数据源的配置和管理
    ThreadLocal 源码剖析
    Java多线程中的死锁问题
    Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)
    PriorityQueue和Queue的一种变体的实现
    被我们忽略的HttpSession线程安全问题
    Java并发之原子变量和原子引用与volatile
    使用Java实现单线程模式
    这些年无处安放的博客
  • 原文地址:https://www.cnblogs.com/liaojiafa/p/6130362.html
Copyright © 2020-2023  润新知