nginx(1)

下一篇:nginx(2)

一、engin X

市场的服务器非常的多,这里简单介绍几种常用的。

  • Apache:源代码开放,跨平台,可移植,且支持的模块非常丰富,虽然在速度性能上不如其他轻量级的web服务器,属于重量级产品,消耗的内存比其他的服务器更高。
  • Lighttpd:德国人写的开源软件。功能也非常丰富,拥有内存开销低,CPU占用率低,性能好,以及模块丰富等特点。支持FastCGI,CGI,Auth,输出压缩,URL重写以及Alias等等重要功能。与nginx相同,是轻量级别的服务器。
  • Tomcat: Tomcat实现了Apache-Jakarta规范,且比绝大多数的商业服务器要好,但是对静态文件,高并发处理的能力比较弱。
  • IBM WebSphere:功能完善、开放的Web应用程序服务器,是IBM电子商务计划的核心部分,基于Java的应用环境。是IBM的一整套产品,范围从简单到高级,直到企业级。
  • Microsoft IIS: 微软的Web服务器,只能运行于微软的平台上,提供了图形化的管理工具。

1.1 简介

  相对于httpd(apache),nginx是比较新的服务器了,现代服务器程序中,并发的压力越来越大,以httpd中的prefork模型为例,由于使用的是select函数,有1024的并发限制(关于linux io模型:http://www.cnblogs.com/carl10086/p/5926153.html ),对于上万个并发请求而言,prefork显得力不从心,因此出现了一个著名的问题C10K,一万个并发请求问题,而nginx就是被设计用来解决C10k问题的 ,nginx是一个开源的HTTP server和reverse proxy(反向代理服务器),同样也是一个IMAP/POP3 proxy。

nginx从2014年开始推出企业版,同时也一如既往维护着开源版本,针对nginx,也有很多的二次开发版本,比如阿里巴巴的tengine还有openresty等等...

1.2 选择Nginx的理由

(1) 高并发连接:官方测试5W的并发,实际生产中可支撑2~4W的并发。
nginx使用的是epoll(linux 2.6内核),即信号驱动(signal driver)的IO的模型。

(2) 内存消耗非常少: Nginx+PHP(FastCGI)服务器在3W并发下,开启10个Nginx进程的消耗为150MB左右内存左右(15*10MB),而开启的64个php-cgi进程消耗1280MB内存,同等硬件环境下,Nginx的并发处理能力应该是Apache的5~10倍。

(3) 成本低:nginx采用的是2-clause BSD-like协议,可以免费被用于商业用途。

其他的优点:

  • 配置简单
  • 支持Rewrite:丰富的Rewrite
  • 内置健康监测
  • 节省带宽:可以压缩
  • 稳定:企业级
  • 支持热部署:甚至于在不停止服务的情况下进行nginx升级

1.3 基本功能

(1) 静态资源的web服务器

(2) http的反向代理服务器

(3) pop3, smpt, imap4等邮件协议的反向代理

(4) 能缓存打开的文件(元数据),支持FastCGI (php-fpm),uWSGI(Python Web Framework)等协议

(5) 模块化,比如一些著名的模块功能:压缩模块zip,SSI模块,SSL模块...

1.4 架构简介

nginx架构文档地址:http://www.aosabook.org/en/nginx.html

 说明: 

  (1) master/worker 一个master进程,可以生成一个或者多个worker进程,其中

    maseter: 加载配置文件、管理worker进程、平滑升级

    worker: Http服务,http代理,fastcig代理...

  (2) 支持Advanced I/O,sendfile, AIO, mmap etc

  (3) 支持Multiplexing via kevent 事件驱动机制,在Linux上是epoll,在FreeBSD上是kqueue,在Solaris上市/dev/poll

  (4) 代理时还支持缓存功能:有2个组件Cache loader, Cache manager

  (5) 模块类型:

      核心模块:core module

      Standard HTTP module

      Optional HTTP modules

      Mail Modules

      3rd party modules

1.5 安装

Nginx的一些模块需要其他第三方库的支持:
gzip需要zlib
rewrite需要pcre
ssl需要openssl
因此,如果在centos环境下:

yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel

支持centos通用软件的大多数安装方式。

(1) yum源安装

由epel(著名可信任的第三方Yum源)提供,因此需要配置epel源,这里简单配置一个阿里的epel源,虚拟机是Centos7:

 wget -P /etc/yum.repos.d/ http://mirrors.aliyun.com/repo/epel-7.repo  
yum info nginx #查看nginx版本

发现yum源中提供的nginx版本是:

Available Packages
Name        : nginx
Arch        : x86_64
Epoch       : 1
Version     : 1.10.2
Release     : 1.el7
Size        : 505 k
Repo        : epel
Summary     : A high performance web server and reverse proxy server
URL         : http://nginx.org/
License     : BSD
Description : Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and
            : IMAP protocols, with a strong focus on high concurrency, performance and low
            : memory usage.

(2) 源码编译安装

# 准备编译环境:
yum groupinstall "Development Tools" "Server Platform Development"
# 如果需要ssl模块,依赖于ssl
yum install -y openssl-devel
# 如果用到url重写,依赖于pcre
yum install -y pcre-devel
# 如果启用压缩
yum install -y zlib
useradd -r nginx
# 下载源代码,这里用的版本是1.8.1,并且解压缩到/usr/local目录下
# 查看帮助: ./configure --help | less
./configure --prefix=/usr/local/nginx --conf-path=/etc/nginx/nginx.conf --user=nginx --group=nginx  --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx/nginx.pid --lock-path=/var/lock/nginx.lock --with-http_ssl_module --with-http_stub_status_module --with-http_gzip_static_module --with-debug
make && make install

 二、基本配置

官方文档:http://nginx.org/en/docs/

主配置文件nginx.conf,主配置文件中可以使用Include的方式引入其他的配置文件,注意配置文件中每个指令都必须以;结尾,并且支持使用变量以及自定义变量的方式。

首先来看一个简单的配置以了解其大体结构:

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

# 使用的用户和组
user nginx;
# 指定工作衍生的进程数(一般等于CPU的总数或者总核数的2倍)
worker_processes 2;
# 指定错误日志的存放路径,级别有{debug|info|notice|warn|error|crit}
error_log /var/log/nginx/error.log crit;
# 指定pid存放的路径
pid /run/nginx.pid;

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

#指定文件描述符的数量
worker_rlimit_nofile 51200;
events {
    # 指定使用的网络I/O模型,Linux推荐使用epoll,FreeBSD推荐kqueue
    use epoll;
    # 允许的连接数
    worker_connections 51200;
}

http {
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    # 设置字符集,如果一个网站有多种字符集这里不设置,让程序员在HTML通过Meta标签设置
    #charset utf8;

    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;
    
    # 设置客户端能够上传文件的大小
    client_max_body_size 8m;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    # 开启gzip压缩
    gzip                on;
    gzip_min_length     1k;
    gzip_buffers        4 16k;
    gzip_http_version   1.1;
    gzip_comp_level     2;
    gzip_types          text/plain application/x-javascript text/css application/xml;
    gzip_vary           on;

    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;



    # 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;
        server_name  www.ysz211.com ysz211.com;
        index        index.html index.htm index.jsp
        root         /usr/share/nginx/html;
        
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }
        
        location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
            expires   30d;
        }

        location ~ .*.(js|css)$ {
            expires   1h;
        }

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

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

# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2 default_server;
#        listen       [::]:443 ssl http2 default_server;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers HIGH:!aNULL:!MD5;
#        ssl_prefer_server_ciphers on;
#
#        # 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 {
#        }
#    }

}

通过上面配置,可以发现:

  • 主配置即全局配置,对http模块以及Mail模块都会生效
  • event{...}: 事件驱动的相关配置
  • http{...}: http模块的配置段
  • mail{...}: mail模块的配置段,如果没有mail模块,则无需该配置段
  • main配置段中一般用来配置全局功能

三、虚拟主机配置

什么是虚拟主机?
假如你要在一台服务器上部署多个应用,或者是多个网站,你需要对服务器上的应用进行逻辑上的区分,一个虚拟主机就是一个"应用"。每台虚拟主机都可以是一个独立的网站,可以有独立的域名,具有完整的Internet服务器功能(WWW FTP Email)等,同一台主机上的虚拟主机之间是完全独立的。从访问者的角度而言,每一台虚拟主机和一台独立的主机完全一样。

虚拟主机是逻辑上的主机概念,不是物理上的。

基于IP的虚拟主机:

Linux、FreeBSD操作系统都支持IP别名。IP别名的概念非常简单:在一块物理网卡上绑定多个IP地址。这里使用ip别名来模拟基于IP的虚拟主机。

ifconfig eno16777736:1 192.168.1.210 broadcast 192.168.1.255 netmask 255.255.255.0 up
route add -host 192.168.1.210 dev eno16777736:1

相关nginx配置如下:

    server {
        listen       192.168.1.211:80;
        server_name  192.168.1.211;
        # Load configuration files for the default server block.
        access_log /var/log/nginx/server1.access.log combined;
        location / {
            root /usr/share/nginx/first;
            index index.html index.htm index.jsp;
        }
    }

    server {
        listen       192.168.1.210:80;
        server_name  192.168.1.210;
        # Load configuration files for the default server block.
        access_log /var/log/nginx/server2.access.log combined;
        location / {
            index index.html index.htm index.jsp;
            root /usr/share/nginx/second;
        }
    }

