Nginx应该都不陌生,作为“上古时期”服务器四大件LNMP(Linux、Nginx、Mysql、PHP)之一,已经证明了它的强大之处,直到今天Nginx仍然有着相当强大的作用与价值。

那么Nginx能帮我们解决那些问题呢?

  • HTTP服务器:Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器。

  • 反向代理:反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端。

  • 负载均衡:负载均衡其意思就是分摊到多个操作单元上进行执行。

  • 动静分离:把动态请求和静态请求分离开,合适的服务器处理相应的请求,使整个服务器系统的性能、效率更高。

在大概了解作用之后我们正式开始学习(Nginx安装不讲,百度上有各种教程)

反向代理

原理

开始反向代理之前先来说一下什么是正向代理。由于谷歌已经退出中国市场,所以所有的访问谷歌服务器的请求均会被防火墙拦截下来

image-20210603155618227

像这样直接访问是拿不到响应的,这时候我们可以使用代理服务器。假设我们有一个代理服务器(proxy.com)做转发,将我们的所有请求以代理服务器发出,再将收到的响应返回用户,这便是正向代理

image-20210603160443212

其实这就是VPN的工作原理,理论上VPN代理可以获取我们发出去的所有请求,所以VPN不可以随便使用,那些免费的VPN风险系数相当大。

正向代理知道了,那什么是反向代理呢?

反向代理的过程用户是无感知的,它不像正向代理那样需要用户选择代理服务器,反向代理是服务方自己的代理,暴露出去的是代理服务器地址,从而隐藏了真实的服务器地址,此外可以用来解决跨域问题,反向代理的过程大致如下

image-20210603172629220

反向代理最常用的场景就是,你只有一个域名,指向一台主机,然后有两个服务跑在两个端口,我们都知道如果http地址不带端口号默认是80端口,要让这两个服务都跑在主域名下,不带端口号,此时就可以使用反向代理了,通过反向代理,将不同的二级域名映射到不同的端口号上

配置

准备工作

开始配置之前,我们要先准备一个运行的服务,简要的搭建一个node服务端程序,代码如下

image-20210604174514800

运行这个脚本

如果对nginx配置不熟悉可以看一下后面的配置介绍

反代一

然后我们开始配置反向代理,我们的程序跑在9000端口,我们要直接访问ip地址(默认80端口)

