Nginx

一 为什么要用Nginx?

我们之前有分析过,单台服务器可能会遇到的问题,比如服务器宕机,或者并发用户太多,单台服务器不够等问题,所以需要集群架构,就是将项目部署到多台服务器。

Nginx学习-小白菜博客

但这样会出现新的问题:

  1. 用户发送的请求会被发送到哪台服务器?
  2. 如果是有软件帮助分发,怎么做到尽量均衡?

对于这些问题的出现,我们可以用Nginx来解决,除此以外,Nginx还可以帮助我们区分动态服务器和静态服务器。

Nginx学习-小白菜博客

二 Nginx是什么?

Nginx (engine x) 是一个高性能的Http服务器和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。它可以用做反向代理服务器,邮件服务器,实现负载均衡和动静分离。

稳定性强、丰富的功能集、简单的配置文件和低系统资源的消耗,占用内存少,并发能力强。

中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

三 Nginx安装和配置

1.使用docker安装Nginx

 docker pull daocloud.io/library/nginx:latest
Nginx学习-小白菜博客
 docker images
Nginx学习-小白菜博客
docker run -d -p 80:80 --name nginx 29
Nginx学习-小白菜博客

2.Nginx核心配置文件

2.1 找到Nginx内部的配置文件

先进入Nginx容器内部

docker exec -it 容器id bash   #进入容器的终端,可以执行一些如ls pwd等一些简单的shell命令
Nginx学习-小白菜博客

再进入容器的etc/nginx目录下:

Nginx学习-小白菜博客

将nginx.conf文件的内容复制出来

Nginx学习-小白菜博客

2.2 nginx.conf文件结构


# 全局块
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


#events块
events {
    worker_connections  1024;
}



http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    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;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

全局块:

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

worker_processes  1   #这是 Nginx 服务器并发处理服务的关键配置,worker_processes 值越大,可以支持的并发处理量也越多,但是会受到硬件、软件等设备的制约。

events 块:

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

http块:

http模块顾名思义,就是关于http服务请求的配置。这些配置包括http请求的文件类型(MIME-TYPE)的定义,http请求日志的输出,http连接的超时时长,单连接请求上限的配置。

http块的最后一句#include /etc/nginx/conf.d/*.conf ,是指引入了conf.d目录下的以.conf为结尾的配置文件。我们找到他们。

Nginx学习-小白菜博客

default.conf内容如下:

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

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

    location / {
        root   /usr/share/nginx/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   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.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;
    #}
}

去掉注释部分

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

 
}

