nginx的安装、管理、配置与调试
阅读原文时间:2021年04月20日阅读:1

前言

记性不好,遇到的相关nginx问题和解决方法都会扩充在上面,如有问题请留言。

目录

安装nginx

装好gcc g++ 开发库环境
ubunto

$ apt-get install build-essential
$ apt-get install libtool

centos

$ yum -y install gcc automake autoconf libtool make
$ yum install gcc gcc-c++

下载nginx

下载依赖模块gzpi、rewrite、ssl

设定nginx安装目录

/usr/local/nginx/

解压nginx后编译安装

$ sudo ./configure \
--prefix=/usr/local/nginx/nginx \
--with-pcre=/usr/local/opensoft/pcre-8.39 \
--with-zlib=/usr/local/opensoft/zlib-1.2.8 \
--with-openssl=/usr/local/opensoft/openssl-1.0.1t

运行

/usr/local/nginx/sbin/nginx

查看80端口是否运行

netstat -ano | grep 80

访问 localhost ,显示Welcome to nginx! 完成安装。

管理nginx

编译安装需要自行建立nginx shell

配置nginx.conf

配置介绍

user www www;      #运行用户和组
worker_processes  number | auto;      #worker进程数,cpu总核同数量,减少cpu调度成本。
worker_cpu_affinity 01 10;     #多核绑定,位图表示法,ps -F查看,PSR列对应CPU号
pid /usr/local/webserver/nginx/nginx.pid;     #指定pid存放的路径
worker_rlimit_nofile;     #文件描述符数量
master_process on | off;     #启动进程池机制,默认on,如果设置为off,将不会建立master进程,用一个worker来处理。worker_processes也会失效。
daemon on | off;     #是否守护进程,默认on。

#任意域可配
error_log file | level     #debug | info | notice | warn | error | crit | alert | emerg  默认error,过滤前面包含后面,debug需要编译--with-debug,debug按模块控制等级,例如debug_http。