基于域名的虚拟主机:

最常见的虚拟主机。只需要把多个域名配置到DNS服务器即可。这种技术可以使多个虚拟主机可以使用一个IP地址,有效的解决了IP地址不足的问题。

    server {
        listen       80;
        server_name  www.ysz211.com;
        # Load configuration files for the default server block.
        access_log /var/log/nginx/server1.access.log combined;
        location / {
            root /usr/share/nginx/first;
            index index.html index.htm index.jsp;
        }
    }

    server {
        listen       80;
        server_name  web.ysz211.com;
        # Load configuration files for the default server block.
        access_log /var/log/nginx/server2.access.log combined;
        location / {
            index index.html index.htm index.jsp;
            root /usr/share/nginx/second;
        }
    }

四、日志切割

与Nginx日志相关的指令主要有2条,一条是log_format,用来设置日志的格式,另外一条是access_log,用来指定存放路径、格式和缓存大小。两条指令在Nginx配置文件中的位置可以在http{...}之间,也可以在虚拟主机之间,即server{....}之间。

用log_format指令来设置日志格式:

语法:

log_format name string ...;

其中name表示定义的格式名称,string表示格式样式。log_format有一个默认的无须设置的combined日志格式,相当于apachecombined日志格式,其参数如下所示:

log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';

也可以自己定义一份日志的记录格式,不过要注意,log_format指令设置的name名称要在Nginx配置文件中是不能重复的。

当有代理服务器时,后端服务器Nginx$remote_addr拿到的是ip地址,一般代理服务器会记录X-Forwarded-For信息的IP地址,才是真是IP。此时可以自定义mylogformat

log_format mylogformat '$http_x_forwarded_for - [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';

用access_log指令指定日志存放的路径:

语法:

access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;

其中path表示存放路径,format表示格式名称,buffer=size表示内置缓冲区的大小。

用法如下:
(1) access_log off 表示关闭日志
(2) 可以使用默认的combined格式的日志,示例:

access_log /data1/logs/filename.log;

或者

access_log /data1/logs/filename.log combined;

(3) 也可以使用自定义的日志记录

access_log /data1/logs/access.log mylogformat buffer=32k;

(4) 在0.7.4之后的版本,access_log指令中的日志文件路径可以包含变量,例如:

access_log /data1/logs/$server_name.log combined;

但是此时会有限制:

  • Nginx设置的用户和组必须对该路径有权限
  • 缓冲无法被使用
  • 必须使用open_log_file_cache指令来设置经常被使用的日志文件的描述符缓存来提高性能

open_log_file_cache用法:

open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
  • max: 设置缓存中的最大文件描述符数量。如果超过,使用LRU算法清除
  • inactive:设置一个时间,如果在设置的时间内没有使用文件描述符,则自动删除,默认是10s
  • min_uses: 在inactive时间内,日志文件超过被使用的次数,则日志文件的描述符记录缓存,默认为1
  • valid: 设置多长时间检查一次,查看变量指令的日志文件路径与文件名是否仍然存在。默认是60s。
  • off: 禁止使用缓存。

例如:

open_log_file_cache max=1000 inactive=20s min_uses=2 valied=1m;

日志文件的切割:

生产环境中,由于访问日志的文件增长速度非常快,因此,必须对日志文件进行定时切割,即按照时间进行切割,最常用是按照天。
nginx不自动支持日志的轮转,但是如果指定了pid,可以使用kill -USER1 nginx进程号的方式来让nginx重新生成一份access_log文件。

#!/bin/bash
# 这个脚本必须在每天的00:00运行
logs_path="/data1/logs/"
yesterday_path=${logs_path}$(date -d "yesterday" + "%Y")/$(date -d "yesterday" + "%m")/
mkdir -p ${yesterday_path}
mv ${logs_path}access.log ${yesterday_path}access_$(date -d "yesterday" +"%Y%m%d").log
kill -USER1 `cat /run/nginx.pid`

最后配置crontab定时任务即可。

crontab -e
00 00 * * * /bin/bash /usr/local/nginx/sbin/cut_nginx_log.sh

附:参数说明

(1) Nginx运行基础配置

  • use
