一、Nginx简介

1.简介

Nginx 是高性能的 HTTP 和反向代理的服务器,处理高并发能力是十分强大的,能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数。

Nginx三大功能:

  • 反向代理:暴露的是代理服务器地址,隐藏了真实服务器 IP 地址。

image.png

  • 负载均衡:增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中到单个服务器上的情况改为将请求分发到多个服务器上,将负载分发到不同的服务器,也就是我们所说的负载均衡

image.png

  • 动静分离:动静分离将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问。将静态资源放到nginx中,动态资源转发到tomcat服务器中

image.png

2.安装及运行

首先从阿里云镜像仓库拉取我们需要的nginx镜像

  1. docker pull nginx

为了便于我们在后期容器外部宿主机对docker的配置文件进行修改,因此我们需要将nginx的相关配置文件以数据卷的形式挂载在宿主机上,首先我们以交互的方式随便进入一个nginx容器中获取相关配置文件的路径以及内容

docker run -it nginx /bin/bash

进入容器以后分别在以下路径寻找相关文件

  • 配置文件路径 /etc/nginx/nginx.conf
  • 默认配置文件路径/etc/nginx/conf.d/default.conf
  • 默认首页文件夹/usr/share/nginx/html
  • 日志文件路径/var/log/nginx

随后以上容器可以将其删除,我们在本地建一个存储nginx相关文件的文件夹

mkdir -p /data/nginx/{conf,conf.d,html,logs}

在conf中挂载配置文件数据卷,conf.d中挂载默认配置文件数据卷,html和logs亦然

同时将上一步查找到的nginx.conf和default.conf文件内容拷贝到本地数据卷中

然后运行一个新的容器,并将数据卷映射关系填好。

docker run --name mynewnginx -d -p 80:80 -v/data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v /data/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf -v /data/nginx/logs:/var/log/nginx nginx

这是通过宿主机80端口就可以访问得到nginx服务器首页了

image.png

3.配置文件

#这个值越大,可以支持的并发处理量也越多,会受到硬件、软件等设备的制约
worker_processes  1;
events {
    worker_connections 1024;
}
http{
    include mime.types;
    default_type application/octer-stream;

    sendfile  on;
    keepalive_timeout  65;
    server{
        listen  80;
        server_name  localhost;

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

根据上述文件,我们可以很明显的将nginx.conf配置文件分为三部分

第一部分:全局块

从配置文件开始到events块之间的内容,主要会设置一些影响nginx服务器整体运行的配置指令,主要包括配置运行Nginx服务器的用户(组)、允许生成的worker process数、进程PID存放路径、日志存放路径和类型以及配置文件的引入等。

第二部分:events块

events {
    worker_connections 1024;
}

events块涉及的指令主要影响Nginx服务器与用户的网络连接,常见的设置包括是否开启对多work process下的网络连接进行序列化,是否允许同时接收对个网络连接,选取哪种事件驱动模型来处理连接请求,每个wordprocess可以同时支持的最大连接数等。上述例子中就表示每个workprocess支持的最大连接数为1024,这部分的配置对Nginx的性能影响较大,在实际中应该灵活配置

第三部分:http块

这算是 Nginx 服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。需要注意的是:http 块也可以包括 http全局块、server 块。

  • http全局块

http全局块配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。

  • server 块

这块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的,该技术的产生是为了 节省互联网服务器硬件成本。


每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机。 而每个 server 块也分为全局 server 块,以及可以同时包含多个 locaton 块。
1、全局 server 块
最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或IP配置。
2、location 块
一个 server 块可以配置多个 location 块。
这块的主要作用是基于 Nginx 服务器接收到的请求字符串(例如 server_name/uri-string),对虚拟主机名称 (也可以是IP 别名)之外的字符串(例如 前面的 /uri-string)进行匹配,对特定的请求进行处理。地址定向、数据缓 存和应答控制等功能,还有许多第三方模块的配置也在这里进行。

二、三大功能

1.反向代理

1.反向代理方式一

1.实现效果

打开浏览器,在浏览器地址栏输入地址www.123.com,跳转到 liunx系统 tomcat 主页面中

2.准备工作

在本地机C:\Windows\System32\drivers\etc目录下修改hosts文件,添加本地linux域名映射,192.168.19.128就是我们的linux服务器的IP地址

192.168.19.128   123.com

通过docker启动tomcat,使用默认端口8080

docker run  -d -p 8080:8080 tomcat:8.5.31

image.png

修改本地/data/nginx/conf.d/defalut.conf

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
    proxy_pass  http://172.17.0.1:8080;
    proxy_redirect   default;
    }
}