server {
    listen       80;
    server_name  127.0.0.1;

    location / {
        # root   html;
        # index  index.html index.htm;
        proxy_pass http://127.0.0.1:9000;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

效果如下

image-20210604175424249

反代二

在现在的开发中,后端一般都是使用微服务架构,不同的服务模块运行在不同的服务器(192.168.1.45、192.168.1.46)或者同一服务器的不同端口下(192.168.1.45:8080、192.168.1.45:8081),我们可以使用nginx反向代理来将不同的服务代理到统一域名的不同路径下(192.168.1.45/module1、192.168.1.45/module2)

我们需要将原来的node脚本复制一份,端口改为9001,然后运行起来。然后修改nginx.conf

server {
  listen 			80;
  serve_rname 127.0.0.1
  location ~ module1 {
    proxy_pass http://127.0.0.1:9000;
  }
  location ~ module2 {
    proxy_pass http://127.0.0.1:9001;
  }
}

location配置规则

location [ = | ~ | * | ^] uri {

}

  • =: 用于不含正则表达式的uri前,要求请求字符串与uri严格匹配,如果匹配成功,就停止继续向下搜索并立即处理该请求
  • ~: 用于表示uri包含正则表达式,并且区分大小写
  • ~*: 用于表示uri包含正则表达式,并且不区分大小写
  • ^~: 用于不含正则表达式的uri前,要求Nginx服务器找到标识uri和请求字符串匹配度最高的location后,立即使用此location处理请求,而不再使用location块中的正则uri和请求字符串做匹配
  • !: 对匹配结果取非
  • 注意: 如果uri包含正则表达式,则必须要有或者*标识。

此时我们分别访问module1和module2

image-20210604201304520

反代三

如果是不同的应用,但我们想用同一个域名,这时候就需要使用二级域名,然后通过反向代理来指向不同的应用

这里我们需要使用域名,所以在host文件中添加host,文件路径如下(需要管理员权限)

hosts

添加如下两条记录

127.0.0.1 www.proxy.com
127.0.0.1 test.proxy.com

然后修改我们的nginx配置文件,依旧是指向我们之前的两个node服务,区别于的第二个案例的是这里要添加的是两个server,通过server_name来区分虚拟主机

server {
    listen       80;
    server_name  www.proxy.com;
    location / {
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:9000;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}
server {
  listen 				80;
  server_name   test.proxy.com;
  location / {
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:9001;
  }
}

效果如下

image-20210604202420052

负载均衡

原理

在没有配置负载均衡时我们的服务器网络架构是这样的

image-20210603194420298

非常简单,就是接受用户请求然后处理返回,但是当用户量上去之后,一台服务器无法处理大量的请求,这时我们我们想让多台服务器来共同处理,这时就需要负载均衡,通过Nginx服务器分发到不同的服务器上,可以根据不同的服务器性能等依据来划分服务器处理的请求数量。

使用负载均衡后,我们的网络架构如下

image-20210603194827721

使用负载均衡时,一般会使用到反向代理

思考题:使用负载均衡后,怎么保持数据库的一致性?

配置

这里依旧是使用前面反向代理的两个node程序,分别运行在9000和9001端口

在配置负载均衡时需要在http下,server同层级使用upstream配置一个服务器列表然后命名,然后在location中添加反向代理的配置http://服务器列表名

upstream module {
  server 127.0.0.1:9000;
  server 127.0.0.1:9001;
}

server {
    listen       80;
    server_name  127.0.0.1;

    location / {
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://module;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

重新应用配置之后去浏览器访问,可以看见服务器控制台日志如下

image-20210604215829421

请求被平均分配到了两台服务器上,这其实是nginx负载均衡的默认策略——轮询,除此之外Nginx还有其他的负载均衡策略

  • 轮询:默认,将请求按照请求时间平均分配到列表中的服务器上
  • 权重:使用weight声明权重,权重和访问率成正比,使用权重来解决服务器之间性能不同的差异
  • ip_hash:每个请求按访问ip的hash结果分配, 这样每个访客固定访问一个后端服务器,可以解诀session的问题
  • fair:(需引入第三方插件)按后端服务器的响应时间来分配请求,响应时间短的优先分配

四种策略的声明模式如下

# 轮询
upstream module {
  server 127.0.0.1:9000;
  server 127.0.0.1:9001;
}
# 权重
upstream module {
  server 127.0.0.1:9000 weight=2;
  server 127.0.0.1:9001 weight=1;
}
# ip_hash
upstream module {
  ip_hash;
  server 127.0.0.1:9000;
  server 127.0.0.1:9001;
}
# fair
upstream module {
  fair;
  server 127.0.0.1:9000;
  server 127.0.0.1:9001;
}

动静分离

原理

为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速
度。降低原来单个服务器的压力。过程如下

image-20210603220952303

配置

这里动静分离并不是简单地动态页面和静态页面的分离,而是动态请求和静态请求的分离。这里我们需要重新做一下准备,准备一个文件夹www用于存放静态资源,然后我们所有的请求进行分类,静态资源访问/asserts/xxx,动态请求走/api/xxx

location /api {
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:9000;
}
location /images/ {
  root /Nginx/www/; # Window下要用绝对路径
  autoindex on;
}

效果如下

image-20210605084406337

注意:这里在配置location中的root时Windows要设置绝对路径,不然会404;在访问文件时查找路径为root+location+文件名,如果不使用此种模式可以设置alias来替换root,在访问文件时就是alias+文件名

配置解析

Nginx的配置文件一共有三个大块

  • 全局块:设置一些运行指令,例如worker_processes用来设置支持的并发数量
  • events块:影响Nginx服务器与用户的网络连接,例如worker_connections用来设置最大连接数
  • http(s)块:Nginx配置中最常用的块
    • http全局块:包括文件引入、日志自定义、超时时间等等
    • http server块:和虚拟主机有密切关系,一个server块就相当于一个虚拟主机。我们的配置工作主要集中在server块中

image-20210604160804717

server详解

我们只对最常使用的server块配置项进行介绍,其他部分如有需要可以面向百度/Google

  • listen:监听的端口

  • server_name:主机名,一般是二级域名

  • location:路径中包含某个设定值就做相应的操作

    • proxy_pass:设置被代理服务器的端口或套接字,以及URL

    • 将代理服务器收到的用户的信息传到真实服务器上

      • proxy_set_header Host $host;
      • proxy_set_header X-Real-IP $remote_addr;
      • proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    • # 查看nginx状态
      location /NginxStatus {
        stub_status on;
        access_log on;
        auth_basic "NginxStatus";
        auth_basic_user_file conf/htpasswd; # 需要使用htpasswd生成密码文件
      }
      
    • deny all;禁止访问匹配中的location

返回反代配置


前端小白