Syntax:    use method;
Default:    —
Context:    events

 指明Linux的IO模型,不用指明,默认nginx会自动使用linux系统中最高效的方式

  •  user USERNAME [GROUPNAME];

    nginx中是master worker架构,这里指定的是Nginx worker进程的属组 属主

    user nginx nginx

  • pid /PATH/TO/PID_FILE;

     指定nginx进程的pid文件

    pid /var/run/nginx.pid

  • worker_rlimit_nofile #;

     指定一个worker进程所能打开的最大文件描述数量;一个worker进程要支持并发,linux处处皆文件,一个连接至少一个socket文件

(2) 性能优化基础配置

  • worker_processes #;

    用来指定worker进程的个数,通通常是物理CPU核心数量-1

    可以设定为"auto",实现自动设定为当前CPU核心数量

  • worker_cpu_affinity CPUMASK CPUMARK ...;

    CPUMASK: 

         0000 0001

         0000 0010

         0000 0100

         ...

    worker和CPU绑定,不管worker运行的cpu如何切换,只能在指定的cpu上,绑定之后可以使用命令ps axo command,pid,psr查看绑定情况

  • worker_priority nice;

    指明进程的nice值[-20,19] ,nice值越小,优先级越高

  • accept_mutex 
Syntax:    accept_mutex on | off;
Default:    
accept_mutex off;
Context:    events

  接收请求的互斥机制,是否让worker依次接收用户请求,否则当一个请求报文到达,所有的worker都会被Notfied。不过在支持epoll()的linux内核中,如果使用时reuseport参数可以不用配置这个。注意,在1.11.3版本之前的默认值是on。

  • lock_file
Syntax:    lock_file file;
Default:    
lock_file logs/nginx.lock;
Context:    main

  想要用accept_mutex必须利用到共享锁文件。

(3) 调试基础配置

  • daemon off|on;

    是否以守护进程运行nginx

  • master_process on|off;

     是否以master/worker模型运行nginx,正常情况使用,调试模式下可以关闭

  • error_log /PATH/TO/ERROR_LOG level;

     错误日志文件及其类别;出于调试的需要;可以设定为debug:但是debug仅在编译时候使用了 "--with-debug"选项时才有效

http模块配置

套接字以及主机相关的指令

1. server

server{

  listen PORT;

  server_name NAME;

  root /PATH/TO/DOCUMENTROOT;

}

 ...

注意

  (1) 基于port; listen在不同的端口

  (2) 基于hostname server_name指令指向不同的主机名

2. listen

Syntax:    
listen address[:port] [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]]; listen port [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]]; listen unix:path [default_server] [ssl] [http2 | spdy] [proxy_protocol] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]]; Default: listen *:80 | *:8000; Context: server

    default_server: 说明是默认虚拟主机,即当客户端使用ip访问或者使用任意不能找到对应虚拟主机时使用的默认虚拟主机
    ssl: 限制只能通过ssl连接提供服务

    backlog=#: 后缓队列的长度

    rcvbuf=#: 接收缓冲大小

    sndbuf=#: 发送缓冲区大小

 3. server_name name ....;

  指明当前虚拟主机的主机名,后面可以使用一个或者多个空白字符分隔的多个主机,支持使用*表示任意长度,支持~开始表示的正则表达式

  当一个客户端的请求中的主机名可以和多个虚拟主机名相匹配时,依照如下的次序进行匹配:

  首先,精确匹配 www.baidu.com

  其次, 左侧匹配 *.baidu.com

  右侧匹配:www..baidu.*

  正则表达式: ~^.*.baidu.com$

  再找不到,就是default_server

4. tcp_nodelay on|off;

Syntax:    tcp_nodelay on | off;
Default:    
tcp_nodelay on;
Context:    http, server, location

  原文链接:http://www.cnblogs.com/yezuozuoloveqi/articles/4705607.html

  keepalive模式下的连接是否使用TCP_NODELAY选项

   TCP_NODELAY和TCP_CORK基本上控制了包的“Nagle化”,Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。JohnNagle是Nagle算法的发明人,后者就是用他的名字来命名的,他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题(欲了解详情请参看IETFRFC896)。他解决的问题就是所谓的silly window syndrome,中文称“愚蠢窗口症候群”,具体含义是,因为普遍终端应用程序每产生一次击键操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据载荷以及40个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞,。Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了,但在我们看来,有些场合下把这一选项关掉也是合乎需要的。
现在让我们假设某个应用程序发出了一个请求,希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。如果我们马上发送数据,那么交互性的以及客户/服务器型的应用程序将极大地受益。如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY=on选项来完成,这样就禁用了Nagle算法。
另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据,这种数据传输方式有益于大量数据的通信性能,典型的应用就是文件服务器。应用Nagle算法在这种情况下就会产生问题。但是,如果你正在发送大量数据,你可以设置TCP_CORK选项禁用Nagle化,其方式正好同TCP_NODELAY相反(TCP_CORK和TCP_NODELAY是互相排斥的)。