在docker中访问宿主的地址即为172.17.0.1

image.png

当我们在浏览器输入123.com时,本地ENS解析域名为192.168.19.128地址,随后我们访问该地址80端口,又由于我们的80端口与nginx容器80端口建立了映射关系,所以这个请求直接发到了nginx服务器的80端口,在以上配置文件中,我们设置了nginx监听80端口,并将这个端口收到得请求全部转发到宿主机的8080端口,而宿主机的8080端口又与tomcat容器的8080端口建立了映射,所以这个请求最终由tomcat收到。

image.png

注意:当防火墙开启时,nginx的转发请求会被宿主机拒绝,因此我们需要关闭宿主机的防火墙

systemctl status firewalld  #查看防火墙状态
systemctl stop firewalld    #暂时关闭,服务器重启时又会打开
systemctl disable firewalld #永久关闭

2.反向代理方式二

1.实现效果

使用 nginx反向代理,根据访问的路径跳转到不同端口的服务中nginx 监听端口为9001,

访问 http://123.com/dev/ 直接跳转到 127.0.0.1:8080

访问 http:// 123.com/vod/ 直接跳转到 127.0.0.1:8081

2.准备工作

创建一台端口为8081的tomcat容器实例,并添加数据卷映射关系

docker run -d -p 8081:8080 -v /data/tomcat/tomcat1:/usr/local/tomcat/webapps/vod tomcat:8.5.31

创建一台端口为8080的tomcat容器实例,并添加数据卷映射关系

docker run -d -p 8080:8080 -v /data/tomcat/tomcat2:/usr/local/tomcat/webapps/dev tomcat:8.5.31

分别在tomcat1、tomcat2文件夹下建两个html文件,以便后期容易看出反向代理的效果

在nginx的default.conf中添加如下内容

server {
    listen       80;
    server_name  localhost;
    location ~/dev/ {
        proxy_pass  http://172.17.0.1:8080;
        proxy_redirect   default;
    }
    location ~/vod/ {
        proxy_pass  http://172.17.0.1:8081;
        proxy_redirect   default;
    }
}

image.png

image.png

2.负载均衡

1.实现效果

浏览器地址栏输入地址 http://123.com/dev/a.html,负载均衡效果,访问平均打到8080和 8081端口中

2.准备工作

  1. 准备两台tomcat容器,一台8080端口,一台8081端口
  2. 在两台 tomcat 里面 webapps 目录中,创建名称是dev文件夹,在dev文件夹中创建页面 a.html,用于测试
  3. 将原本在反向代理中添加的/dev/映射删掉
docker run -d -p 8080:8080 -v /data/tomcat/tomcat1:/usr/local/tomcat/webapps/dev tomcat:8.5.31 
docker run -d -p 8081:8080 -v /data/tomcat/tomcat2:/usr/local/tomcat/webapps/dev tomcat:8.5.31
location /{
        proxy_pass http://myserver;
    }
#以下这个放在server{}外边,http{}里边
    upstream myserver{
        server 192.168.19.128:8080;
        server 192.168.19.128:8081;
    }

配置完成之后在浏览器输入123.com/dev/a.html,即可看到负载均衡效果

