Nginx学习整理


参考:

学习目录

  • 基础篇
    1. nginx介绍
    2. nginx编译安装
    3. nginx整合php
    4. nginx信号控制
  • 应用篇
    1. nginx虚拟主机配置
    2. nginx日志切割
    3. nginx与gzip设置
  • 实战篇
    1. nginx与浏览器缓存配置
    2. nginx与rewrite规则
    3. nginx与memcached
  • 优化篇
    1. nginx连续数优化
    2. nginx反向代理
    3. nginx集群与负载平衡

nginx介绍

Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的

nginx编译安装

方法一:源码编译安装

# 安装依赖
yum -y install pcre pcre-devel gcc gcc-c++ autoconf automake make zip*
# 下载源码并解压
cd /usr/local/src
wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar zxvf nginx-1.18.0.tar.gz
cd nginx-1.18.0
# 编译安装
./configure --prefix=/usr/local/nginx
make && make install
# 启动
cd /usr/local/nginx
 ./sbin/nginx

操作命令介绍

  1. -?,-h:显示该帮助信息
  2. -v:打印版本号并退出
  3. -V:打印版本号与编译信息并退出
  4. -t:测试配置并退出
  5. -T:测试配置、转储并退出
  6. -q:测试配置时只显示错误
  7. -s signal:发送信号给主进程,包括stop、 quit、 reopen、 reload
  8. -p prefix:指定nginx服务器路径前缀 (默认:/usr/local/nginx/)
  9. -c filename:指定nginx配置文件路径 (默认:conf/nginx.conf)
  10. -g directives:指定nginx附加配置文件路径

方法二:yum源安装(推荐使用)

# 配置yum源
vim /etc/yum.repos.d/nginx.repo
    [nginx-stable]
    name=nginx stable repo
    baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
    gpgcheck=1
    enabled=1
    gpgkey=https://nginx.org/keys/nginx_signing.key
    [nginx-mainline]
    name=nginx mainline repo
    baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
    gpgcheck=1
    enabled=0
    gpgkey=https://nginx.org/keys/nginx_signing.key
yum makecache
# 安装
yum -y install nginx
# 版本查看
nginx -v  # nginx version: nginx/1.18.0
# 开机自启与启动
systemctl enable nginx && systemctl start nginx && systemctl status nginx

可能存在问题

不能绑定80端口,80端口已经被占用(有时是自己装了apache,nginx等,还有更多情况是操作系统自带了apache并作为服务启动)
解决:使用netstat -tulnp查看, 把占用80端口的软件或服务关闭即可

nginx整合php

apache一般是把php当做自己的一个模块来启动的,而nginx则是把http请求变量(如get,user_agent等)转发给php进程,即php独立进程,与nginx进行通信,称为 fastcgi运行方式,因此,为apache所编译的php是不能用于nginx的。
注意: 我们编译的PHP 要有如下功能:连接mysql, gd, ttf, 以fpm(fascgi)方式运行
./configure --prefix=/usr/local/fastphp --with-mysql=mysqlnd --enable-mysqlnd --with-gd --enable-gd-native-ttf --enable-gd-jis-conv --enable-fpm
设计到具体选项,可以使用./configure -help | grep mysql查看

nginx与php合作的方式说明

nginx+php的配置比较简单,核心就一句话:把请求的信息转发给9000端口的PHP进程,让PHP进程处理 指定目录下的PHP文件。处理流程如下:

  1. 碰到php文件
  2. 把根目录定位到 html
  3. 把请求上下文转交给9000端口PHP进程
  4. 并告诉PHP进程,当前的脚本是$document_root$fastcgi_scriptname【注:PHP会去找这个脚本并处理,所以脚本的位置要指对】

编译安装php

yum install -y libxml* libpng* mariadb* gd gd-devel freetype
cd /usr/local/src
wget https://www.php.net/distributions/php-7.4.9.tar.gz
tar zxf php-7.4.9.tar.gz
cd php-7.4.9
./configure --prefix=/usr/local/php \
--enable-mysqlnd \
--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd \
--without-sqlite3 \
--enable-gd --enable-gd-jis-conv --enable-fpm
make && make install

修改nginx配置文件,整合php

cp /usr/local/src/php-7.4.9/php.ini-development /usr/local/php/lib/php.ini
cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf
cp /usr/local/php/etc/php-fpm.d/www.conf.default /usr/local/php/etc/php-fpm.d/www.conf
/usr/local/php/sbin/php-fpm     # 启动php-fpm
systemctl start mariadb  # 启动mysql数据库
vim /usr/local/nginx/conf/nginx.conf
    # 在server下面,取消注释后修改
    location ~ \.php$ {
        root           html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        # 修改下面这一行
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
        }
./sbin/nginx -s reload

nginx信号控制

如果不习惯或者不喜欢使用kill命令的这种方式,可以使用nginx自带的命令进行管理。

信号控制选项

  • TERM, INT:立刻关闭(不推荐使用)
  • QUIT:优雅的关闭进程,即等请求结束后再关闭
  • HUP:改变配置文件,平滑的重读配置文件
  • USR1:重读日志,在日志按月/日分割时有用
  • USR2:平滑的升级
  • WINCH:优雅关闭旧的进程(配合USR2来进行升级)

使用方法

主进程号查询命令: ps aux | grep nginx | grep master
进程号获取也可以读取nginx在配置文件中指定的pid文件,默认是cat /usr/local/nginx/logs/nginx.pid
使用方式:kill -信号选项 nginx的主进程号,例如

  1. 重读配置文件
kill -HUP 5415
或者
kill -HUP `cat /usr/local/nginx/logs/nginx.pid`
  1. 写入新的日志文件