5. tcp_nopush

 linux 下是tcp_cork,上面的意思就是说,当使用sendfile函数时,tcp_nopush才起作用,它和指令tcp_nodelay是互斥的。tcp_cork是linux下tcp/ip传输的一个标准了,这个标准的大概的意思是,一般情况下,在tcp交互的过程中,当应用程序接收到数据包后马上传送出去,不等待,而tcp_cork选项是数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,这样有助于解决网络堵塞,已经是默认了。
也就是说tcp_nopush = on 会设置调用tcp_cork方法,这个也是默认的,结果就是数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,这样有助于解决网络堵塞。
以快递投递举例说明一下(以下是我的理解,也许是不正确的),当快递东西时,快递员收到一个包裹,马上投递,这样保证了即时性,但是会耗费大量的人力物力,在网络上表现就是会引起网络堵塞,而当快递收到一个包裹,把包裹放到集散地,等一定数量后统一投递,这样就是tcp_cork的选项干的事情,这样的话,会最大化的利用网络资源,虽然有一点点延迟。
对于nginx配置文件中的tcp_nopush,默认就是tcp_nopush,不需要特别指定,这个选项对于www,ftp等大文件很有帮助

6. sendfile on|off

现在流行的web 服务器里面都提供 sendfile 选项用来提高服务器性能,那到底sendfile是什么,怎么影响性能的呢?sendfile实际上是 Linux2.0+以后的推出的一个系统调用,web服务器可以通过调整自身的配置来决定是否利用sendfile这个系统调用。先来看一下不用sendfile的传统网络传输过程:

1 read(file,tmp_buf, len);
2 write(socket,tmp_buf, len);

硬盘 >> kernel buffer >> user buffer>> kernel socket buffer >>协议栈

一般来说一个网络应用是通过读硬盘数据,然后写数据到socket来完成网络传输的。上面2行代码解释了这一点,不过上面2行简单的代码掩盖了底层的很多操作。来看看底层是怎么执行上面2行代码的:

  1. 系统调用read()产生一个上下文切换:从user mode切换到kernel mode,然后DMA执行拷贝,把文件数据从硬盘读到一个kernel buffer里。
  2. 数据从kernel buffer拷贝到 user buffer,然后系统调用 read()返回,这时又产生一个上下文切换:从kernel mode 切换到user mode。
  3. 系统调用write()产生一个上下文切换:从user mode切换到kernel mode,然后把步骤2读到user buffer的数据拷贝到kernel buffer(数据第2次拷贝到 kernel buffer),不过这次是个不同的kernelbuffer,这个buffer和socket相关联。
  4. 系统调用write()返回,产生一个上下文切换:从 kernel mode 切换到 user mode(第4次切换了),然后 DMA 从 kernel buffer拷贝数据到协议栈(第4次拷贝了)。

上面4个步骤有4次上下文切换,有4次拷贝,我们发现如果能减少切换次数和拷贝次数将会有效提升性能。在kernel2.0+版本中,系统调用sendfile()就是用来简化上面步骤提升性能的。sendfile()不但能减少切换次数而且还能减少拷贝次数。


再来看一下用sendfile()来进行网络传输的过程:

sendfile(socket,file, len);
硬盘 >> kernel buffer (快速拷贝到kernelsocket buffer) >>协议栈

  1. 系统调用sendfile()通过DMA把硬盘数据拷贝到kernel buffer,后数据被kernel直接拷贝到另外一个与socket相关的kernel buffer。这里没有user mode和kernel mode之间的切换,在kernel中直接完成了从一个buffer到另一个buffer的拷贝。
  2. DMA把数据从kernelbuffer直接拷贝给协议栈没有切换,也不需要数据从user mode拷贝到kernel mode,因为数据就在kernel里。

步骤减少了,切换减少了,拷贝减少了,自然性能就提升了。这就是为http://write.blog.csdn.net/postedit什么说在Nginx配置文件里打开sendfile on选项能提高web server性能的原因。

路径相关的配置

7.  root

Syntax:    root path;
Default:    
root html;
Context:    http, server, location, if in location

   设置web资源的路径映射地址:用于指明请求的URL对应的文档目录路径,即根路径

   可用的上下文:

    http: 表示所有的虚拟主机

    server: 某一个虚拟主机

    location: 某一个地址

      if:某个条件

8. location 

官方文档:http://nginx.org/en/docs/http/ngx_http_core_module.html#location

Syntax:    location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
Default:    —
Context:    server, location

  根据用户请求的uri来匹配,根据优先级自上而下,用来对不同的资源做不同的配置

  =: URI的精确匹配

  ^~: 左半部分匹配 不区分大小写

  ~: 正则表达式的匹配 区分大小写

  ~*: 正则表达式匹配,不区分大小写

  不带符号

