• 负载均衡中间件(一)Nginx高性能负载均衡器


    Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/PO3)代理服务器,并在一个BSD协议下发行,可以在UNIX、GNU/Linux、BSD、Mac OS X、Solaris,以及Microsoft Windows等操作系统中运行。

    由俄罗斯的码农lgor Sysover所开发,最初供俄国大型的入口网站及搜寻引擎Rambler使用。其特点是占用内存少,并发能力强(用于解决C10K问题,现在可轻松处理C100K),事实上nginx的并发能力确实在同类型的网页服务器中表现较好。

    I

    一、Nginx基础

    Nginx安装

    编译安装

    linux C++ 通讯架构(一)nginx安装、目录、进程模型

    非编译安装

    Install the prerequisites:

    sudo yum install yum-utils
    

    To set up the yum repository, create the file named /etc/yum.repos.d/nginx.repo with the following contents:

    [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
    module_hotfixes=true
    
    [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
    module_hotfixes=true
    

    By default, the repository for stable nginx packages is used. If you would like to use mainline nginx packages, run the following command:

    sudo yum-config-manager --enable nginx-mainline
    

    To install nginx, run the following command:

    sudo yum install nginx

    Nginx虚拟主机

    如果你有两个不同域名的网站,但是你只有一台服务器,这时候怎么办?其实利用nginx或者apache都可以帮你用一台机器来模拟多台机器作为服务器提供服务。

    虚拟主机,就是把一台物理服务器划分成多个“虚拟”的服务器,每一个虚拟主机都可以有独立的域名和独立的目录。

    nginx的虚拟主机就是通过nginx.conf中server节点指定的,想要设置多个虚拟主机,配置多个server节点即可。

    先看一个最简单的虚拟主机配置示例

    server { 
      listen 80; 
      server_name a.test.com; 
    
      location / { 
        index index.html; 
        root /home/www/host_a/; 
      } 
    }

    其中

    listen 80; 

    指定这个虚拟主机监听的是80端口

    server_name a.test.com; 

    指定这个虚拟主机名为a.test.com,当用户访问a.test.com时,就有这个虚机主机进行处理。

    指定这个虚拟主机名为a.test.com,当用户访问a.test.com时,就有这个虚机主机进行处理。

    多台虚拟主机
    (1)对两个域名配置相应的虚拟主机,指定不同的目录

    a.test.com -> /home/www/a
    b.test.com -> /home/www/b

    配置

    server { 
    listen 80; 
    server_name a.test.com; 
    
    #开启网站目录文件列表功能,访问目录时列出其中的文件列表,默认不开启
    autoindex on; 
    
    index index.html; 
    root /home/www/a/; 
    }
    
    server { 
    listen 80; 
    server_name b.test.com; 
    
    index index.html; 
    root /home/www/b/; 
    
    #禁止对self目录的访问
    location /(self)/ { 
    deny all; 
        } 
    }

    通过 Nginx 可以实现虚拟主机的配置,Nginx 支持三种类型的虚拟主机配置

    • 基于 IP 的虚拟主机
    • 基于域名的虚拟主机
    • 基于端口的虚拟主机

    基于 IP 的虚拟主机配置

    Linux 操作系统允许添加 IP 别名,IP 别名就是在一块物理网卡上绑定多个 lP 地址。这样就能够在使用单一网卡的同一个服务器上运行多个基于 IP 的虚拟主机。

    需求

    • 一台 Nginx 服务器绑定两个 IP:192.168.75.145、192.168.75.245
    • 访问不同的 IP 请求不同的 HTML 目录,即:
      • 访问 http://192.168.75.145 将访问 html145 目录下的 html 网页
      • 访问 http://192.168.75.245 将访问 html245 目录下的 html 网页

    创建目录及文件

    /usr/local/docker/nginx/html 目录下创建 html145html245 两个目录,并分辨创建两个 index.html 文件

    绑定多 IP

    ifconfig ens33:0 192.168.75.245 broadcast 192.168.75.255 netmask 255.255.255.0

    配置虚拟主机

    修改 /usr/local/docker/nginx 目录下的 nginx.conf 配置文件:

    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
    
        sendfile        on;
        
        keepalive_timeout  65;
        # 配置虚拟主机 192.168.75.145
        server {
        # 监听的ip和端口,配置 192.168.75.145:80
            listen       80;
        # 虚拟主机名称这里配置ip地址
            server_name  192.168.75.145;
        # 所有的请求都以/开始,所有的请求都可以匹配此 location
            location / {
            # 使用 root 指令指定虚拟主机目录即网页存放目录
            # 比如访问 http://ip/index.html 将找到 /usr/local/docker/nginx/html/html145/index.html
            # 比如访问 http://ip/item/index.html 将找到 /usr/local/docker/nginx/html/html145/item/index.html
    
                root   /usr/share/nginx/html145;
            # 指定欢迎页面,按从左到右顺序查找
                index  index.html index.htm;
            }
    
        }
        # 配置虚拟主机 192.168.75.245
        server {
            listen       80;
            server_name  192.168.75.245;
    
            location / {
                root   /usr/share/nginx/html245;
                index  index.html index.htm;
            }
        }
    }

    基于端口的虚拟主机配置

    需求

    • Nginx 对外提供 80 和 8080 两个端口监听服务
    • 请求 80 端口则请求 html80 目录下的 html
    • 请求 8080 端口则请求 html8080 目录下的 html

    创建目录及文件

    /usr/local/docker/nginx/html 目录下创建 html80html8080 两个目录,并分辨创建两个 index.html 文件

    配置虚拟主机

    修改 /usr/local/docker/nginx 目录下的 nginx.conf 配置文件:

    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
    
        sendfile        on;
        
        keepalive_timeout  65;
        # 配置虚拟主机 192.168.75.145
        server {
        # 监听的ip和端口,配置 192.168.75.145:80
            listen       80;
        # 虚拟主机名称这里配置ip地址
            server_name  192.168.75.145;
        # 所有的请求都以/开始,所有的请求都可以匹配此 location
            location / {
            # 使用 root 指令指定虚拟主机目录即网页存放目录
            # 比如访问 http://ip/index.html 将找到 /usr/local/docker/nginx/html/html145/index.html
            # 比如访问 http://ip/item/index.html 将找到 /usr/local/docker/nginx/html/html145/item/index.html
    
                root   /usr/share/nginx/html80;
            # 指定欢迎页面,按从左到右顺序查找
                index  index.html index.htm;
            }
    
        }
        # 配置虚拟主机 192.168.75.245
        server {
            listen       8080;
            server_name  192.168.75.245;
    
            location / {
                root   /usr/share/nginx/html8080;
                index  index.html index.htm;
            }
        }
    }

    注意: 别忘记将容器的 8080 端口映射到宿主机,否则无法访问 8080 端口

    基于域名的虚拟主机配置

    需求

    • 两个域名指向同一台 Nginx 服务器,用户访问不同的域名显示不同的网页内容
    • 两个域名是 admin.ooqiu.com 和 service.ooqiu.com
    • Nginx 服务器使用虚拟机 192.168.75.145

    配置 Windows Hosts 文件

    • 通过 host 文件指定 admin.ooqiu.com 和 service.ooqiu.com 对应 192.168.75.145 虚拟机:
    • 修改 window 的 hosts 文件:(C:WindowsSystem32driversetc)
    image.png

    创建目录及文件

    /usr/local/docker/nginx/html 目录下创建 htmladminhtmlservice 两个目录,并分辨创建两个 index.html 文件

    配置虚拟主机

    user  nginx;
    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
    
        sendfile        on;
    
        keepalive_timeout  65;
        server {
            listen       80;
            server_name  admin.ooqiu.com;
            location / {
                root   /usr/share/nginx/htmladmin;
                index  index.html index.htm;
            }
    
        }
    
        server {
            listen       80;
            server_name  service.ooqiu.com;
    
            location / {
                root   /usr/share/nginx/htmlservice;
                index  index.html index.htm;
            }
        }
    }

    Nginx配置文件

    Nginx的配置文件nginx.conf位于其安装目录的conf目录下。
    nginx.conf由多个块组成,最外面的块是main,main包含Events和HTTP,HTTP包含upstream和多个Server,Server又包含多个location


    从图中我们可以看出主要包含以下几大部分内容:
    • 1、全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
    • 2、events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
    • 3、http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。
    • 4、server块:配置虚拟主机的相关参数,一个http中可以有多个server。
    • 5、location块:配置请求的路由,以及各种页面的处理情况。
    ########### 每个指令必须有分号结束。#################
    #user administrator administrators;  #配置用户或者组,默认为nobody nobody。
    #worker_processes 2;  #允许生成的进程数,默认为1
    #pid /nginx/pid/nginx.pid;   #指定nginx进程运行文件存放地址
    error_log log/error.log debug;  #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别以此为:debug|info|notice|warn|error|crit|alert|emerg
    events {
        accept_mutex on;   #设置网路连接序列化,防止惊群现象发生,默认为on
        multi_accept on;  #设置一个进程是否同时接受多个网络连接,默认为off
        #use epoll;      #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
        worker_connections  1024;    #最大连接数,默认为512
    }
    http {
        include       mime.types;   #文件扩展名与文件类型映射表
        default_type  application/octet-stream; #默认文件类型,默认为text/plain
        #access_log off; #取消服务日志    
        log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定义格式
        access_log log/access.log myFormat;  #combined为日志格式的默认值
        sendfile on;   #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
        sendfile_max_chunk 100k;  #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
        keepalive_timeout 65;  #连接超时时间,默认为75s,可以在http,server,location块。
    
        upstream mysvr {   
          server 127.0.0.1:7878;
          server 192.168.10.121:3333 backup;  #热备
        }
        error_page 404 https://www.baidu.com; #错误页
        server {
            keepalive_requests 120; #单连接请求上限次数。
            listen       4545;   #监听端口
            server_name  127.0.0.1;   #监听地址       
            location  ~*^.+$ {       #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
               #root path;  #根目录
               #index vv.txt;  #设置默认页
               proxy_pass  http://mysvr;  #请求转向mysvr 定义的服务器列表
               deny 127.0.0.1;  #拒绝的ip
               allow 172.18.5.54; #允许的ip           
            } 
        }
    }

    上面是nginx的基本配置,需要注意的有以下几点:

    1、几个常见配置项:

    • 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 :记录客户端浏览器的相关信息;

    2、惊群现象:一个网路连接到来,多个睡眠的进程被同事叫醒,但只有一个进程能获得链接,这样会影响系统性能。

    3、每个指令必须有分号结束。

    常见内置变量

    $args                      请求中的参数;
    $binary_remote_addr        远程地址的二进制表示
    $body_bytes_sent           已发送的消息体字节数
    $content_length            HTTP请求信息里的"Content-Length"
    $content_type              请求信息里的"Content-Type"
    $document_root             针对当前请求的根路径设置值
    $document_uri              与$uri相同
    $host                      请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名;    
    $http_cookie               cookie 信息 
    $http_referer              来源地址
    $http_user_agent           客户端代理信息
    $http_via                  最后一个访问服务器的Ip地址
    $http_x_forwarded_for      相当于网络访问路径。    
    $limit_rate                对连接速率的限制          
    $remote_addr               客户端地址
    $remote_port               客户端端口号
    $remote_user               客户端用户名,认证用
    $request                   用户请求信息
    $request_body              用户请求主体
    $request_body_file         发往后端的本地文件名称      
    $request_filename          当前请求的文件路径名
    $request_method            请求的方法,比如"GET""POST"等
    $request_uri               请求的URI,带参数   
    $server_addr               服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费)
    $server_name               请求到达的服务器名
    $server_port               请求到达的服务器端口号
    $server_protocol           请求的协议版本,"HTTP/1.0""HTTP/1.1"
    $uri 

    二、Nginx负载均衡

    正向代理和反向代理

    正向代理

    类似一个跳板机,代理访问外部资源

    反向代理(Reverse Proxy)

    实际运行方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

    正向代理:客户端 <一> 代理 一>服务端

    类似一个跳板机,代理访问外部资源。接收局域网请求,访问互联网。

    反向代理:客户端 一>代理 <一> 服务端

    实际运行方式是指一代理服务器来解释Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。接收互联网请求,访问局域网。

    反向代理作用:

    1.保证内网的安全,可以使用反向代理提供的WAF功能,阻止web攻击。大型网站,通常将反向代理作为公网访问地址,web服务器是内网

    2.负载均衡,通过反向代理服务器来优化网站的负载

    负载均衡原理

    负载均衡,但从字面上的意思来理解可以解释为N台服务器平均分担负载,不会因为某台服务器负载高宕机和某台服务器闲置的情况。负载均衡的前提就是2台以上服务器才能实现。

    Nginx负载均衡4种配置方案

    1.轮询

    Round Robin,根据Nginx配置文件中的顺序,依次把客户端的web请求分发到不同的后端服务器上。

    2.最少连接least_conn

    Web请求会被转发到连接数最少的服务器

    3.IP地址哈希ip_hash

    前述的两种负载均衡方案中,同一客户端连续的Web请求可能会被分发到不同的后端服务器进行处理,因此如果涉及到会话session,那么会话会比较复杂。常见的基于数据库的会话持久化。要克服上面的难题,可以使用基于IP地址哈希的负载均衡方案。这样的话,同一客户端连续的Eeb请求都会被分发到同一服务器进行处理。

    4.基于权重weight

    基于权重的负载均衡(weighted load balancing),可以配置Nginx把请求更多地分发到高配置的后端服务器上,把相对较少的请求分发到低配服务器。

    负载均衡配置

    配置基于Round Robin轮询的负载均衡

    注意:

    1.缺省配置就是轮询策略。

    2.nginx负载均衡支持http和https协议,只要修改proxy_pass后协议即可。

    3.nginx支持FastCGI,uwsgi,SCGI,memcached的负载均衡,只需将proxy_pass改为fastcgi,uwsgi_pass,sci_pass,memcached_pass即可。

    4.此策略适合服务器配置相当,无状态且短平快的服务使用。

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    
    events{
      use epoll;
      worker_connections 65535;
    }
    
    http{
      upstream netease.com{
        server 127.0.0.1:8881;
        server 127.0.0.1:8882;
        server 127.0.0.1:8883;
      }
      
      server{
        listen 80;
        server_name netease.com;
         
        location /{
          proxy_pass http://netease.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
        }
      }
    }

    worker_processes 设为auto表示,cpu有多少核,就启动多少worker进程

    pid 进程编号所放的位置

    events nginx采用了基于事件的网络IO,比如多路复用的NIO技术,最成熟的是linux下的epoll

    http upstream转发,netease.com是我们配置的后端服务,下面的三台服务器,是要轮询的服务器

    server 监听80端口,server_name,location

     $remote_addr 客户端地址

    配置基于ip_hash的负载均衡

    注意:

    1.ip哈希负载均衡使用ip_hash指令定义

    2.nginx使用请求客户端的ip地址进行哈希计算,确保使用同一个服务器响应请求

    3.此策略适合有状态服务,比如session

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    
    events{
      use epoll;
      worker_connections 65535;
    }
    
    http{
      upstream netease.com{
        ip_hash;
        server 127.0.0.1:8881;
        server 127.0.0.1:8882;
        server 127.0.0.1:8883;
      }
      
      server{
        listen 80;
        server_name netease.com;
         
        location /{
          proxy_pass http://netease.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
        }
      }
    }

    配置基于least_conn的负载均衡

    注意:

    1.最少链接负载均衡通过least_conn指令定义

    2.此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    
    events{
      use epoll;
      worker_connections 65535;
    }
    
    http{
      upstream netease.com{
        least_conn;
        server 127.0.0.1:8881;
        server 127.0.0.1:8882;
        server 127.0.0.1:8883;
      }
      
      server{
        listen 80;
        server_name netease.com;
         
        location /{
          proxy_pass http://netease.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
        }
      }
    }

    配置基于权重的负载均衡

    注意:

    1.权重负载均衡需要使用weight指令定义

    2.权重越高分配到需要处理的请求越多

    3.此策略可以与最少链接负载和ip哈希策略结合使用

    4.此策略比较适合服务器的硬件配置差别比较大的情况

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    
    events{
      use epoll;
      worker_connections 65535;
    }
    
    http{
      upstream netease.com{
        least_conn;
        server 127.0.0.1:8881;
        server 127.0.0.1:8882;
        server 127.0.0.1:8883;
      }
      
      server{
        listen 80;
        server_name netease.com;
         
        location /{
          proxy_pass http://netease.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
        }
      }
    }
    
    
    基于权重
    
    注意:
    
    权重负载均衡需要使用weight指令定义
    权重越高分配到需要处理的请求越多
    此策略可以与最少链接负载和ip哈希策略结合使用
    此策略比较适合服务器的硬件配置差别较大的情况
    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    
    events{
      use epoll;
      worker_connections 65535;
    }
    
    http{
      upstream netease.com{
        server 127.0.0.1:8881 weight=3;
        server 127.0.0.1:8882 weight=2;
        server 127.0.0.1:8883 weight=1;
      }
      
      server{
        listen 80;
        server_name netease.com;
         
        location /{
          proxy_pass http://netease.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
        }
      }
    }

    二、代理缓存机制

    nginx的http_proxy模块,可以实现类似于Squild的缓存功能

    nginx对客户已经访问过的内容在nginx服务器本地建立副本,这样在一段时间内再次访问该数据,就不需要通过nginx服务器再次向后端服务器发出请求,所以能够减少nginx服务器与后端服务器之间的网络流量,减轻网络拥塞,同时还能减小数据传输延迟,提高用户访问速度。

    同时,当后端服务器宕机时,nginx服务器上的副本资源还能够回应相关的用户请求,这样能够提高后端服务器的鲁棒性。

    缓存文件放在哪?

    proxy_cache_path:nginx使用该参数指定缓存位置

    proxy_cache:该参数为之前指定的缓存名称

    proxy_cache_path:有两个必填参数

    第一个参数为缓存目录

    第二个参数keys_zone指定缓存名称和占用内存空间的大小

    下面示例中的10m是对内存中缓存内容元数据信息大小的限值,如果想限值缓存总量大小,需要用max_size参数

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid
    
    http{
      proxy_cache_path /data/nginx/cache keys_zone=one:10m max_size=10g;
      upstream yes.163.com{
        server 127.0.0.1:8881;
        server 127.0.0.1:8882;
        server 127.0.0.1:8883;
      }
      
      server{
        listen 80;
        proxy_cache one;
        server_name yes.163.com;
         
        location /{
          proxy_pass http://yes.163.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
        }
      }
    }

    如何指定哪些请求被缓存?

    1.nginx默认会缓存所有get和head方法的请求结果,缓存的key默认使用请求字符串。

    2.自定义key

    例如proxy_cache_key $host$request_uri$cookie_user

    3.指定请求至少被发送了多少次以上时才缓存,可以防止低频请求被缓存

    例如proxy_cache_min_uses 5

    4.指定哪些方法的请求被缓存

    例如proxy_cache_methods GET HEAD POST

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid
    
    http{
      proxy_cache_path /data/nginx/cache keys_zone=one:10m;
      
      upstream yes.163.com{
        server 127.0.0.1:8881;
        server 127.0.0.1:8882;
        server 127.0.0.1:8883;
      }
      
      server{
        listen 80;
        proxy_cache one;
        server_name yes.163.com;
         
        location /{
          proxy_pass http://yes.163.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
          proxy_cache_key $host$request_uri$cookie_user;
        }
      }
    }

    缓存有效期

    默认情况下,缓存内容长期留存,除法缓存的总量超出限制。可以指定缓存有效时间,例如:

    • 响应状态码为200200 302时,10分钟有效proxy_cache_valid 200 302 10m
    • 对应任何状态码,5分钟有效proxy_cache_valid any 5m

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid
    
    http{
      proxy_cache_path /data/nginx/cache keys_zone=one:10m;
      
      upstream yes.163.com{
        server 127.0.0.1:8881;
        server 127.0.0.1:8882;
        server 127.0.0.1:8883;
      }
      
      server{
        listen 80;
        proxy_cache one;
        server_name yes.163.com;
         
        location /{
          proxy_pass http://yes.163.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
          proxy_cache_valid 200 302 10m;
        }
      }
    }

    对于某些请求,是否可以不走缓存?

    prox_cache_bypass:该指令响应来自原始服务器而不是缓存

    例如:proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment

    如果任何一个参数值不为空,或者不等于0,nginx就不会查找缓存,直接进行代理转发

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid
    
    http{
      proxy_cache_path /data/nginx/cache keys_zone=one:10m;
      
      upstream yes.163.com{
        server 127.0.0.1:8881;
        server 127.0.0.1:8882;
        server 127.0.0.1:8883;
      }
      
      server{
        listen 80;
        proxy_cache one;
        server_name yes.163.com;
         
        location /{
          proxy_pass http://yes.163.com;
          proxy_set_header Host  $host;
          proxy_set_header  X-Real-IP  $remote_addr;
          proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
        }
      }
    }

    网页的缓存是由HTTP消息头“Cache-control”来控制的,常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。其作用根据不同的重新浏览方式分为下面几种情况。

     示例

     9000端口开一个原服务器,80开缓存服务器

    创建/root/nodejs目录,下面创建index.html,index.htm和public目录,public目录下创建9000.css.

    [root@node01 mynginx]# cd /etc/nginx
    [root@node01 nginx]# ll
    total 40
    drwxr-xr-x 2 root root 4096 Feb 25 12:24 conf.d
    -rw-r--r-- 1 root root 1007 Jan 21 22:51 fastcgi_params
    -rw-r--r-- 1 root root 2837 Jan 21 22:51 koi-utf
    -rw-r--r-- 1 root root 2223 Jan 21 22:51 koi-win
    -rw-r--r-- 1 root root 5231 Jan 21 22:51 mime.types
    lrwxrwxrwx 1 root root   29 Feb 25 12:24 modules -> ../../usr/lib64/nginx/modules
    -rw-r--r-- 1 root root  643 Jan 21 22:48 nginx.conf
    -rw-r--r-- 1 root root  636 Jan 21 22:51 scgi_params
    -rw-r--r-- 1 root root  664 Jan 21 22:51 uwsgi_params
    -rw-r--r-- 1 root root 3610 Jan 21 22:51 win-utf
    [root@node01 nginx]# mkdir h5bp
    [root@node01 nginx]# ll
    total 44
    drwxr-xr-x 2 root root 4096 Feb 25 12:24 conf.d
    -rw-r--r-- 1 root root 1007 Jan 21 22:51 fastcgi_params
    drwxr-xr-x 2 root root 4096 Feb 25 15:18 h5bp
    -rw-r--r-- 1 root root 2837 Jan 21 22:51 koi-utf
    -rw-r--r-- 1 root root 2223 Jan 21 22:51 koi-win
    -rw-r--r-- 1 root root 5231 Jan 21 22:51 mime.types
    lrwxrwxrwx 1 root root   29 Feb 25 12:24 modules -> ../../usr/lib64/nginx/modules
    -rw-r--r-- 1 root root  643 Jan 21 22:48 nginx.conf
    -rw-r--r-- 1 root root  636 Jan 21 22:51 scgi_params
    -rw-r--r-- 1 root root  664 Jan 21 22:51 uwsgi_params
    -rw-r--r-- 1 root root 3610 Jan 21 22:51 win-utf
    [root@node01 nginx]# cd h5bp
    [root@node01 h5bp]# touch basic.conf
    [root@node01 h5bp]# mkdir cache
    [root@node01 h5bp]# cd cache
    [root@node01 cache]# touch expires.conf
    [root@node01 cache]# cd ..
    [root@node01 h5bp]# vi basic.conf
    [root@node01 h5bp]# cd ..
    [root@node01 nginx]# ll
    total 44
    drwxr-xr-x  2 root root 4096 Feb 25 12:24 conf.d
    -rw-r--r--  1 root root 1007 Jan 21 22:51 fastcgi_params
    drwxr-xr-x 11 root root 4096 Feb 25 15:46 h5bp
    -rw-r--r--  1 root root 2837 Jan 21 22:51 koi-utf
    -rw-r--r--  1 root root 2223 Jan 21 22:51 koi-win
    -rw-r--r--  1 root root 5231 Jan 21 22:51 mime.types
    lrwxrwxrwx  1 root root   29 Feb 25 12:24 modules -> ../../usr/lib64/nginx/modules
    -rw-r--r--  1 root root  643 Jan 21 22:48 nginx.conf
    -rw-r--r--  1 root root  636 Jan 21 22:51 scgi_params
    -rw-r--r--  1 root root  664 Jan 21 22:51 uwsgi_params
    -rw-r--r--  1 root root 3610 Jan 21 22:51 win-utf
    [root@node01 nginx]# vi nginx.conf

    h5bp/basic.conf

    include h5bp/cache/expires.conf;

    h5bp/cache/expires.conf

    location ~* .(?:manifest|appcache|html?|xml|json)$ {
      expires -1;
    }
    
    location ~* .(?:rss|atom)$ {
      expires 1h;
      add_header Cache-Control "public";
    }
    
    location ~* .(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
      expires 1M;
        access_log off;
              add_header Cache-Control "public";
    }
    
    location ~* .(?:css|js)$ {
      expires 1y;
        access_log off;
              add_header Cache-Control "public";
    }

    /etc/nginx/nginx.conf

    user  root; # 和你当前启动ngnix的用户一致
    worker_processes  1;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    
    events {
        use epoll;
        worker_connections  1024;
    }
    
    
    http {
        proxy_cache_path /root/nodejs keys_zone=one:10m max_size=10g inactive=60m;
        proxy_cache_key "$scheme$request_method$request_uri";
        upstream origin.163.com{
            server 127.0.0.1:9000;
        }
    
        server{
            listen 80;
            proxy_cache one;
            server_name yes.163.com;
            location /{
                add_header X-proxy-Cache $upstream_cache_status;
                include proxy_params;
                proxy_pass http://origin.163.com;
            }
        }
    
        server{
            listen 9000;
            root /root/nodejs/;
            index index.html index.html;
            charset utf-8;
            include h5bp/basic.conf;
    
            location / {
                try_files $uri $uri/ = 404;
            }
        }
    
    }

    起一个服务监听80端口,如果访问yes.163.com(server_name),会被proxy_pass转发到http://origin.163.com这个upstream,然后会将其负载到127.0.0.1:9000,9000端口是第二个server,引入basic.conf,进而引入expires.conf。

    [root@node01 nginx]# curl -I http://yes.163.com/public/9000.css
    HTTP/1.1 200 OK
    Server: nginx/1.17.8
    Date: Tue, 25 Feb 2020 09:01:03 GMT
    Content-Type: text/plain; charset=utf-8
    Content-Length: 0
    Connection: keep-alive
    Last-Modified: Tue, 25 Feb 2020 09:01:00 GMT
    ETag: "5e54e24c-0"
    Expires: Wed, 24 Feb 2021 09:01:03 GMT
    Cache-Control: max-age=31536000
    Cache-Control: public
    X-proxy-Cache: MISS
    Accept-Ranges: bytes
    
    [root@node01 nginx]# curl -I http://yes.163.com/public/9000.css
    HTTP/1.1 200 OK
    Server: nginx/1.17.8
    Date: Tue, 25 Feb 2020 09:01:06 GMT
    Content-Type: text/plain; charset=utf-8
    Content-Length: 0
    Connection: keep-alive
    Last-Modified: Tue, 25 Feb 2020 09:01:00 GMT
    ETag: "5e54e24c-0"
    Expires: Wed, 24 Feb 2021 09:01:03 GMT
    Cache-Control: max-age=31536000
    Cache-Control: public
    X-proxy-Cache: HIT
    Accept-Ranges: bytes
    
    [root@node01 nginx]# ll /root/nodejs
    total 8
    -rw------- 1 root root  708 Feb 25 17:01 6547b68e6c0c729fbfaefe613305c248
    drwxrwxrwx 2 root root 4096 Feb 25 17:01 public

    三、通过Lua扩展Nginx

    nginx模块需要用C开发,而且必须符合一系列复杂的规则,用C开发模块必须熟悉nginx的源代码,使得开发者望而生畏。

    ngx_lua模块通过将lua解释器集成进nginx,可以采用lua脚本实现业务逻辑。

    该模块具备以下特性:

    1.高并发、非阻塞的处理各种请求

    2.Lua内建协程,可以很好的将异步回调转换成顺序调用的形式

    3.每个协程都有一个独立的全局环境(变量空间),继承全局共享的、只读的comman data

    得益于Lua协程的支持,ngx_lua在处理10000个并发请求时只需要很少的内存,非常适合用于实现可扩展的、高并发的服务。

    协程(Coroutine)  进程是资源分配的基本单位,线程是资源调度的基本单位

    协程类似一种多线程,与多线程的区别有:

    1.协程并发os线程,所以创建、切换开销比线程相对要小。

    2.协程与线程一样有自己的栈、局部变量等,但是协程的栈是在用户进程空间模拟的,所以创建、切换开销很小。

    3.多线程程序是多个线程并发执行,也就是说在一瞬间有多个控制流在执行。而协程强调的是一种多个协程键协作的关系,只有当一个协程主动放弃执行权,另一个协程才能获得执行权,所以在某一瞬间,多个协程间只有一个在运行。

    4.由于多个协程只有一个在运行,所以对于临界区的访问不需要加锁,而多线程的情况则必须加锁。

    5.多线程程序由于有多个控制流,所以程序的行为不可控,而多个协程的执行是由开发者定义的所以是可控的。

    nginx的每个Worker进程都是在epoll或kqueue这样的事件模型上,封装成协程,每个请求都有一个协程进行处理。这正好与Lua内建协程的模型是一致的,所以即使ngx_lua需要执行Lua,相对C有一定的开销,但依然能保证高并发能力。

    Nginx进程模型

    nginx采用多进程模型,单Master-多Worker,Master进程主要用了管理Worker进程。

    Worker进程采用单线程、非阻塞的事件模型(Event Loop,事件循环)来实现端口的监听及客户端请求的处理和响应,同时Worker还要处理来自Master的信号。Worker进程个数一般设置为机器CPU核数。

    Master进程具体包括如下4个主要功能:

    (1)接收来自外界的信号

    (2)向各worker进程发送信号

    (3)监控worker进程的运行状态

    (4)当worker进程退出后(异常情况下),会自动重新启动新的worker进程

    HTTP请求处理

    ngx_lua指令

    属于nginx的一部分,它的执行指令都包含在nginx的11个步骤中,相应的处理阶段可以做插入式处理,即可插拔式架构,不过ngx_lua并不是所有阶段都会运行的;另外指令可以在http、server if、location、location if几个范围进行配置:

    OpenResty

    是一个基于nginx与Lua的高性能Web平台,其内部集成了大量精良的Lua库、第三方模块

    以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态Web应用、Web服务和动态网关。

    作原理:通过汇聚各种设计精良的nginx模块,从而将nginx有效地变成一个强大的通用Web应用平台。这样,Web开发人员和系统工程师可以使用Lua脚本语言调动nginx支持的各种C以及Lua模块,快速构造出足以胜任10K乃至1000K以上单机并发连接的高性能Web应用系统。

    目标:让你的Web服务直接跑在nginx服务内部,充分利用nginx的非阻塞I/O模型,不仅仅对HTTP客户端请求,甚至对于远程后端诸如MySQL、PostgreSQL、Memcached以及Redis等都进行一致的高性能响应。

    OpenResty是个package,打包了nginx和各种精良的库

    将简单的转发工作,扩充为可以编写动态脚本

    nginx转变为业务服务器,可以进行增删改查,可以进行业务处理

    ngx_lua实例

    四个例子

    helloworld

    content_by_lua:内容处理器,接收请求处理并输出响应

    该指令工作在nginx处理流程的content阶段,即内容生产阶段,是所有请求处理阶段中最为重要的阶段,因为这个阶段的指令通常是用来生成HTTP响应内容的

    输出:

    异步输出helloworld

    读取请求参数

    访问存储(redis)

    四、高性能nginx最佳实践

    nginx监听端口

    基本语法:listen address:port

    默认:listen 80

    作用:listen参数决定nginx服务器如何监听端口。在listen后可以加IP地址,端口和主机名,非常灵活。

    例如:

    listen 127.0.0.1:8000
    
    listen 127.0.0.1; //默认80端口
    
    listen 8000 ;// listen *:8000;// listen localhost:8000;
    user  nginx;
    worker_processes  auto;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    
    events {
        use epoll;
        worker_connections 65535;
    }
    
    
    http {
        server {
            listen 80;
            location /{
                default_type text/html;
                return 200 "Hello, Nginx! I am working on 80!
    ";
    
            }
     }
    
        server {
            listen 8080;
            location /{
                default_type text/html;
                return 200 "Hello, Nginx! I am working on 8080!
    ";
    
            }
        }
    
    
    }

    会启动两个server

    Nginx虚拟主机

    user  nginx;
    worker_processes  auto;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    
    events {
        use epoll;
        worker_connections 65535;
    }
    
    
    http {
        upstream origin.163.com {
            server 127.0.0.1:8080;
        }
        server {
            listen 80;
            server_name yes.163.com;
            location / {
               proxy_pass http://origin.163.com;
            }
        }
        server {
            listen 8080;
            location / {
                default_type text/html;
                return 200 "Hello, Nginx! I am working on 8080!
    ";
            }
        }
    }

    通过proxy_pass把请求转发给upstream,upstream会从列表里按策略(默认轮询)选一server,这里最终发到了8080端口,监听8080端口

    修改hosts

    127.0.0.1 yes.163.com

    结果

    [root@node02 nginx]# curl -i http://yes.163.com
    HTTP/1.1 200 OK
    Server: openresty/1.15.8.2
    Date: Thu, 24 Oct 2019 09:47:29 GMT
    Content-Type: text/html
    Content-Length: 36
    Connection: keep-alive
    
    Hello, Nginx! I am working on 8080!

    nginx配置location

    location用来指定请求是如何被处理的

    域名后面的一串成为uri,指定uri如何被处理,应该被哪个块接收和处理

    user  nginx;
    worker_processes  auto;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    
    events {
        use epoll;
        worker_connections 65535;
    }
    
    
    http {
        
        server {
            listen 80;
          
            location / {
                default_type text/html;
                return 200 "location /: I am default location!
    ";
            }
            
            location = /goodjob {
                default_type text/html;
                return 200 "location = /goodjob
    ";
            }
            
            location ~ /GoodJob {
                default_type text/html;
                return 200 "location ~ /GoodJob
    ";
            }
            
            location ~* /goodjob{
                default_type text/html;
                return 200 "location ~* /goodjob
    ";
            }

              location ^~ /goodjob{
                   default_type text/html;
                   return 200 "location ^~ /goodjob ";
               }

    
        }
    
    }

    结果

    [root@node02 nginx]# curl -i http://127.0.0.1/goodjob        完全匹配
    HTTP/1.1 200 OK
    Server: openresty/1.15.8.2
    Date: Thu, 24 Oct 2019 10:44:34 GMT
    Content-Type: text/html
    Content-Length: 20
    Connection: keep-alive
    
    location = /goodjob
    [root@node02 nginx]# curl -i http://127.0.0.1/GoodJob          大小写敏感
    HTTP/1.1 200 OK
    Server: openresty/1.15.8.2
    Date: Thu, 24 Oct 2019 10:44:38 GMT
    Content-Type: text/html
    Content-Length: 20
    Connection: keep-alive
    
    location ~ /GoodJob
    [root@node02 nginx]# curl -i http://127.0.0.1/Goodjob          大小写不敏感
    HTTP/1.1 200 OK
    Server: openresty/1.15.8.2
    Date: Thu, 24 Oct 2019 10:44:44 GMT
    Content-Type: text/html
    Content-Length: 21
    Connection: keep-alive

    [root@node02 nginx]# curl -i http://127.0.0.1/goodjob/hello     只要goodjob匹配就可以
    HTTP/1.1 200 OK
    Server: openresty/1.15.8.2
    Date: Thu, 24 Oct 2019 10:51:31 GMT
    Content-Type: text/html
    Content-Length: 21
    Connection: keep-alive

    location ^~ /goodjob

    注意:location是有顺序的,如果一个请求有可能被多个location匹配,实际上这个请求会被第一个location处理

    location / {}会处理所有的请求

    常规配置

    定义环境变量

    语法:evn VAR|VAR=VALUE

    作用:用户可以直接设置操作系统上的环境变量

    举例:evn TESTPATH=/tmp

    嵌入其他配置文件

    语法:include /path/file;

    作用:可以把其他配置文件引入进来,路径可以使用绝对路径也可以使用相对路径,还可以含有通配符*

    例如,下面的basic.conf

     引用了expires.conf

    pid文件

    语法:pid path/file;

    默认:pid logs/nginx.pid;

    作用:保存master进程ID的pid文件存放路径。

    nginx worker进程运行的用户和用户组

    语法:user username [groupname];

    默认:user nobody nobody;

    作用:master进程fork出的进程在哪个用户和用户组下。

    指定nginx worker进程可以打开的最大句柄描述符个数

    语法:worker_rlimit_nofile limit;

    作用:设置一个worker可以打开的最大句柄数。

    限制信号对列

    语法:worker_rlimit_sigpending limit;

    作用:设置每个用户发往nginx的信号对列的大小。也就是说,当某个用户的信号对列满了,这个用户再发送的信号量就会被丢掉。

    nginx高性能配置

    nginx worker进程个数

    语法:worker_processs number;

    默认:worker_processes 1;

    作用:在master_worker运行方式下,定义worker进程的个数。worker进程的数量会直接影响性能。每个worker都是单线程的进程,他会调用各个模块来实现各种功能。如果确定这些模块不会出现堵塞式调用,那么进程数可以和CPU核心数一样;反之,则稍少一些。

    绑定nginx worker进程到指定的CPU内核

    语法:worker_cpu_affinity cpumask [cpumask...]

    作用:假设每个worker都是很繁忙的,如果多个进程都在抢同一个CPU,那么就会出现同比问题。反之,如果每个worker进程独享一个CPU,就实现了完全的并发。

    举例:

    worker_processes 4;

    worker_cpu_affinity 1000 0100 0010 0001;

    user  nginx;
    worker_processes  auto;
    worker_cpu_affinity 1000 0100 0010;
    
    pid        /var/run/nginx.pid;
    
    
    events {
        use epoll;
        worker_connections 65535;
    }
    
    
    http {
        
        server {
            listen 80;
          
            location / {
                default_type text/html;
                return 200 "location /: I am default location!
    ";
            }
            
            location = /goodjob {
                default_type text/html;
                return 200 "location = /goodjob
    ";
            }
            
            location ~ /GoodJob {
                default_type text/html;
                return 200 "location ~ /GoodJob
    ";
            }
            
            location ~* /goodjob{
                default_type text/html;
                return 200 "location ~* /goodjob
    ";
            }
            
             location ^~ /goodjob{
                default_type text/html;
                return 200 "location ^~ /goodjob
    ";
            }
        }
    
    }

    SSL硬件加速

    语法:ssl_engine device;

    作用:如果服务器上有SSL硬件加速设备,那么就可以进行配置加快SSL协议的处理速度。用户可以用OpenSSL提供的命令来查看是否有SSL硬件加速设备:openssl engine -t

    nginx worker进程优先级设置

    语法:worker_priority nice;

    默认:worker_priority 0;

    作用:在Linux和Unix中,当许多进程都处于可执行状态时,按照优先级来决定内核选择哪一个进程执行。进程分配的CPU时间片大小也与优先级有关,优先级越高,时间片越长(如,在默认的情况下,最小时间片是5ms,最大则有800ms)。优先级由静态优先级和内核根据进程的执行情况所做的动态调整(目前只有+-5的调整)共同决定。nice是进程的优先级,它的取值范围是-20~+19,-20是最高级,+19是最低优先级。不建议把nice值设为比内核进程(t通常为-5)还要小

    nginx事件配置

    是否打开accept锁

    语法:accept_mutex [on|off];

    默认:accept_mutex on;

    作用:负载均衡锁,这把锁可以让多个worker进程轮流的,序列化的与新的客户端建立TCP连接。accept锁默认是打开的,如果关闭它,那么建立TCP连接的耗时会更短,但不利于负载均衡,因此不建议关闭。

     

    使用accept锁后到真正建立连接之间的延迟时间

    语法:accept_mutex_delay Nms;

    默认:accept_mutex_delay 500ms;

    作用:在使用accept锁后,同一时间只有一个worker进程能够取到accept锁。这个accept锁不是堵塞锁,如果取不到会立刻返回。如果只有一个worker进程试图取锁而没有取到,它至少要等待accept_mutex_delay定义的时间才能再次试图取锁。

    批量建立新连接

    语法:multi_accept [on|off];

    默认:multi_accept off;

    作用:当事件模型有新连接时,尽可能的对本次调度客户端发起的所有TCP请求都建立连接。

    选择事件模型

    语法:use [kqueue|rtsig|epoll|/dev/poll|select|eventport];

    默认:nginx会选出最合适的时间模型

    作用:对于Linux系统,可供选择的事件驱动模型有:poll,select,epoll三种,一般来说,epoll是性能最高的。

    每个worker的最大连接数

    语法:worker_connections number;

    作用:定义每个worker进程可以同时处理的最大连接数

    nginx事件模型

    配置实例

    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
    
        sendfile        on;
        
        keepalive_timeout  65;
        # 配置虚拟主机 192.168.75.145
        server {
        # 监听的ip和端口,配置 192.168.75.145:80
            listen       80;
        # 虚拟主机名称这里配置ip地址
            server_name  192.168.75.145;
        # 所有的请求都以/开始,所有的请求都可以匹配此 location
            location / {
            # 使用 root 指令指定虚拟主机目录即网页存放目录
            # 比如访问 http://ip/index.html 将找到 /usr/local/docker/nginx/html/html145/index.html
            # 比如访问 http://ip/item/index.html 将找到 /usr/local/docker/nginx/html/html145/item/index.html
    
                root   /usr/share/nginx/html145;
            # 指定欢迎页面,按从左到右顺序查找
                index  index.html index.htm;
            }
    
        }
        # 配置虚拟主机 192.168.75.245
        server {
            listen       80;
            server_name  192.168.75.245;
    
            location / {
                root   /usr/share/nginx/html245;
                index  index.html index.htm;
            }
        }
    }
  • 相关阅读:
    Java:多线程<一>
    Java:Exception
    Java: 内部类
    Ubuntu安装jdk
    ubuntu搜狗拼音安装
    录音-树莓派USB摄像头话筒
    leetcode 最小栈
    leetcode 编辑距离 动态规划
    leetcode 最小覆盖字串
    leetcode 最长上升子序列 动态规划
  • 原文地址:https://www.cnblogs.com/aidata/p/11734567.html
Copyright © 2020-2023  润新知