将其替换到nginx.conf文件中的include /etc/nginx/conf.d/*.conf,然后可以看到http块的内容为:

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    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;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

 
   }
}

http块结构包含:

​ server块: 每一个Server模块就是一个独立的虚拟主机,每个虚拟的主机可配置不同的域名或IP地址

​ listen:代表nginx监听的端口号

​ Location模块:每一台虚拟主机下可能因请求URI的不同而进行不同的响应,所以对这些不同的请求进行 分组,每一个组可以称为一个location

​ root:将接收到的请求根据/usr/share/nginx/html去查找静态资源

​ index:默认去上述root里的路径中找到index.html或者index.htm文件

3.使用docker-compose安装nginx,并配置数据卷

根据上一节的分析,我们知道未来我们需要在nginx容器内部创建不同的的conf文件用来配置nginx,那么可以通过配置数据卷的方式将创建的conf文件放在容器外部。

创建docker-compose.yml文件

version: '3.0'
services:
  nginx:
    restart: always
    image: daocloud.io/library/nginx:latest
    container_name: nginx
    ports:
      - 80:80
    volumes:
      - /wang/docker_nginx/conf.d/:/etc/nginx/conf.d

运行docker-compose.yml文件

docker-compose up -d
Nginx学习-小白菜博客

在数据卷中手动创建conf配置文件

cd  /wang/docker_nginx/conf.d

vi default.conf

在default.conf文件中输入

 server {
        listen 80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
   }

保存退出

重启docker-compose

docker-compose restart

运行:

Nginx学习-小白菜博客

四 Nginx常用功能

1.Nginx反向代理

1.1 什么是代理

代理其实就是一个中介,A和B本来可以直连,中间插入一个C,C就是中介。
刚开始的时候,代理多数是帮助内网client访问外网server用的。

1.2 正向代理

正向代理隐藏了用户,用户的请求被代理服务器接收代替,到了服务器,服务器并不知道用户是谁。

比如我们国内访问谷歌,直接访问访问不到,我们可以通过一个正向代理服务器,请求发到代理服,代理服务器能够访问谷歌,这样由代理去谷歌取到返回数据,再返回给我们,这样我们就能访问谷歌了。

正向代理的用途:

(1)访问原来无法访问的资源,如google

​ (2) 可以做缓存,加速访问资源

(3)对客户端访问授权,上网进行认证

(4)代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息

Nginx学习-小白菜博客

1.3 反向代理

反向代理(Reverse Proxy)是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

用户发送请求到服务器,访问的其实是反向代理服务器,用户不知道最终访问的是哪台服务器。

反向代理的作用:

(1)保证内网的安全,阻止web攻击,大型网站,通常将反向代理作为公网访问地址,Web服务器是内网

(2)反向代理服务器是配置在服务端的,客户端不知道访问的到底是哪一台服务器

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

Nginx学习-小白菜博客

1.4 Nginx怎么实现反向代理

1.启动2台tomcat服务器和1个nginx服务器

docker-compose.yml

version: '3.0'
services: 
  tomcat_01:
    restart: always
    image: daocloud.io/library/tomcat:8.5.16-jre8
    container_name: tomcat_01
    ports:
      - 8085:8080
    environment:
      TZ: Asia/Shanghai
    volumes:
      - /wang/data/tomcat_01_webapps:/usr/local/tomcat/webapps
      - /wang/data/tomcat_01_logs:/usr/local/tomcat/logs
  tomcat_02:
    restart: always
    image: daocloud.io/library/tomcat:8.5.16-jre8
    container_name: tomcat_02
    ports:
      - 8086:8080
    environment:
      TZ: Asia/Shanghai
    volumes:
      - /wang/data/tomcat_02_webapps:/usr/local/tomcat/webapps
      - /wang/data/tomcat_02_logs:/usr/local/tomcat/logs  

在两台服务器根目录下分别创建一个index.html页面,用作测试页面。

Nginx学习-小白菜博客

测试一下:

Nginx学习-小白菜博客
Nginx学习-小白菜博客

启动一个nginx服务器,上一章已启动过

2.修改default.conf文件,配置反向代理

找到nginx数据卷目录中创建的default.conf文件

Nginx学习-小白菜博客

输入命令 vi default.conf 进入编辑状态

修改内容如下:

server {
        listen   80;
        server_name  localhost;

        
        #使用nginx实现反向代理   当访问 http://42.192.12.30/ 时会转到http://42.192.12.30:8085/下
        
        location /{
                proxy_pass http://42.192.12.30:8085/;
        }

}


运行结果:

Nginx学习-小白菜博客

在tomcat_02服务器上部署swagger项目后

继续修改default.conf文件

server {
        listen   80;
        server_name  localhost;

        #使用nginx实现反向代理   当访问 http://42.192.12.30/swagger 时会转到http://42.192.12.30:8086/swagger下
        
        location /swagger{
                proxy_pass http://42.192.12.30:8086;
        }
        
        #使用nginx实现反向代理   当访问 http://42.192.12.30/ 时会转到http://42.192.12.30:8085/下
        
        location /{
                proxy_pass http://42.192.12.30:8085/;
        }

}
Nginx学习-小白菜博客

我们输入的网址叫做请求URI,nginx用请求URI与location中配置的URI做匹配。

比如我们请求的URI是:http://42.192.12.30/swagger/swagger-ui.html

根据配置文件,当请求主机是http://42.192.12.30 代表进入了Nginx,当路径中有/swagger代表进入了location /swagger,也就是会访问http://42.192.12.30:8086,后面加上相对路径swagger/swagger-ui.html

1.5 nginx中的location指令

location是Nginx中的块级指令(block directive),,location指令的功能是用来匹配不同的url请求,进而对请求做不同的处理和响应。

1.语法规则
Nginx学习-小白菜博客
2.优先级
  • 首先精确匹配 =
  • 其次前缀匹配 ^~
  • 其次是按文件中顺序的正则匹配
  • 然后匹配不带任何修饰的前缀匹配
  • 最后是交给 / 通用匹配
  • 当有匹配成功时候,停止匹配,按当前匹配规则处理请求

匹配的时候依照最佳匹配规则,按照能匹配到的最多的规则进行匹配。
如 location ^~ /user/add/ 和 location ^~ /user/,请求 http://localhost/user/add/1.html,会匹配location ^~ /user/add/

3.绝对路径和相对路径

绝对路径

location /reg{
    proxy_pass http://42.192.12.30:8085/;
}

当访问 http://127.0.0.1/reg 时,nginx匹配到/reg路径,把请求转发给42.192.12.30:8085服务,实际请求路径为
http://42.192.12.30:8085,nginx会去掉匹配的“/reg”。

相对路径

location /reg {
    proxy_pass  http://42.192.12.30:8085;
}

当访问http://127.0.0.1/reg 时,nginx匹配到/reg路径,把请求转发给42.192.12.30:8085服务,实际请求代理服务器的路径为
http://42.192.12.30:8085/reg, 此时nginx会把匹配的“/reg”也代理给代理服务器。

3.示例
location = /  {#规则A}

location = /login {#规则B}

location ^~ /static/ {#规则C   匹配任何以 /static/ 开头的查询并且停止搜索。任何正则表达式将不会被测试}

location ~ \.(gif|jpg|png|js|css)$ {#规则D}

location ~* \.png$ {#规则E}

location !~ \.js$ {#规则F}

location !~* \.js$ {#规则G}

location / {#规则H}


访问根目录/, 比如http://localhost/ 将匹配规则A

访问 http://localhost/login 将匹配规则 B,http://localhost/register 则匹配规则H

访问 http://localhost/static/a.html 将匹配规则C

访问 http://localhost/b.png 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用

访问 http://localhost/static/c.png  将匹配规则C,D和规则E,但优先匹配到规则C

访问 http://localhost/a.PNG 则匹配规则E, 而不会匹配规则D,因为规则E不区分大小写。

访问 http://localhost/index.js 不会匹配规则F和规则G

访问 http://localhost/index.JS 不会匹配规则G,因为不区分大小写。

规则F,规则G属于排除法,符合匹配规则但是不会匹配到。

访问 http://localhost/goods/id/1 则最终匹配到规则H,因为以上规则都不匹配。

2 Nginx负载均衡

Nginx学习-小白菜博客

Nginx实现负载均衡的策略包含自带的三种策略和第三方提供的插件方式。

自带的三种策略为:

2.1、轮询方式(默认)

每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

修改default.conf文件

upstream server-list{
    server 42.192.12.30:8085;
    server 42.192.12.30:8086;
}
server {
        listen   80;
        server_name  localhost;

    
        location /{
                proxy_pass http://server-list/;
        }

}

upstream模块里面包含了一组upstream服务器,upstream服务器是指上游服务器,也就是nginx所代理的后端服务器。这些服务器可能被赋予了不同的权重、不同的类型甚至可以基于维护等原因被标记为down。

重启nginx服务器测试

​ 结果如下:两个服务器交换。

Nginx学习-小白菜博客

Nginx学习-小白菜博客

2.2、指定权重

指定轮询几率,weight和访问比率成正比,也就是权重越高,被分配的几率越大,用于后端服务器性能不均的情况。

修改default.conf文件

upstream server-list{
    server 42.192.12.30:8085 weight=6;
    server 42.192.12.30:8086 weight=2;
}
server {
        listen   80;
        server_name  localhost;

    
        location /{
                proxy_pass http://server-list/;
        }

}

2.3、IP绑定 ip_hash

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session共享的问题。

修改default.conf文件

upstream server-list{
    ip_hash;
    server 42.192.12.30:8085 weight=6;
    server 42.192.12.30:8086 weight=2;
}
server {
        listen   80;
        server_name  localhost;

    
        location /{
                proxy_pass http://server-list/;
        }

}

相同ip 进入的是同一台服务器。

3 Nginx动静分离

之前我们讲过动静分离结构,就是将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开。那么部署的时候呢?

部署的时候也应该分开部署,这样可以提高用户访问静态代码的速度,降低对后台应用访问。

比如我们可以将静态资源放到nginx中,动态资源转发到tomcat服务器中。

修改docker-compose.yml文件

添加静态文件数据卷:

version: '3.0'
services:
  nginx:
    restart: always
    image: daocloud.io/library/nginx:latest
    container_name: nginx
    ports:
      - 80:80
    volumes:
      - /wang/docker_nginx/conf.d/:/etc/nginx/conf.d
      - /wang/docker_nginx/static/:/static     #设置nginx根目录下的static文件夹对应到/wang/docker_nginx/static目录

修改conf.d目录下的default.conf文件:

配置静态资源路径

upstream server-list{
    ip_hash;
    server 42.192.12.30:8085 weight=6;
    server 42.192.12.30:8086 weight=2;
}
server {
        listen   80;
        server_name  localhost;
        
        location /html{
                root /static;  # 根目录下的static对应的是/wang/docker_nginx/static
                index index.html index.htm;
        }
        
        location /js{
                root /static;  # 根目录下的static对应的是/wang/docker_nginx/static
                autoindex on;
        } 
        location /{
                proxy_pass http://server-list/;
        }

}

测试:

docker-compose down

docker-compose up -d

Nginx学习-小白菜博客