9. alias

Syntax:    alias path;
Default:    —
Context:    location

定义路径别名,新的文档映射

location ~ ^/users/(.+.(?:gif|jpe?g|png))$ {
    alias /data/w3/images/$1;
}

/users/1.png -> /data/w3/images/1.png

10. index

  指明默认主页面

11. error_page

Syntax:    error_page code ... [=[response]] uri;
Default:    —
Context:    http, server, location, if in location

文档: http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page

根据http资源的响应码来实现错误重定向

 主要有2种用法:

 error_page 404 /404.html

 error_page 404 =200 /404.html (以指定响应状态码进行响应)

 /404.html 是一个url而不是文件映射

12. try_files

Syntax:    try_files file ... uri;
try_files file ... =code;
Default:    —
Context:    server, location

尝试查找第1到第N-1个文件,如果找到即当做资源返回,否则,跳转至最后一个uri(注意:必须必须不能匹配至当前的location,而应该配置到其他的location中,否则会死循环)

客户端请求相关的配置:

13. keepalive_timeout

Syntax:    keepalive_timeout timeout [header_timeout];
Default:    
keepalive_timeout 75s;
Context:    http, server, location

客户端每一次和服务端发送请求报文,服务器端返回响应报问,每次连接都需要三次握手,每次断开都需要4次握手,keepalive则可以是虚链路不关闭,timeout则是keepalive的超时时长,即超出多少时间就不使用keep_alive,默认是75s,0表示禁止长连接

14. keepalive_requests

同上,表示keepalive连接之后所允许的最大资源数量,默认是100

15. keepalive_disable none | browser ...;

指明在何种浏览器中禁止keep_alive功能,none 表示哪种都不禁用

16. send_timeout #;

Syntax:    send_timeout time;
Default:    
send_timeout 60s;
Context:    http, server, location

Set a timeout for transmitting a reponse to the client. The timeout is set only between two successive write operations, not for the transmission of the whole repsonse. If the client does not receive anything within this time, the default value is 60s.

客户端的速度非常慢或者响应报文内容非常长时,怎么都发不完,此时必须设置一个超时时长,不能让服务器一直陪着这个单独的客户端传输,因此需要设置超时时长。

17. client_body_buffer_size size;

Syntax:    client_body_buffer_size size;
Default:    
client_body_buffer_size 8k|16k;
Context:    http, server, location

Sets buffer size for reading client request body. In case the request body is larger than the buffer, the whole body or only its part is written to a temporary file. By default, buffer size is equal to two memory pages. This is 8K on x86, other 32-bit platforms, and x86-64. It is usually 16K on other 64-bit platforms.

接收客户端请求报文的body部分的缓冲区大小,64位平台一般是16K,超出缓冲区大小,暂存至磁盘上.

18. client_body_temp_path path [level1 [level2] [level3]]

Syntax:    client_body_temp_path path [level1 [level2 [level3]]];
Default:    
client_body_temp_path client_body_temp;
Context:    http, server, location

可以分级存储,高并发的情况下,如果大量的请求缓冲区都放置不下,临时文件非常多,因此我们必须按照一定的规律进行存储,提高查找速度,这里指创建多少个1级目录,2级目录,3级目录

/var/tmp/body 2 1 2 

说明: 2表示第一级有(2个16进制数字个数) 2^8 个第一级目录,依次类推...

对客户端的请求进行限制

19. limit_rate

Syntax:    limit_rate rate;
Default:    
limit_rate 0;
Context:    http, server, location, if in location

Limits the rate of response transmission to a client. The rate is specified in bytes per second.

20. limit_except

Syntax:    limit_except method ... { ... }
Default:    —
Context:    location

Limits allowed HTTP methods inside a location

limit_except GET POST{

  allow 192.168.1.0/24;

  deny all;

}

表示除了GET HEAD POST之外的方法仅仅允许192.168.1.0/24网络中的主机使用

文件操作优化相关

21. aio

Syntax:    aio on | off | threads[=pool];
Default:    
aio off;
Context:    http, server, location
This directive appeared in version 0.8.11.

是否启用aio

22. directio

Syntax:    directio size | off;
Default:    
directio off;
Context:    http, server, location
This directive appeared in version 0.7.7.

是否启用直接io,即不使用缓冲,都性能有影响,但是数据更可靠,因为缓冲中的数据还是有可能丢失的

23. open_file_cache