Nginx 提供了几种分配方式(策略):

  1. 轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。
  2. weight: weight 代表权,重默认为 1,权重越高被分配的客户端越多。指定轮询几率,weight 和访问比率成正比,用于后端服务器性能不均的情况。 例如:

    upstream server_pool{
    server 192.168.5.21 weight=10;
    server 192.168.5.22 weight=10;
    }
    
  3. ip_hash :每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 的问题。 例如:

    upstream server_pool{
    ip_hash;
    server 192.168.5.21:80;
    server 192.168.5.22:80;
    }
    
  4. fair(第三方):按后端服务器的响应时间来分配请求,响应时间短的优先分配。

    upstream server_pool{
    server 192.168.5.21:80;
    server 192.168.5.22:80;
    fair;
    }
    

3.动静分离

Nginx 动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和 静态页面物理分离。严格意义上说应该是动态请求跟静态请求分开,可以理解成使用 Nginx 处理静态页面,Tomcat 处理动态页面。动静分离从目前实现角度来讲大致分为两种:

  • 把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案
  • 是动态跟静态文件混合在一起发布,通过 nginx 来分开

通过 location 指定不同的后缀名实现不同的请求转发。通过 expires 参数设置,可以使浏览器缓存过期时间,减少与服务器之前的请求和流量。具体 Expires 定义:是给一个资 源设定一个过期时间,也就是说无需去服务端验证,直接通过浏览器自身确认是否过期即可, 所以不会产生额外的流量。此种方法非常适合不经常变动的资源。(如果经常更新的文件, 不建议使用 Expires 来缓存),我这里设置3d,表示在这 3 天之内访问这个 URL,发送 一个请求,比对服务器该文件最后更新时间没有变化,则不会从服务器抓取,返回状态码 304,如果有修改,则直接从服务器重新下载,返回状态码 200。

在nginx配置文件中添加如下:

   location ~* \.(jsp|png|css)$ {
        proxy_pass http://172.17.0.1:8080;     #jsp|png|css等文件转发给8080端口的tomcat处理
    }

三、原理

image.png

image.png

master-workers 的机制的好处

    首先,对于每个 worker 进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销, 同时在编程以及问题查找时,也会方便很多。其次,采用独立的进程,可以让互相之间不会 影响,一个进程退出后,其它进程还在工作,服务不会中断,master 进程则很快启动新的 worker 进程。当然,worker 进程的异常退出,肯定是程序有 bug 了,异常退出,会导致当 前 worker 上的所有请求失败,不过不会影响到所有请求,所以降低了风险。

需要设置多少个 worker

Nginx 同 redis 类似都采用了 io 多路复用机制,每个 worker 都是一个独立的进程,但每个进 程里只有一个主线程,通过异步非阻塞的方式来处理请求, 即使是千上万个请求也不在话 下。每个 worker 的线程可以把一个 cpu 的性能发挥到极致。所以 worker 数和服务器的 cpu 数相等是最为适宜的。设少了会浪费 cpu,设多了会造成 cpu 频繁切换上下文带来的损耗。

设置 worker 数量

worker_processes 4 
#work 绑定 cpu(4 work 绑定 4cpu)
worker_cpu_affinity 0001 0010 0100 1000 

#work 绑定 cpu (4 work 绑定 8cpu 中的 4 个) 。 
worker_cpu_affinity 0000001 00000010 00000100 00001000

连接数 worker_connection

这个值是表示每个 worker 进程所能建立连接的最大值,所以,一个 nginx 能建立的最大连接 数,应该是 workerconnections workerprocesses。当然,这里说的是最大连接数,对于 HTTP 请 求 本 地 资 源 来 说 , 能 够 支 持 的 最 大 并 发 数 量 是 worker_connections workerprocesses,如果是支持 http1.1 的浏览器每次访问要占两个连接,所以普通的静态访 问最大并发数是: worker_connections workerprocesses /2,而如果是 HTTP 作 为反向代 理来说,最大并发数量应该是 worker_connections worker_processes/4。因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服 务的连接,会占用两个连接。