kill -USR1 5415
或者
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`

nginx虚拟主机配置

nginx配置文件结构

  1. 全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
  2. events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
  3. http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。
  4. server块:配置虚拟主机的相关参数,一个http中可以有多个server。
  5. location块:配置请求的路由,以及各种页面的处理情况。
    server继承 main,location 继承 server, upstream 既不会继承其他的配置,也不会被继承
...              #全局块

events {         #events块
   ...
}

http      #http块
{
    ...   #http全局块
    server        #server块
    { 
        ...       #server全局块
        location [PATTERN]   #location块
        {
            ...
        }
        location [PATTERN] 
        {
            ...
        }
    }
    server
    {
      ...
    }
    ...     #http全局块
}

配置文件详解

nginx配置文件博大精深,这里只是简单介绍部分常用参数,如果想了解更多参数以及使用方法,请参考网站http://nginx.org/en/docs/或者https://www.nginx.cn/doc/index.html

#【注意】:每个指令必须有分号结束

# --------------------------- 全局块 --------------------------
# 配置用户或者组,默认为nobody nobody
user root root;  
# 允许生成的进程数,默认为1。可以自行修改,但太大无益,因为要争夺CPU,一般设置为CPU逻辑核心数
worker_processes 1;  
# 指定nginx进程运行文件存放地址
pid /nginx/pid/nginx.pid;   
#制定日志路径,级别(级别参数可省略,默认为crit)。这个设置可以放入全局块、http块、server块,级别以此为:debug|info|notice|warn|error|crit|alert|emerg
error_log log/error.log debug;  

# --------------------------- events块 --------------------------
events {
    # 设置网路连接序列化,防止惊群现象发生,默认为on
    #   惊群现象:一个网路连接到来,多个睡眠的进程被同时叫醒,但只有一个进程能获得链接,这样会影响系统性能
    accept_mutex on;   
    # 设置一个进程是否同时接受多个网络连接,默认为off
    multi_accept on;  
    # 事件驱动模型,默认为epoll,select|poll|kqueue|epoll|resig|/dev/poll|eventport
    use epoll;      
    # 最大连接数,默认为512
    worker_connections  1024;    
}

# --------------------------- http块 --------------------------
http {

    # --------------------------- http块:http全局块 --------------------------
    # 文件扩展名与文件类型映射表
    include       mime.types;   
    # 默认文件类型,默认为text/plain
    default_type  application/octet-stream; 
    # 取消服务日志
    access_log off;     
    # 自定义日志格式,其中:
    #   1. $remote_addr 与 $http_x_forwarded_for:用以记录客户端的ip地址;
    #   2.$remote_user:用来记录客户端用户名称;
    #   3.$time_local:用来记录访问时间与时区;
    #   4.$request:用来记录请求的url与http协议;
    #   5.$status:用来记录请求状态;成功是200;
    #   6.$body_bytes_s ent:记录发送给客户端文件主体内容大小;
    #   7.$http_referer:用来记录从那个页面链接访问过来的;
    #   8.$http_user_agent :记录客户端浏览器的相关信息;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                                 '$status $body_bytes_sent "$http_referer" '
                                 '"$http_user_agent" "$http_x_forwarded_for"';
    # combined为日志格式的默认值,可以在全局块、http块、server块设置
    access_log log/access.log main; 
    # 允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。 
    sendfile on;   
    # 每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
    sendfile_max_chunk 100k;  
    #连接超时时间,默认为75s,可以在http,server,location块。
    keepalive_timeout 65;  
    # 配置热备或者负载均衡等
    upstream mysvr {   
      server 127.0.0.1:7878;
      server 192.168.10.121:3333 backup;  #热备
    }
    # 错误页
    error_page 404 https://www.baidu.com; 
    # 关于缓存tcp_nopush、压缩gzip等参数,可详细参考官网说明

    # --------------------------- http块:server块 --------------------------
    server {
        # --------------------------- http块:server全局块 --------------------
        # 单连接请求上限次数
        keepalive_requests 120; 
        # 监听端口
        listen       4545;   
        # 监听地址   
        server_name  127.0.0.1;      
        # 设置编码格式为utf-8
        charset utf-8;

        # --------------------------- http块:location块 ----------------- 
        #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
        location  ~*^.+$ { 
            # 根目录      
           root path;  
           # 设置默认页
           index vv.txt;  
           # 请求转向mysvr 定义的服务器列表
           proxy_pass  http://mysvr;  
           # 拒绝的ip
           deny 127.0.0.1;  
           # 允许的ip 
           allow 172.18.5.54;           
        } 
    }
}

代理服务配置详解

参数详解
  1. 基本指令
    1. proxy_pass:设置代理服务器的协议和地址。语法:proxy_pass URL
    2. proxy_hide_header:用于设置Nginx服务器发送http响应时,隐藏一些头域信息。语法:proxy_hide_header field,field为需要隐藏的头域,可用于http、server、localtion
    3. proxy_pass_header:默认Nginx服务器在发送响应报文时,报文不包含date server X-accel等来自被代理服务器的头域信息,该指令可以设置这些头域信息已被发送。语法:proxy_pass_header filed
    4. proxy_pass_request_body:配置是否将客户端请求体发送给代理服务器。语法:proxy_pass_request_body on | off,可用于http、server、localtion
    5. proxy_pass_request_header:配置是否将客户端的请求头发送给代理服务器
    6. proxy_set_header:用于更改Nginx服务器接收到的客户端请求的请求头,然后将新的请求头发送给被代理服务器。语法:proxy_set_header filed value,field为要更改的信息所在的头域,value为要更改后的值
    7. proxy_set_body:更改Nginx服务器接收到的客户端请求的请求体信息,然后将新的请求体发送给被代理的服务器。语法:proxy_set_body value,value为更改的信息
    8. proxy_bind:强制将与代理主机的连接绑定到指定的ip主机。语法:proxy_bind address ,address为IP地址
    9. proxy_connect_timout:用于配置Nginx服务器与后端被代理服务器尝试连接的超时时间。语法:proxy_connect_timout time,默认时间60秒
    10. proxy_read_timeout:用于配置Nginx服务器向后端被代理服务器(组)发出read请求后,等待响应的超时时间。语法:proxy_read_timeout time,默认时间60秒
    11. proxy_send_timeout:用于配置Nginx服务器向后端被代理服务器(组)发出write请求后,等待响应的超时时间。语法:proxy_send_timeout time,默认时间60秒
    12. proxy_http_version:用于设置Nginx服务器提供代理服务器的HTTP协议版本。语法:proxy_http_version 1.0|1.1|2.0,默认是1.0
    13. proxy_method:用于设置Nginx服务器请求代理服务器使用的请求方法,设置了这个客户端的请求方法将会被忽略。语法:proxy_method POST|GET
    14. proxy_ignore_client_abort:用于设置在客户端中断网络请求的时候,Nginx服务器是否中断对被代理服务器的请求。语法:proxy_ignore_client_abort on | off
    15. proxy_ignore_headers:用于设置一些HTTP响应头的头域。语法:proxy_ignore_headers filed ...,filed为要设置的HTTP相应头的头域信息,例如"X-Accel-Redirect"、"X-Accel-Expires"、"Expores"、"Cache-Control"、"Set-Cookie"
    16. proxy_headers_hash_max_size:存放HTTP报文头的哈希表的容量。语法:proxy_headers_hash_max_size size,默认大小512
    17. proxy_headers_hash_bucket_size:Nginx服务器申请存放HTTP报文头的哈希表容量的单位大小。语法:proxy_headers_hash_max_size 64
    18. proxy_next_upstream:如果Nginx定义了upstream后端服务器组,如果组内有异常情况,将请求顺次交给下一个组内服务器处理。语法:proxy_next_upstream error|timeout|invalid_header|http_500 502 503 504 404|off
    19. proxy_ssl_session_reuse:该指令用于配置是否使用基于SSL安全协议的会话连接(htts://)被代理服务器。语法:proxy_ssl_session_reuse on | off,默认on
  2. ProxyBuffer指令
    1. proxy_buffering:用于配置是否启用或者关闭proxybuff。语法:proxy_buffering on | off
    2. proxy_buffers:用于配置接收一次被代理服务器响应数据的Proxy Buffer个数和每个Buffer的大小。语法:proxy_buffers number size,size一般设置为内存页大小,根据平台的不同,取值可能为4KB或者8KB,例如:proxy_buffers 8 4KB|8KB
    3. proxy_buffer_size:用于配置从被代理服务器获取的第一部分响应数据的大小,默认为4k或者8k,保持与proxy_buffers指令中的size变量相同。
    4. proxy_busy_buffers_size:用于限制同时处于BUSY状态的Proxy Buffer的总大小。语法:proxy_busy_buffers_size size,size为设置处于BUSY状态的缓存区总大小。默认为8KB或者16KB。
    5. proxy_temp_path:用于配置磁盘上的一个文件路径,用于临时存放被代理服务器的大体积响应数据。如果Proxy Buffer被装满后,响应数据仍然没有被Nginx服务器完全接收,之后响应的数据就会被临时存放在该文件中。语法:proxy_temp_path path [level1 [level2 [level3]]],path为磁盘上临时存放文件的路径,levelN缓存文件存放在设置的路径的第几级hash目录中
    6. proxy_max_temp_file_size:用于设置所有临时文件的总大小。语法:proxy_max_temp_file_size size,默认是1024M
    7. proxy_temp_file_write_size:用于配置同时写入临时文件的数据量的总大小,语法:proxy_temp_file_write_size size,默认设置根据平台的不同,可以为8KB或者16KB,一般与平台的内存也大小相同
  3. Proxy Cache指令
    1. proxy_cache:用于配置一块公用的内存区域的名称,该区域可以存放缓存的索引数据。这些数据在Nginx服务器启动时由缓存索引重建进程负责建立,在Nginx服务器的整个运行过程中由缓存管理进程负责定时检查过期数据、检索等管理工作。语法:proxy_cache zone | off,zone为设置用于存放缓存索引的内存区域的名称,off为关闭proxy_cache功能(默认设置为on)
    2. proxy_cache_bypass:用于配置Nginx在响应客户端时不从缓存中获取数据的条件。语法:proxy_cache_bypass string ...,string为条件变量,支持配置多个,当至少有一个字符串指令不为空或者不等于0时,响应数据不从缓存中获取。举例proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment $http_pragma $http_authorization
    3. proxy_cache_key:用于配置Nginx服务器在内存中为缓存数据建立索引时使用的关键字
    4. proxy_cache_lock_timeout:用于配置开启锁功能以后锁的超时时间,默认为5s。
    5. proxy_cache_in_uses:当客户端向被代理的服务器发送相同的请求达到该指令设定的次数后,Nginx服务器才对该其更年期的响应数据做缓存,默认为1。
    6. proxy_cache_path:用于设置Nginx服务器存储缓存数据的路径以及和缓存索引相关的内容,语法:proxy_cache_path path [levels=levels] keys_zone=name:size1 [inactive=time1] [max_size=size2] [loader_files=number] [loader_sleep=time2] [loader_threshold=time3]
      1. path:设置缓存存放的根路径
      2. levels:设置相对于path指定目录的第几级hash目录中缓存数据。levels=1表示一级hash目录,levels=1:2,表示两级目录,以此类推。该目录是基于请求URL通过哈希算法得到的
      3. name:size1:Nginx服务器的缓存索引重建进程在内存中为缓存数据建立索引,这一对变量用来设置存放缓存索引的内存区域的名称和大小t
      4. time1:设置强制更新缓存数据的时间,当缓存数据在设定的时间内没有被访问时,Nginx服务器就强制从硬盘上将其删除,下次客户端访问该数据时重新缓存,默认为10
      5. size2:设置缓存数据大小,当缓存的大小超过该变量的设置时,索引管理进程将根据最近最少被访问的策略删除缓存
      6. number:设置缓存索引重建进程每次加载的数据元素的数量上限,默认为100
      7. time2:设置缓存索引重建进程在一次遍历结束后下一次遍历开始之间暂停的时长,默认为50ms
      8. time3:设置遍历一次磁盘缓存源数据的时间上限,默认为200ms
        指令比较复杂,一般需要设置前面3个指令的情形比较多,后面几个变量与Nginx服务器缓存索引重建进程以及管理进程性能有关,一般情况下保持默认设置就可以了。例如:proxy_cache_path /data/nginx/cache/a levels=1 keys_zone=a:10m;或者proxy_cache_path /data/nginx/cache/b levels=2:2 keys_zone=b:100m;或者proxy_cache_path /data/nginx/cache/c levels=1:1:2 keys_zone=c:1000m;。【注:】该指令只能放在http块中
    7. proxy_cache_use_stale:指定在哪种情况下,当被代理的服务器无法访问或者访问错误等现象时,Nginx服务器可以使用历史缓存响应客户端的请求。语法:proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | off ...,默认为off
    8. proxy_cache_valid:该指令可以针对不能的HTTP响应状态设置不同的缓存时间。语法:proxy_cache_valid [code ...] time,code为设置HTTP响应的状态码,默认只为响应码是200、301、302的响应数据做缓存,可以使用any,表示缓存所有该指令中未设定的其他响应数据;time为缓存时间。举例:proxy_cache_valid 200 302 10m;proxy_cache_valid 301 1h;proxy_cache_valid any 10m; ,第三个例子表示对返回状态为不是200、301、302的响应数据缓存10分钟
    9. proxy_no_cache:配置在什么情况下不使用cache功能。语法:proxy_no_cache string ...,string可以是一个或者多个变量,当string的值不为空或者不为0时,不启用cache功能。
    10. proxy_store:配置是否在本地磁盘缓存来自被代理服务器的响应数据。语法:proxy_store on | off | stringon | off设置是否开启Proxy Store功能,如果开启,缓存文件会存放到alias指令或root指令设置的本地路径,默认为off;string为自定义缓存文件存放路径,使用该配置时,默认开启Proxy Store
    11. proxy_store_access:用于设置用户或用户组对Proxy Store缓存文件的访问权限。语法:proxy_store_access users:permissions ...,users可以设置为user、group或者all;permission设置方位权限。举例:proxy_store on;proxy_store_access user:rw group:rw all:r;root /data/www;
常用配置举例
  1. 当代理遇到状态码为404时,我们把404页面导向百度
#错误页
error_page 404 https://www.baidu.com; 
#如果被代理服务器返回的状态码为400或者大于400,设置的error_page配置起作用。默认为off。
proxy_intercept_errors on;    
  1. 如果我们的代理只允许接受get,post请求方法的一种
#支持客户端的请求方法:post/get
proxy_method get;    
  1. 设置支持的http协议版本
#Nginx服务器提供代理服务的http协议版本1.0,1.1,默认设置为1.0版本
proxy_http_version 1.0 ; 
  1. 如果nginx服务器给2台web服务器做代理,负载均衡算法采用轮询,那么当一台机器web程序iis关闭,也就是说web不能访问,那么nginx服务器分发请求还是会给这台不能访问的web服务器,如果这里的响应连接时间过长,就会导致客户端的页面一直在等待响应,对用户来说体验就大打折扣,为了避免这样的情况发生。这里我配张图来说明下问题。
    代理
    如果负载均衡中其中web2发生这样的情况,nginx首先会去web1请求,但是nginx在配置不当的情况下会继续分发请求道web2,然后等待web2响应,直到响应时间超时,才会把请求重新分发给web1,这里的响应时间如果过长,用户等待的时间就会越长。
    下面的配置是解决方案之一:
# nginx服务器与被代理的服务器建立连接的超时时间,默认60秒
proxy_connect_timeout 1;   
# nginx服务器想被代理服务器组发出read请求后,等待响应的超时间,默认为60秒
proxy_read_timeout 1; 
# nginx服务器想被代理服务器组发出write请求后,等待响应的超时间,默认为60秒
proxy_send_timeout 1; 
#客户端断网时,nginx服务器是否终端对被代理服务器的请求。默认为off
proxy_ignore_client_abort on;  
  1. 如果使用upstream指令配置一组服务器作为被代理服务器,服务器中的访问算法遵循配置的负载均衡规则,同时可以使用该指令配置在发生哪些异常情况时,将请求顺次交由下一组服务器处理。
#反向代理upstream中设置的服务器组,出现故障时,被代理服务器返回的状态值。error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off
proxy_next_upstream timeout;  
  • error:建立连接或向被代理的服务器发送请求或读取响应信息时服务器发生错误
  • timeout:建立连接,想被代理服务器发送请求或读取响应信息时服务器发生超时
  • invalid_header:被代理服务器返回的响应头异常
  • off:无法将请求分发给被代理的服务器
  • http_400,....:被代理服务器返回的状态码为400、500、502等
  1. 如果想通过http获取客户的真是ip而不是获取代理服务器的ip地址,那么要做如下的设置
#只要用户在浏览器中访问的域名绑定了 VIP,VIP下面有RS,就用$host ,host是访问URL中的域名和端口,例如www.taobao.com:80
proxy_set_header Host $host; 
#把源IP 【$remote_addr,建立HTTP连接header里面的信息】赋值给X-Real-IP,这样在代码中 $X-Real-IP来获取源IP
proxy_set_header X-Real-IP $remote_addr; 
#在nginx 作为代理服务器时,设置的IP列表,会把经过的机器ip,代理机器ip都记录下来,用 【,】隔开,代码中用 echo $x-forwarded-for |awk -F, '{print $1}' 来作为源IP 
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

负载均衡配置详解

配置模板如下:

upstream mysvr { 
      server 192.168.10.121:3333;
      server 192.168.10.122:3333;
    }
 server {
        ....
        location  ~*^.+$ {         
           proxy_pass  http://mysvr;  #请求转向mysvr 定义的服务器列表         
        }

关于nginx负载均衡配置的几个状态参数讲解:

  • down,表示当前的server暂时不参与负载均衡
  • backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻
  • max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream模块定义的错误
  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用
upstream mysvr { 
      server 127.0.0.1:7878 weight=2 max_fails=2 fail_timeout=2;
      server 192.168.10.121:3333 weight=1 max_fails=2 fail_timeout=1;    
    }
热备

如果有2台服务器,当一台服务器发生事故时,才启用第二台服务器给提供服务。服务器处理请求的顺序:AAAAAA突然A挂啦,BBBBBBBBBBBBBB.....

upstream mysvr { 
      server 127.0.0.1:7878; 
      server 192.168.10.121:3333 backup;  #热备     
    }
轮询

nginx默认就是轮询其权重都默认为1,服务器处理请求的顺序:ABABABABAB....

upstream mysvr { 
      server 127.0.0.1:7878;
      server 192.168.10.121:3333;       
    }
加权轮询

根据配置的权重的大小而分发给不同服务器不同数量的请求。如果不设置,则默认为1。下面服务器的请求顺序为:ABBABBABBABBABB....

upstream mysvr { 
      server 127.0.0.1:7878 weight=1;
      server 192.168.10.121:3333 weight=2;
      }
ip_hash

nginx会让相同的客户端ip请求相同的服务器。

upstream mysvr { 
      server 127.0.0.1:7878; 
      server 192.168.10.121:3333;
      ip_hash;
    }

配置文件举例

例子1: 基于域名的虚拟主机
server {
    listen 80;  #监听端口
    server_name a.com; #监听域名

    location / {
            root a.com;   #根目录,此处使用相对路径,相对于/usr/local/nginx,也可以使用绝对路径
            index index.html;
    }
}
例子2: 基于端口的虚拟主机配置
server {
    listen 8080;
    server_name 192.168.1.204;

    location / {
            root /var/www/html8080;  # 根目录,此处使用绝对路径,当然可以使用相对路径
            index index.html;
    }
}

nginx日志切割

主要配置参数

  1. access_log
    combined为日志格式的默认值,可以在全局块、http块、server块设置,格式为:access_log logs/host.access.log main;,说明它的访问日志的文件是logs/host.access.log ,使用的格式为"main"格式。除了main格式,你可以自定义其他格式.
  2. log_format
    定义日志格式,便于下面引用,主要参数如下:
    1. $remote_addr 与 $http_x_forwarded_for:用以记录客户端的ip地址;
    2. $remote_user:用来记录客户端用户名称;
    3. $time_local:用来记录访问时间与时区;
    4. $request:用来记录请求的url与http协议;
    5. $status:用来记录请求状态;成功是200;
    6. $body_bytes_s ent:记录发送给客户端文件主体内容大小;
    7. $http_referer:用来记录从那个页面链接访问过来的;
    8. $http_user_agent :记录客户端浏览器的相关信息;
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                            '$status $body_bytes_sent "$http_referer" '
                            '"$http_user_agent" "$http_x_forwarded_for"';
# 引用
server {
    listen 80;
    server_name a.com; 
    access_log logs/z.com.access.log main;
    location / {
            root a.com; 
            index index.html;
    }
}

main格式是我们定义好一种日志的格式,并起个名字main,便于引用。
以上面的例子,main类型的日志,记录的remote_addr.... http_x_forwarded_for等选项。

日志切割(由定时任务完成)

  1. 编辑脚本/root/backup.sh
#!/bin/bash
# 原始日志文件
LOGPATH=/usr/local/nginx/logs/z.com.access.log
# 备份日志目录
BASEPATH=/data/$(date -d yesterday +%Y%m)
mkdir -p $BASEPATH
# 获取昨天的日期并生成备份文件名
bak=$BASEPATH/$(date -d yesterday +%d-%H:%M).zcom.access.log
# 备份
mv $LOGPATH $bak
touch $LOGPATH
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
  1. 设置定时任务
crontab -e
    01 00 * * * /root/backup.sh  # 每天0时1分(建议在02-04点之间,系统负载小)

nginx与gzip设置(压缩管理)

介绍

gzip是一种压缩技术,经过gzip压缩后的页面大小可以变成原来的30%或者更小。用户浏览页面的时候速度也会更快,gzip的压缩页面需要服务端于浏览器同时支持,服务端压缩传到浏览器进行解压并解析,现在大多数的浏览器都已经支持解析gzip过的页面,gzip使用环境:http块、server块、location块、if(x),一般把它定义在nginx.conf的http{…..}之间

原理

浏览器请求 ----> 声明可以接受gzip压缩(或deflate压缩或compress或sdch压缩) ----> 服务器回应 ----> 把内容用gzip方式压缩发给浏览器 ---->浏览解码gzip ----> 显示收gzip压缩内容
从http协议的角度看请求头声明 Accept-Encoding:gzip,deflate,sdch (是指压缩算法,其中sdch是google倡导的一种压缩方式,目前支持的服务器尚不多),响应头响应:Content-Encoding:gzip、Content-Length:36093
注意:图片/mp3这样的二进制文件,不必压缩,因为压缩率比较小,比如100->80字节,而且压缩也是耗费CPU资源的。比较小的文件也不必压缩。
Nginx实现资源压缩的原理是通过ngx_http_gzip_module模块拦截请求,并对需要做gzip的类型做gzip,ngx_http_gzip_module是Nginx默认集成的,不需要重新编译,直接开启即可

参数

加粗选项为常用选项

  • gzip on|off
    打开或关闭gzip
  • gzip_buffers 32 4k|16 8k|4 8k;
    设置用于处理请求压缩的缓冲区数量和大小。比如32 4K表示按照内存页大小以4K为单位(即一个系统中内存页为4K),申请32倍的内存空间。建议此项不设置,使用默认值
  • gzip_comp_level 6
    设置gzip压缩级别(1-9),级别越底压缩速度越快文件压缩比越小,反之速度越慢文件压缩比越大,常用值为6
    随着压缩级别的升高,压缩比有所提高,但到了级别6后,很难再提高;随着压缩级别的升高,处理时间明显变慢;gzip很消耗cpu的性能,高并发情况下cpu达到100%。
    不是压缩级别越高越好,其实gzip_comp_level 1的压缩能力已经够用了,后面级别越高,压缩的比例其实增长不大,反而很吃处理性能。压缩一定要和静态资源缓存相结合,缓存压缩后的版本,否则每次都压缩高负载下服务器肯定吃不住。
  • gzip_disable msie6;
    通过表达式,表明哪些UA头不使用gzip压缩。(IE5.5和IE6 SP1使用msie6参数来禁止gzip压缩 )指定哪些不需要gzip压缩的浏览器(将和User-Agents进行匹配),依赖于PCRE库
  • gzip_min_length 200;
    当返回内容大于此值时才会使用gzip进行压缩,以K为单位,当值为0时,所有页面都进行压缩
  • gzip_http_version 1.0|1.1;
    用于识别http协议的版本,早期的浏览器不支持gzip压缩,用户会看到乱码,所以为了支持前期版本加了此选项。默认在http/1.0的协议下不开启gzip压缩
  • gzip_proxied any;
    Nginx做为反向代理的时候启用:
    • off:关闭所有的代理结果数据压缩
    • expired:如果header中包含”Expires”头信息,启用压缩
    • no-cache:如果header中包含”Cache-Control:no-cache”头信息,启用压缩
    • no-store:如果header中包含”Cache-Control:no-store”头信息,启用压缩
    • private:如果header中包含”Cache-Control:private”头信息,启用压缩
    • no_last_modified:启用压缩,如果header中包含”Last_Modified”头信息,启用压缩
    • no_etag:启用压缩,如果header中包含“ETag”头信息,启用压缩
    • auth:启用压缩,如果header中包含“Authorization”头信息,启用压缩
    • any:无条件压缩所有结果数据
  • gzip_types text/html | application/x-javascript | text/css | application/xml;
    设置需要压缩的MIME类型,如果不在设置类型范围内的请求不进行压缩,对应的详细类型,可以在conf/mime.types中查看
  • gzip_vary on|off;
    是否传输gzip压缩标志,增加响应头”Vary: Accept-Encoding”

location详解

location 有”定位”的意思, 根据Uri来进行不同的定位,在虚拟主机的配置中是必不可少的,location可以把网站的不同部分,定位到不同的处理方式上。比如, .php文件则调用PHP解释器,这时就需要location

location语法

location [=|~|~*|^~] patt {...},中括号可以不写任何参数,此时称为一般匹配。patt可以是目录、文件、正则表达式。

  • =
    严格匹配(精确匹配)。只有请求的 url 路径与后面的字符串完全相等时,才会命中。如果这个查询匹配,那么将停止搜索并立即处理此请求。
  • ~
    区分大小写匹配(可用正则表达式)。
  • ~*
    不区分大小写匹配(可用正则表达式)。
  • ^~
    表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找,一般用来匹配目录。
  • @ name
    定义一个自定义命名的 location,主要用于内部重定向,不能用来处理正常的请求。

工作流程

工作流程
location命中过程:

  1. 先判断精确匹配,如果命中,立即返回结果并结束解析过程
  2. 判断普通命中,如果有多个命中,记录下来最长的命中结果【注意:仅仅是记录,并没有结束解析过程,最长的为准】
  3. 继续判断正则表达是的结果,按照配置中的正则表达式的顺序为准,由上至下开始匹配,一旦匹配成功则立即返回结果,并结束解析过程
    【注意:普通匹配的顺序无所谓,是因为按照命中的长短来确定;正则匹配顺序有所谓,因为是从前往后开始匹配】
    【总结】优先级:精确匹配>正则匹配>普通匹配;匹配顺序:精确匹配>普通匹配>正则匹配

举例

无正则

location = / {
   root  /var/www/html/;
   index index.htm index.html;
}
location / {
   root  /usr/local/nginx/html;
   index index.html index.htm;
}

location配置如上,若访问http://xxx.com/,定位的流程是:

  1. 精准匹配命中"/",得到index页为index.htm,所以请求的地址变为http://xxx.com/index.htm
  2. 再次匹配/index.htm,此次内部转跳uri已经是/index.htm,命中普通匹配/,根目录为/usr/local/nginx/html
  3. 最终结果访问了/usr/local/nginx/html/index.htm

有正则

location / {
  root  /usr/local/nginx/html;
  index index.html index.htm;
}
location ~ image {
  root  /var/www/;
  index index.html;
}

如果访问http://xx.com/image/logo.png,此时uri为/image/logo.png命中了普通匹配/,也命中了正则匹配~ image,但是根据上述图片中匹配过程分析,最终是正则匹配生效。所以最终访问地址为/var/www/image/logo.png

更长匹配

location / {
            root   /usr/local/nginx/html;
            index  index.html index.htm;
        }
location /foo {
            root /var/www/html;
            index index.html;
}

访问 http://xxx.com/foo, 对于uri来说,/foo两个location的patt都能匹配他们,即/能从左前缀匹配 /foo, /foo也能左前缀匹配/foo,此时真正访问/var/www/html/index.html,原因:/foo匹配的更长,因此使用之

@name的用法

location / {
  try_files $uri $uri/ @custom
}
location @custom {
  # ...do something
}

当访问url找不到对应的文件就重定向到我们自定义的命名location(此处为 custom)。命名 location中不能再嵌套其它的命名location。

综合

# 只匹配"/".
location = / { 
 [ configuration A ]  
} 
 # 匹配任何请求,因为所有请求都是以"/"开始,但是更长字符匹配或者正则表达式匹配会优先匹配 
location / { 
 [ configuration B ]  
} 
# 匹配任何以 /images/ 开始的请求,并停止匹配其它location 
location ^~ /images/ { 
 [ configuration C ]  
} 
# 匹配以 gif、jpg、jpeg结尾的请求,但是所有 /images/ 目录的请求将由 [Configuration C]处理.   
location ~* \.(gif|jpg|jpeg)$ { 
 [ configuration D ]  
}
  1. /:精确匹配到第1个location,匹配停止,使用configurationA
  2. /some/other/url:首先前缀部分字符串匹配到了第2个location,然后进行正则匹配,显然没有匹配上,则使用第2个location的配置configurationB
  3. /images /1.jpg:首先前缀部分字符串匹配到了第2个location,但是接着对第3个location也前缀匹配上了,而且这时已经是配置文件里面对这个url的最大字符串匹配了,并且location带有 "^~" 前缀,则不再进行正则匹配,最终使用configurationC
  4. /some/other/path/to/1.jpg:首先前缀部分同样字符串匹配到了第2个location,然后进行正则匹配,这时正则匹配成功,则使用congifurationD

URL尾部的/需不需要

  • location 中的字符有没有/都没有影响。也就是说/user/和/user是一样的。
  • 如果URL结构是https://domain.com/的形式,尾部有没有/都不会造成重定向。因为浏览器在发起请求的时候,默认加上了/,虽然很多浏览器在地址栏里也不会显示/,这一点,可以访问baidu验证一下。
  • 如果URL的结构是https://domain.com/some-dir/,尾部如果缺少/将导致重定向。因为根据约定,URL尾部的/表示目录,没有/表示文件。所以,访问/some-dir/时,服务器会自动去该目录下找对应的默认文件;访问/some-dir的话,服务器会先去找some-dir文件,找不到的话会将some-dir当成目录,重定向到/some-dir/,去该目录下找默认文件。

Rewrite语法详解

定义

rewrite功能就是使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。rewrite只能放在 server、 location、 if中,并且只能对域名后边的除去传递的参数外的字符串起作用。例如 http://seanlook.com/a/we/index.php?id=1&u=str只对/a/we/index.php重写。

语法

rewrite regex replacement [flag];
如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。rewrite和location功能有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。
很多情况下rewrite也会写在location里,它们的执行顺序是:

  1. 执行server块的rewrite指令
  2. 执行location匹配
  3. 执行选定的location中的rewrite指令
    如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500错误。

flag标志位

  • last : 相当于Apache的[L]标记,表示完成rewrite
  • break : 停止执行当前虚拟主机的后续rewrite指令集
  • redirect : 返回302临时重定向,地址栏会显示跳转后的地址
  • permanent : 返回301永久重定向,地址栏会显示跳转后的地址
    因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301、302的原因了。这里last和break区别有点难以理解:
  • last一般写在server和if中,而break一般使用在location中
  • last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
  • break和last都能组织继续执行后面的rewrite指令

常用正则

. : 匹配除换行符以外的任意字符
? : 重复0次或1次
+ : 重复1次或更多次
* : 重复0次或更多次
\d :匹配数字
^ : 匹配字符串的开始
$ : 匹配字符串的结束
{n} : 重复n次
{n,} : 重复n次或更多次
[c] : 匹配单个字符c
[a-z] : 匹配a-z小写字母的任意一个
小括号()之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容。
正则里面容易让人困惑的是\转义特殊字符

举例

例1

http {
    # 定义image日志格式
    log_format imagelog '[$time_local] ' $image_file ' ' $image_type ' ' $body_bytes_sent ' ' $status;
    # 开启重写日志
    rewrite_log on;
    
    server {
        root /home/www;
        
        location / {
            # 重写规则信息
            error_log logs/rewrite.log notice;
            # 注意这里要用‘'单引号引起来,避免{}
            rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4;
            # 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行
            set $image_file $3;
            set $image_type $4;
            }
        
        location /data {
            # 指定针对图片的日志格式,来分析图片类型和大小
            access_log logs/images.log mian;
            root /data/images;
            # 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个url里
            try_files /$arg_file /image404.html;
            }
        location = /image404.html {
            # 图片不存在返回特定的信息
            return 404 "image not found\n";
        }
}

# 对形如/images/ef/uh7b3/test.png的请求,重写到/data?file=test.png,
# 于是匹配到location /data,先看/data/images/test.png文件存不存在,
# 如果存在则正常响应,
# 如果不存在则重写tryfiles到新的image404 location,直接返回404状态码。

例2

rewrite ^/images/(.*)_(\d+)x(\d+)\.(png|jpg|gif)$ /resizer/$1.$4?width=$2&height=$3? last;
# 对形如/images/bla_500x400.jpg的文件请求,
# 重写到/resizer/bla.jpg?width=500&height=400地址,并会继续尝试匹配location。

if指令与全局变量

if (condition){重写模式},对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件可以是如下任何内容:

  • 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
  • 直接比较变量和内容时,使用=或!=
  • ~ 正则表达式匹配
  • ~* 不区分大小写的匹配
  • !~ 区分大小写的不匹配
  • -f和!-f 用来判断是否存在文件
  • -d和!-d 用来判断是否存在目录
  • -e和!-e 用来判断是否存在文件或目录
  • -x和!-x 用来判断文件是否可执行
    重写模式中常用指令:
  • set:设置变量用的, 可以用来达到多条件判断时作标志用,达到apache下的rewrite_condition的效果
  • return:返回状态码
  • break:跳出rewrite
  • rewrite:重写

例子

# 如果UA包含"MSIE",rewrite请求到/msid/目录下,即如果用户设备为IE浏览器的时候,重定向
if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
    } 
 
# IE浏览器访问时,跳转到ie.htm
if ($http_user_agent ~ MSIE) {
    rewrite ^.*$ /ie.htm;
    break;  # 不break会导致循环重定向
    }

# 判断IE并重写,且不用break,用set变量来达到目的【判断是IE浏览器且方位的不是ie.html,则进行重写】
if ($http_user_agent ~* msie) {
    set $isie 1;
    }
if ($fastcgi_script_name = ie.html) {
    set $isie 0;
    }
if ($isie 1) {
    rewrite ^.*$ ie.html;   # $isie的值为1则重写
    }

 # 如果cookie匹配正则,设置变量$id等于正则引用部分
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
    } 
 
 # 如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301、302
if ($request_method = POST) {
    return 405;
    } 
 
 # 限速,$slow可以通过set指令设置
if ($slow) {
    limit_rate 10k;
    } 
 
# 如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查
if (!-f $request_filename){
    break;
    proxy_pass http://127.0.0.1;
    } 
 
# 如果query string中包含"post=140",永久重定向到example.com
if ($args ~ post=140){
    rewrite ^ http://example.com/ permanent;
    }
 
 # 禁止192.168.1.100访问
if  ($remote_addr = 192.168.1.100) {
    return 403;
    }

# 当访问的文件不存在时,重定向至404.html
if (!-e $document_root$fastcgi_script_name) {
    rewrite ^.*$ /404.html break;
    } 
# 以 xx.com/dsafsd.html这个不存在页面为例,观察访问日志, 日志中显示的访问路径依然是"GET /dsafsd.html HTTP/1.1"
# 提示: 服务器内部的rewrite和302跳转不一样. 
#         跳转的话URL都变了,变成重新http请求404.html,而内部rewrite, 上下文没变,
#         就是说 fastcgi_script_name 仍然是 dsafsd.html,因此会循环重定向。

 # 防盗链
location ~* \.(gif|jpg|png|swf|flv)$ {
    valid_referers none blocked www.123.com www.abc.com;
    if ($invalid_referer) {
        return 404;
        } 
    }

全局变量

$args : #这个变量等于请求行中的参数,同$query_string
$content_length : 请求头中的Content-length字段。
$content_type : 请求头中的Content-Type字段。
$document_root : 当前请求在root指令中指定的值。
$host : 请求主机头字段,否则为服务器名称。
$http_user_agent : 客户端agent信息
$http_cookie : 客户端cookie信息
$limit_rate : 这个变量可以限制连接速率。
$request_method : 客户端请求的动作,通常为GET或POST。
$remote_addr : 客户端的IP地址。
$remote_port : 客户端的端口。
$remote_user : 已经经过Auth Basic Module验证的用户名。
$request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。
$scheme : HTTP方法(如http,https)。
$server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。
$server_name : 服务器名称。
$server_port : 请求到达服务器的端口号。
$request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
$uri : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
$document_uri : 与$uri相同。

例子

http://localhost:88/test1/test2/test.php
    $host:localhost
    $server_port:88
    $request_uri:http://localhost:88/test1/test2/test.php
    $document_uri:/test1/test2/test.php
    $document_root:/var/www/html
    $request_filename:/var/www/html/test1/test2/test.php

基于ecshop的Rewrite实战

注意:用url重写时, 正则里如果有{},正则要用双引号包起来

location /ecshop {
    index index.php;
    # 将"goods-xxxxxxx.html"重写到"goods.php?id=xxxxxxx"
    rewrite "goods-(\d{1,7})\.html" /exshop/goods.php?id=$1;  # $1为正则匹配的后向引用
    # 或者
    rewrite goods-([\d]+)\.html$ /ecshop/goods.php?id=$1;

    # 下面为各个页面的重写配置
    rewrite article-([\d]+)\.html$ /ecshop/article.php?id=$1;
    rewrite category-(\d+)-b(\d+)\.html /ecshop/category.php?id=$1&brand=$2;
    rewrite category-(\d+)-b(\d+)-min(\d+)-max(\d+)-attr([\d\.]+)\.html /ecshop/category.php?id=$1&brand=$2&price_min=$3&price_max=$4&filter_attr=$5;
    rewrite category-(\d+)-b(\d+)-min(\d+)-max(\d+)-attr([\d+\.])-(\d+)-([^-]+)-([^-]+)\.html /ecshop/category.php?id=$1&brand=$2&price_min=$3&price_max=$4&filter_attr=$5&page=$6&sort=$7&order=$8;
}

nginx缓存配置

提高网站性能。对于网站的图片,尤其是新闻站,,图片一旦发布,,改动的可能是非常小的。能否在用户访问一次后,图片缓存在用户的浏览器端,且时间比较长的缓存。

expires参数

使用nginx的expires设置 ,可以在location块或if块里,格式如下:

expires 30s;
expires 30m;
expires 2h;
expires 30d;
# 【注意】:服务器的日期要准确,如果服务器的日期落后于实际日期,可能导致缓存失效

304(Not Modified)

304也是一种很好的缓存手段,这个不需要设置
原理:服务器响应文件内容时,同时响应Etag标签(内容的签名,内容一变,他也变)和Last_Modified这2个标签值(Expires为缓存内容到期时间),浏览器下次去请求时,头信息发送这两个标签, 服务器检测文件有没有发生变化,如过没有发生变化,直接头信息返回EtagLast_Modified。浏览器知道内容无改变,于是直接调用本地缓存。
这个过程,也请求了服务器,但是传着的内容极少。对于变化周期较短的,如静态html、js、css,比较适于用这个方式。

nginx反向代理和负载均衡(nginx+apache动静分离)

用nginx做反向代理和负载均衡非常简单,支持两个用法proxyupstream,分别用来做反向代理和负载均衡。
详细的配置参考上面的内容。

反向代理

以反向代理为例,nginx不自己处理php的相关请求,而是把php的相关请求转发给apache来处理。
下图为“动静分离”,动静分离不是一个严谨的说法,叫反向代理比较规范。
动静分离
主要配置:proxy_pass http://192.168.1.200:8080,其中http://必须添加,这是指明协议

# Apache配置
cd /usr/local/httpd
vim conf/httpd.conf
    Listen 8080
    Include conf/extra/httpd-vhosts.conf
    <Directory />
        Option FollowSymLinks
        AllowOverride all
        Order deny,allow
        Allow from all
    </Directory>
vim conf/extra/httpd-vhost.conf
    NameVirtualHost *:8080
    <VirtualHost *:8080>
        ServerAdmin webmaster@dummy-host.example.com
        DocumentRoot "/usr/local/nginx/html"
        ServerName "192.168.1.200"
        ServerAlias www.dummy-host.example.com
    </VirtualHost>

# Nginx配置
cd /usr/local/nginx
vim conf/nginx.conf
    location ~ \.php$ {
        proxy_pass http://192.168.1.200:8080 # 将php文件交给apache处理
    }

测试脚本test.php:

// 动态
<?php  
//phpinfo();
echo rand(1,1000);  //产生1~1000内的随机数
?>
// 静态
<img src="image/logo.png" /> 

负载均衡

反向代理后端如果有多台服务器,自然可形成负载均衡,但proxy_pass需要指向多台服务器,把多台服务器用upstream指定绑定在一起并起个组名,然后proxy_pass指向该组
默认的均衡的算法很简单,就是针对后端服务器的按照顺序逐个请求,也有其他负载均衡算法,如一致性哈希等(需要安装第3方模块)。

vim conf/nginx.conf
    upstream imgserver {
        server 192.168.1.200:81 weight=1 fail_timeout=3 max_fails=2;
        server 192.168.1.200:82 weight=1 fail_timeout=3 max_fails=2;
        
    } 
    server {
        listen 81;
        serber_name localhost;
        root html;
        access_log logs/81-access.log main;
    }
    server {
        listen 82;
        serber_name localhost;
        root html;
        access_log logs/82-access.log main;
    }
    location ~* \.(jpg|jpeg|gif|png) {
        # 反向代理导致了后端服务器收到的源IP为前端服务器的IP,而不是客户真正的IP,解决方法如下
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_pass http://imgserver;
    }

nginx连接memcached

memcached

memcached是一套分布式的高速缓存系统,被许多网站使用。

安装

yum -y install libmemcache* memcache* # 安装memcached及php的memcached扩展
memcached -d -l 127.0.0.1 -p 11211 -m 500 -u root
    # -d:守护进程。当从终端窗口退出的时候memcached还会继续运行
    # -l:指定ip地址,这里指定本地ip
    # -p:指定端口号,端口号为11211
    # -m:分配内存,这里分配了500M内存
    # -u:使用哪个用户运行memcached

php连接memecached的配置如下:

# 编译php连接memecached的扩展
vim conf/php.ini
    extension=memcached.so

使用教程

参考:https://www.runoob.com/Memcached/Memcached-tutorial.html

# 连接 
telnet 127.0.0.1 11211
# 创建值
add /user1.html 0 0 7 # key="/user1.html",flag=0,exptime=0,bytes=7
i am lisi  # value="i am lisi"
# 如果数据添加成功,则输出STORED

nginx连接memcached

nginx的memcached_module模块可以直接从memcached服务器中读取内容后输出,后续的请求不再经过应用程序处理,如php-fpm、django等,大大的提升动态页面的速度。
nginx只负责从memcached服务器中读取数据,要往memcached写入数据还得需要后台的应用程序来完成,主动的将要缓存的页面缓存到memcached中,可以通过404重定向到后端去处理的。
ngx_http_memcached_module可以操作任何兼用memcached协议的软件。如ttserver、membase等。
nginx连接memcached
memcached的key可以通过memcached_key来设置。如果命中,那么直接输出内容,没有命中就意味着nginx需要从应用程序请求页面。同时,该应用程序将键值对写入到memcached,以便下一个请求可以直接从memcached获取。
如果键值不存在,nginx将报告not found错误。

最好的方法是使用error_page指定和location请求处理。同时包含Bad Gateway错误和Gateway Timeout错误,例如error_page 404 502 504 = @app;。【注意】:需要设置default_type,否则可能会显示不正常。

参数详解

  • memcached_bind:指定从哪个IP来连接memcached服务器。语法: memcached_bind address | off,默认值none。配置段http, server, location
  • memcached_buffer_size:读取从memcached服务器接收到响应的缓冲大小,尽快的将响应同步传给客户端。语法: memcached_buffer_size size,默认值4k|8k。配置段: http, server, location
  • memcached_connect_timeout:与memcached服务器建立连接的超时时间,通常不超过75s。语法:memcached_connect_timeout time,默认值60s。配置段:http, server, location
  • memcached_gzip_flag:测试memcached服务器响应标志,如果设置了,将在响应头部添加了Content-Encoding:gzip。语法:memcached_gzip_flag flag,默认值none。配置段:http, server, location
  • memcached_next_upstream:指定在哪些状态下请求将转发到另外的负载均衡服务器上,仅当memcached_pass有两个或两个以上时使用。语法:memcached_next_upstream error | timeout | invalid_response | not_found | off ...,默认值error timeout。配置段: http, server, location
  • memcached_pass:指定memcached服务器地址。使用变量$memcached_key为key查询值,如果没有相应的值则返回error_page 404。语法:memcached_pass address:port or socket,默认值none。配置段:location, if in location
  • memcached_read_timeout:定义从memcached服务器读取响应超时时间。语法:memcached_read_timeout time,默认值60s。配置段:http, server, location
  • memcached_send_timeout:设置发送请求到memcached服务器的超时时间。语法:memcached_send_timeout,默认值60s。配置段:http, server, location
  • $memcached_key 变量:memcached key的值,可以设置为$request_uri$uri$request_method$request_uri$uri?$args

配置

vim conf/nginx.conf
    server {
        location / {
            # set            $memcached_key "$uri?$args";
            set            $memcached_key "$uri";
            memcached_pass 127.0.0.1:11211;
            # error_page     404 502 504 = @fallback;
            error_page 404 /callback.php
        }
        # location @fallback {
        #     proxy_pass     http://backend;
        # }
    }

vim php.ini
    memcache.hash_strategy=consistent

vim html/callback.php
    <?php
    //print_r($_SERVER);
    //获取uri,用来当memcached的key
    $uri = $_SERVER['REQUEST_URI'];
    //echo $uri

    //添加多台服务器,php也需要添加和nginx一样多的服务器
    $mem = new memcache();
    $mem->addServer('192.168.1.200',11211); # 此时不能用localhost
    $mem->addServer('192.168.1.200',11212);
    $mem->addServer('192.168.1.200',11213);

    //提取uri中的uid
    $uid=substr($uri,5,strpos($uri,".")-5);
    //echo $uid;
    // 连接数据库,查询并写入memcached
    $conn = mysql_connect('localhost','root','');
    $sql = 'use test';
    mysql_query($sql,$conn);
    $sql = 'use names utf8';
    mysql_query($sql,$conn);
    $sql = 'select * from user where uid='.$uid;
    $rs = mysql_query($sql,$conn);
    echo 'from mysql query<br />';
    $user = mysql_fetch_assoc($rs);
    if (empty($user)){
        echo "no this user";        
    }else{
        //print_r($user);
        $html = '<h1>'. $user['username'] .'</h1>';
        echo $html
        //$mem = new memcache();
        //$mem->connect('localhost',11211);
        $mem->add($uri,$html,0,300);
        $mem->close();
    }

多台memcache

多台memcache时,nginx与php如何保持集群上的算法同步?

第三方模块(ngx_http_consistent_hash)的安装

Nginx upstream可以实现负载均衡。第三方模块ngx_http_consistent_hash通过一致性哈希算法来选择合适的后端节点。

cd /usr/local/src
wget https://codeload.github.com/replay/ngx_http_consistent_hash/zip/master
unzip master.zip
cd nginx-1.18.0
./configure --prefix=/usr/local/nginx --add-module=/usr/local/src/ngx_http_consistent_hash-master   # --add-module后面是第三方模块的路径
make && make install

配置memcache集群

vim conf/nginx.conf
    upstream mcserver {
        consistent_hash "$request_uri";
        server 192.168.1.200:11211;  # 此时不能用localhost
        server 192.168.1.200:11212;
        server 192.168.1.200:11213;
    }
    location / {
        set $memcached_key "$uri";
        memcached_pass mcserver;
        error_page 404 /callback.php;
       }

高性能的服务器的架设

主要讲解大量访问整体优化思路,对于高性能网站 ,请求量大,如何支撑?

  1. 要减少请求:对于开发人员,合并css, 背景图片, 减少mysql查询等
  2. 对于运维nginx的expires,利用浏览器缓存等,减少查询
  3. 利用cdn来响应请求
  4. 最终剩下的,不可避免的请求,通过服务器集群+负载均衡来支撑。来到这步,就不要再考虑减少请求这个方向了,而是思考如何更好的响应高并发请求。既然响应是不可避免的,就把要做的把工作内容”平均”分给每台服务器,最理想的状态是每台服务器的性能都被充分利用。

内核参数调整

网络

net.core.somaxconn = 4096 允许等待中的监听
net.ipv4.tcp_tw_recycle = 1 tcp连接快速回收
net.ipv4.tcp_tw_reuse = 1 tcp连接重用
net.ipv4.tcp_syncookies = 0 不抵御洪水攻击

防火墙(建议关掉)

net.nf_conntrack_max = 655350
net.netfilter.nf_conntrack_tcp_timeout_established = 120

文件

fs.file-max = 655360 系统最大文件描述符

进程最大文件描述符

/etc/security/limits.conf
soft nofile 50000
hard nofile 50000

nginx参数调整

work process 打开的进程数量,为CPU核心数即可
worker_rlimit_nofile 30000; 进程打开文件的最大数量
keepalive_timeout 0;

php-fpm参数调整

pm = static
pm.max_children = 32