Syntax:    open_file_cache off;
open_file_cache max=N [inactive=time];
Default:    
open_file_cache off;
Context:    http, server, location

  常用的优化选项当打开较多文件的时候是否缓存, 但是nginx不会缓存文件的内容,可以缓存以下三种信息:

    (1) 文件的描述符、文件大小和最近一次的修改时间;

    (2) 打开的目录的结构

    (3) 不存在的文件信息,以及其他否定回答例如没有权限

  max=N表示缓存的最大条目的上年;一旦达到上限,使用LRU算法

  inactive=time: 非活跃时间

24. open_file_cache_errors on | off;

  是否缓存找不到其路径的文件或者没有权限访问的文件相关信息

25. open_file_cache_valid time;

Syntax:    open_file_cache_valid time;
Default:    
open_file_cache_valid 60s;
Context:    http, server, location

Sets a time after which open_file_cache elements should be validated.

缓存过期算法:在open_file_cache_valid的规定时间内该资源文件必须被访问open_file_cache_min_uses次

26. open_file_cache_min_uses

Syntax:    output_buffers number size;
Default:    
output_buffers 2 32k;
Context:    http, server, location

nginx_http_access_module相关配置:即http 访问控制,基于ip

27. allow

Syntax:    allow address | CIDR | unix: | all;
Default:    —
Context:    http, server, location, limit_except

28. deny

Syntax:    deny address | CIDR | unix: | all;
Default:    —
Context:    http, server, location, limit_except

https配置模块

关于ssl安全套接字层的具体情况,请参照另一篇文档:http://www.cnblogs.com/carl10086/p/5905918.html

nginx官方https文档:http://nginx.org/en/docs/http/ngx_http_ssl_module.html

如果你是编译安装且一开始指定了ssl模块的话,配置文件中会有默认的443端口的虚拟主机配置,注意到,这里跟httpd一样,目前还不支持1个ip多个https虚拟主机的配置,一般情况是这样的,查看默认配置文件如下

 # HTTPS server
  
   server {
        #监听443端口,并且强制为ssl
        listen       443 ssl;
        #验证证书时可能要用
        server_name  www.ysz206.com;
        #证书文件地址
       ssl_certificate      cert.pem;
       #私钥地址
       ssl_certificate_key  cert.key;
      #ssl会话缓存
       ssl_session_cache    shared:SSL:1m;
       ssl_session_timeout  5m;
     # ssl中用到的加密算法
      ssl_ciphers  HIGH:!aNULL:!MD5;
      # 开启偏向服务器的解密算法
      ssl_prefer_server_ciphers  on;

    location / {
        root   html;
       index  index.html index.htm;
      }
   }

说明:

Syntax:    ssl_session_cache off | none | [builtin[:size]] [shared:name:size];
Default:    
ssl_session_cache none;
Context:    http, server

ssl中会给服务器带来更大的压力,因此可以考虑使用缓存会话来优化性能,当然这也有一定的安全风险 

ssl_session cache可以设置如下策略

off: 不使用缓存

none: 官方说法 the use of a session cache is gently disallowed: nginx tells a client that sessions may be reuses, but does not actually store sessions parameters in the cache.

builtin: 使用OpenSSL自带的缓存,不同worker间不能共享,缓存默认大小是20480个session会话。而且会造成内存碎片

shared: 由nginx实现的缓存策略,可以被多个worker共享,相对于builtin有更高的命中率

如何在ysz206上使用ssl,非常简单,跟httpd一样,在nginx下面建立一个ssl文件夹,生成私钥,生成证书,在ysz202上给证书进行签名,签名成功之后可以使用如下配置,参考如下配置:

server {
        listen       443 ssl;
        server_name  www.ysz206.com;

        ssl_certificate      /etc/nginx/ssl/nginx.crt;
        ssl_certificate_key  /etc/nginx/ssl/nginx.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;
        }
    }

日志模块

官方文档:http://nginx.org/en/docs/http/ngx_http_log_module.html

1. access_log 和 log_format

Syntax:    access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
Default:    
access_log logs/access.log combined;
Context:    http, server, location, if in location, limit_except

access_log定义日志,引用logformat中定义的格式,例如:

log_format compression '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $bytes_sent '
                       '"$http_referer" "$http_user_agent" "$gzip_ratio"';

access_log /spool/logs/nginx-access.log compression buffer=32k;

2. open_log_file_cache

linux中任何一个打开的文件都可以通过fid(文件描述符file descriptor)来追踪

Defines a cache that stores the file descriptors of frequently used logs whose names contain variables.

在有大量日志文件的时候,open_log_file_cache对性能的提升还是不可忽视的

max: set the maximum number of the descriptors in a ache,即最大缓存条目,默认是10个

inactive: sets the tiime after which the cached descriptor is closed,缓存失效时长