events{
  use poll;     #开启多路复用IO(linux2.6内核以上)
  worker_connections 65535;     #单个worker进程最大连接并发数
  debug_connection 192.168.1.0/24;      #单个ip段进行debug
}
http{
  include mime.types;     #包含mime.types文件
  include vhost/*.conf;     #包含vhost下的所有虚拟主机配置文件

  default_type application/octet-stream;     #指定默认的MIME类型 
  client_max_body_size 8m;                       #客户端上传的文件大小

  #设置日志格式
  log_format  name  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" $http_x_forwarded_for '
                    '"$upstream_addr" "$upstream_status" "$upstream_response_time" "$request_time"';

  #日志存放路径、格式和缓存大小,格式设定为上面定义的name
  access_log /var/log/nginx/access.log  name;
  sendfile            on;              #sendfile是个比 read 和 write 更高性能的系统接口,  反向代理时候无效,因为文件句柄是 socket。
  tcp_nopush     on;           #调用tcp_cork方法,这个也是默认的,结果就是数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,这样有助于解决网络堵塞。
  tcp_nodelay    on;           #合并小的TCP 包为一个,避免了过多的小报文的 TCP 头所浪费的带宽。如果开启了这个算法 (默认),则协议栈会累积数据直到以下两个条件之一满足的时候才真正发送出去,积累的数据量到达最大的 TCP Segment Size或收到了一个 Ack。
  server_tokens   off;         #关闭nginx 版本号,修改版本号 vi src/core/nginx.h,NGINX_VER
  gzip            on;                #启用压缩
  gzip_static     on;             #启用HTTPGzipStatic模块(不在core和standard模块组中,但rpm安装带了此模块),该模块可以读取预先压缩的gz文件,这样可以减少每次请求进行gzip压缩的CPU资源消耗。
  gzip_comp_level 5;         #压缩级别,1最小最快,9最大最慢,一般设为3
  gzip_min_length 1024;    #压缩的最小长度,小于此长度的不压缩(此长度即header中的Content-Length)
  gzip_types text/plain text/css application/x-javascript application/javascript application/xml; (什么类型的页面或文档启用压缩)

  limit_zone   myzone  $binary_remote_addr  10m;     #myzone 名字,$binary_remote_addr = $remore_addr,,10m的会话空间池
  limit_req_zone $binary_remote_addr zone=req_one:10m rate=1r/s;     #rate=1r/s 的意思是每个地址每秒只能请求一次,也就是说根据漏桶(leaky bucket)算法 burst=120 一共有120块令牌,并且每秒钟只新增1块令牌, 120块令牌发完后 多出来的那些请求就会返回503
  server{
     limit_conn one 1;                      #限制客户端并发连接数量为1
     limit_req zone=req_one burst=120;          #加上 nodelay之后超过 burst大小的请求就会直接 返回503
  }

  #反向代理时nginx需要访问的上游服务器和负载均衡策略 
  #加权轮询,基础策略,计算各个后端服务器的当前权值,选择得分最高的服务器处理当前请求。
  #ip哈希,哈希选择失败20以上或一台后端服务器,采用加权。
  #加权适用性强,不依赖客户端任何信息,能把客户端请求合理均匀的分配,劣势是同一个客户端多次请求会被分配到不同的后端服务器处理,无法满足会话保持。
  #ip哈希较好地把同一客户端的多次请求分配到同一台后端服务器,劣势是某个ip地址请求特别多(大量用户通过一个nat代理请求),会导致某台后端服务器压力非常大,其他服务器很空闲的不均衡情况。

  upstream back_end{   
    ip_hash;        #负载均衡策略,默认使用加权轮询(round robin),官方内置,一致哈希、fair第三方模块。
    server 127.0.0.1:80;                                                      #一台普通上游服务器
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;   #默认值1 和 30s,30s内连接3次失败,休息一会,30s后再来。
    server UNIX:/tmp/backend3 backup;                           #备机,不可用时,不能使用ip_hash,扰乱哈希结果违背ip_hash策略初衷。
    server 192.168.0.1:9000 down;                                    #主动宕机,不参与被选。
    server backend1.example.com weight=3;                     #权重3,默认1,与加权策略配合使用。
  }

  #取$is_args的值,定义为$my_flag,默认值为0,如果是“?”,值为1
  map $is_args $my_flag{
    default 0;
    "?"       1;
  }

  #禁止用户通过ip地址访问服务器,nginx未配置该域名或通过服务器ip来访问采用。
  server{
    listen 80 default;     #表示这个server是80端口默认的server
    return 500;             #表示任何使用这个server配置的请求将会返回500
  }

  #虚拟主机配置块
  server{   
    listen 80; #监听80端口
    server_name localhost | *.ibeiliao.com | *.* ; #主机名称,~开头的正则表达式
    keepalive_timeout 75 | 0;#超时时间,默认75s,设为0自动断连, http、location、server域中。    

    # nginx 常用变量(按阶段执行,先统一set变量)
    # curl -v -o /dev/null 'http://localhost/index.html?a=1&b=2' -H 'hello:world'
    # $uri                  : 当前请求的uri,不包含?后的参数                                             = /index.html
    # $is_args            : 当前请求是否带参数,如果有参数值为?,否则是空字符串        =?
    # $args                : 当前请求的完整参数,即?后面的字符串                                    =a=1&b=2
    # $request_uri     : 当前请求的完整URI,包含参数                                                =/index.html?a=1&b=2
    # $arg_xxx          : 当前请求的某个参数                                                        arg_a=1
    # $http_xxx         : 当前请求的xxx头部对应的值                                      http_hello= world
    # $sent_http_xxx : 返回给客户端的响应头部对应的值                                             =nginx/1.8.0
    #
    # nginx 自定义变量
    # set $max_size 10000;
    # set $new_uri /v2$request_uri
    # set $log_tag "extra action"
    #
    # location [ = | ~ | ~* | ^~ | @ ] uri { ... }
    # 例如 location /image/ {...} 匹配 /image/001.jpg
    # =   : URI必须完全匹配   
    # ~   : 大小写敏感匹配                   location ~ \.(php)$ {...} 大小写敏感处理php请求
    # ~*  : 大小写不敏感匹配               location ~* \.(png)$ {...} 忽略大小写,匹配所有的png文件
    # ^~ : 匹配前半部分即可               location ^~ /image/ {...} 匹配/image/*.* 优先级比上面低。
    # @  : 用于内部子请求,外部无法访问 

    #一个转发的location 
    location /passto {    
        proxy_set_header Host $host;            #转发原始请求的host头部
        proxy_buffering off;                           #禁用反向代理缓存,保证每次请求真实转发    
        proxy_pass http://back_end;              #转发到upstream块定义的服务器集群
        #能用try_files代替则用它,否则不要用if,官方声明if用不好的话会有bug。
        #例子:优先使用person下的图片,目录不存在则使用公共目录的图片
        if(-e "${document_root}/person"){
           rewrite ^/(.*)$ /person/$1 break;
        }
        #try_files写法
        try_files /person$uri /$uri =400;
    }      
    location / { #匹配任意URI
       root html;  #http请求根目录,静态web服务器
       alias /var/data/;   #请求目录,与root不同的是,会把location当为别名。location /image/ {...},返回/var/data/001.jpg
       index index.php; #默认index文件
       auth_basic Auth;                                      #弹出信息提示字符为Auth
       auth_basic_user_file /etc/ngx_passwd;     #账号密码
       autoindex  on;                                        #自动列出目录,禁用index
       autoindex_exact_size on;                      #设置索引文件大小的单位
       autoindex_localtime  on;                        #开启本地时间显示文件时间
    }
    #增加websocket的支持
    location /wsapp/ {
      proxy_pass http://wsbackend;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }
    location = /50x.html {
      root html;
    }
    location ~ ^(.*)\/\.svn\/{   #禁止访问SVN配置文件
       deny all;                      #禁止该匹配下的所有访问
       deny 192.168.10.1;     #禁止该ip访问,403 forbidden错误。
    }
    #下列文件缓存在本地浏览器30天
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)${
           expires 30d;
    }
    #下列文件缓存在本地浏览器1小时
    location ~ .*\.(js|css)?${
           expires 1h;
    }
    error_page 500 502 503 504 /50x.html; #错误返回页面
  }
}

nginx优点

事件驱动,nginx内部流程的向前推进基本都是靠各种事件触发来驱动的,否则nginx将一直阻塞在函数epoll_wait()或sigsuspend()这样的系统调用上。

nginx比apache更快是因为启用了epoll模式(linux kenel 2.6+),它不会随着被监控描述符数目的增长而导致效率急速下降。 而apache用的是select模式,采用遍历扫描来判断每个描述符是否有事件发生。监控的描述符数目越多,消耗也就越大。而且受系统默认限制,select模型最多只能同时监控1024个描述符。

首先,基于poll的epoll具有原生poll的优点,即同时监控的描述符个数不受限制(受进程可打开文件描述符个数限制,cat /proc/sys/fs/file-max),其次,epoll模型对事件的响应是触发式的,无需列表扫描。

epoll
1、监控描述符不受限制(受进程可打开文件描述符个数限制)
2、I/O事件响应触发(LT水平触发,不做处理内核持续通知,ET边缘触发,通知一次,更有优势)
select
1、监控最大1024个描述符
2、I/O事件轮询触发

select 标准的I/O复用模型,unix系统都提供,性能较差,nginx可编译中禁用。
poll 标准的I/O复用模型,理论上比select优,同select类似。
epoll Linux 2.6+上正式提供的更为优秀的I/O复用模型
kqueue FreeBSD4.1+、OpenBSD2.9+、NetBSD2.0、OS X上特有的更优秀的I/O复用模型
eventport 系统Solaris 10上可用的高性能I/O复用模型
/dev/poll 同上
rtsig 实时信号模型(real time signals)
aio 异步I/O

多路复用模型
例子:如果要监控10条高速公路堵车(是否可读),需要10个人(10个线程,10处代码)来做这件事,利用某种技术把10条马路的情况统一传达到某个中心,那么只需要1个人在中心进行监控就行了。而select或epoll这样的多路I/O复用机制好比摄像头的功能,能把多个I/O端口的状况反馈到一处,比如某个特定的文件描述符上,这样,应用程序只需要利用对应的select()或epoll_wait()系统调用阻塞关注一处即可。

调试nginx

遇到性能瓶颈(strace -T 跟踪消耗时间)、启动失败、响应数据与预期不一致、莫名其妙的Segment ation Fault段错误。

ps aux | grep nginx

状态为Ts(s代表Nginx进程为会话的首进程,session leader,T代表处在TASK_STOPPED状态)

使用gdb | cgdb 调试
1、编译nginx的时候绑定gdb
2、修改nginx为一个工作进程,关闭守护进程。
3、开始调试gdb -q -p 4614

使用strace(系统调用)/pstack(内部函数)调试
1、strace -p 4033
2、wget 127.0.0.1 函数

其他调试
System Tap/

参考

  • 深入剖析 nginx – 高群凯
  • 实战nginx:取代apache的高性能web服务器 – 张宴
  • ningx.cn