image.png

附录-配置汇总

复制代码
user  nobody;         主模块命令, 指定Nginx的worker进程运行用户以及用户组,默认由nobody账号运行。                                
worker_processes  1;   指定Nginx要开启的进程数,一般设置为CPU数*核数。
//error log:用来定义全局错设日志文件的路径和日志名称。
        日志输出级别有debug,info,notice,warn,error,crit 可供选择,
        其中debug输出日志最为详细,crit输出日志最少。
#error_log  logs/error.log; 
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;  用来指定进程id的存储文件位置。

//event:设定nginx的工作模式及连接数上限,其中参数use用来指定nginx的工作模式(
      这里是epoll,epoll是多路复用IO(I/O Multiplexing)中的一种方式),
     nginx支持的工作模式有select ,poll,kqueue,epoll,rtsig,/dev/poll。
     其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,
      对于linux系统,epoll是首选。
events {
    use epoll;
    worker_connections  1024;设置nginx每个进程最大的连接数,默认是1024,所以nginx最大的连接数
                  max_client=worker_processes * worker_connections。
                  进程最大连接数受到系统最大打开文件数的限制,需要设置ulimit。
}

//以上这块配置代码是对nginx全局属性的配置。


#下面部分是nginx对http服务器相关属性的设置
http {
    include       mime.types;               主模块命令,对配置文件所包含文件的设定,减少主配置文件的复杂度,相当于把部分设置放在别的地方,然后在包含进来,保持主配置文件的简洁
    default_type  application/octet-stream; 默认文件类型,当文件类型未定义时候就使用这类设置的。 

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '   指定nginx日志的格式
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;   开启高效文件传输模式(zero copy 方式),避免内核缓冲区数据和用户缓冲区数据之间的拷贝。
    #tcp_nopush     on;

    #keepalive_timeout  0;   客户端连接超时时间
    keepalive_timeout  65;

    #gzip  on;             设置是否开启gzip模块

    #server段是虚拟主机的配置 这里可以写在别的文件中 然后在包含进来,比如写在/usr/local/nginx/vhost/xxx.conf 目录某文件中 然后在包含进来,可以包含多个文件 include /usr/local/nginx/vhost/*;
    server {
        listen       80;   虚拟主机的监听服务端口
        server_name  localhost;   用来指定ip或者域名,多个域名用逗号分开

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {                       地址匹配设置,支持正则匹配,也支持条件匹配,这里是默认请求地址,用户可以location命令对nginx进行动态和静态网页过滤处理
            root   html;                   虚拟主机的网页根目录
            index  index.html index.htm;   默认访问首页文件
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        location ~ \.php$ {   将以php为后缀的文件转发到 FastCGI处理. 使用FastCGI默认配置。本地8088端口处理
            fastcgi_pass   http://127.0.0.1:8088;
              fastcgi_index index.php;
              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
              include fastcgi_params;

        }
        #静态文件,nginx自己处理
        location ~ ^/(images|javascript|js|css|flash|media|static)/ {
             root /var/www/public/images;       
             expires 30d;  #缓存时间30天,静态文件更新不多,过期时间可以设大一点。
        }
       #配置Nginx状态的地址
        location /NginxStatus {
          stub_status            on;
          access_log              on;
          auth_basic              "NginxStatus";
          auth_basic_user_file  conf/htpasswd;
        }

       #配置nginx负载均衡的服务器列表
       upstream mysvr {
          #weigth参数表示权值,权值越高被分配到的几率越大
          #本机上的Squid开启3128端口
          server 192.168.199.1:88 weight=5;
          server 192.168.199.1:80   weight=1;

        }


        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {              
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

    #端口转发 

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

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


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.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;
    #    }
    #}

}