min_uses:最少使用次数

valid: 验证缓存条目有效性的频率

跟之前的session缓存一样,缓存有效性在于必须在inactive时间中最少使用min_uses次

 Example:

open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;

rewrite模块

Syntax:    rewrite regex replacement [flag];
Default:    —
Context:    server, location, if

rewrite模块用来重写request URI的,在rewrite模块中可以使用pcre的正则表达式,但是正则表达式引擎都是比较消耗系统资源的。

大致流程:

  把用户请求的URI基于regex做检查,匹配到时替换为replacement指定的字符串;如果是replacement是以http://或者https://开头的绝对地址,则替换结果会以重定向的方式直接返回给客户端,否则会在同一个location中的多个rewrite规则中自上而下逐条检测,可以使用flag来控制循环功能,常用的flag如下:

  last: 重写完成之后停止对当前uri在当前location中的后续其他重写操作,改为对新url的新一轮处理;

  break: 重写完成之后停止对当前uri在当前locatioin中后续其他重写操作;

  redirect: 重写完成之后会返回一个客户端的临时重定向,由客户端重新发起请求(302)

  permanent: 重写完成之后会返回给客户端一个永久的重定向,由客户端重新对新的url发送请求(301)

1. rewirte指定: 重写指令

server {
      ...
      rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 break;
      rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra  break;
      return  403;
      ...
 }

使用 last有可能出现死循环,比如有一个rewrite (.*).txt$ $1.html last,而另一个location中刚好有rewrite (.*).html $1.txt last,则会出现死循环,用break的效果可能不一样,请自行测试。

 2. rewrite_log on | off;

  是否启用重写日志;启用时,日志信息会发往错误日志;

3. if指令

Syntax:    if (condition) { ... }
Default:    —
Context:    server, location

跟if语句差不多

比较表达式:
  ==,!=
  ~:模式匹配,区分字符大小写;
  ~*:模式匹配,不区分字符大小写;
  !~:模式不匹配,区分字符大小写;
  !~*: 模式不匹配,不区分字符大小写;
文件及目录判断:
  -f, !-f:是否存在且为普通文件;
  -d, !-d: 是否存在且为目录;
  -e, !-e:是否存在;
  -x, !-x:是否存在且可执行;

demo:

if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
}

if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
}

if ($request_method = POST) {
    return 405;
}

if ($slow) {
    limit_rate 10k;
}

if ($invalid_referer) {
    return 403;
}

  

 4. return指令

Syntax:    return code [text];
return code URL;
return URL;
Default:    —
Context:    server, location, if

Stops processing and returns the specified code to a client. The non-standard code 444 closes a connetcion without sending a response header.

可以返回code url,不过是重定向应该指定302,301等。

5. set指令

Syntax:    set $variable value;
Default:    —
Context:    server, location, if

用户自定义变量

gzip模块

用cpu的时间换取带宽

配置demo如下:

gzip            on;
gzip_min_length 1000;
gzip_proxied    expired no-cache no-store private auth;
gzip_types      text/plain application/xml text/css application/json application/javascript
gzip_disable   msie6;
gzip_comp_level 6;

1. gzip_comp_level指令

Syntax:    gzip_comp_level level;
Default:    
gzip_comp_level 1;
Context:    http, server, location

指定压缩比例,1-9

2.gzip_disable指令

Syntax:    gzip_disable regex ...;
Default:    —
Context:    http, server, location
This directive appeared in version 0.6.23.

有些浏览器不支持,regex是匹配客户端浏览器类型的模式,匹配到的不进行压缩

3. gzip_min_length

Syntax:    gzip_min_length length;
Default:    
gzip_min_length 20;
Context:    http, server, location

最小压缩长度

4. gzip_http_version

Syntax:    gzip_http_version 1.0 | 1.1;
Default:    
gzip_http_version 1.1;
Context:    http, server, location

指定支持压缩的最小http协议版本

5. gzip_types

Syntax:    gzip_types mime-type ...;
Default:    
gzip_types text/html;
Context:    http, server, location

指定压缩额资源内容类型

6. gzip_proxied

Syntax:    gzip_proxied off | expired | no-cache | no-store | private | no_last_modified | no_etag | auth | any ...;
Default:    
gzip_proxied off;
Context:    http, server, location

Enables or disables gzipping of response for proxied requests depending on the request and response. 对代理的请求基于何种属性判断其是否应该启用压缩功能;

off: 所有被代理的请求通通禁止压缩

expired: 如果一个响应报文首部包含expired字段,且有一个过期值,那就使用压缩

....具体请参考文档,大同小异

原文地址:https://www.cnblogs.com/carl10086/p/5926281.html