【05】nginx:TCP / 正向 / 反向代理 / 负载均衡

写在前面的话

在我们日常的工作中,不可能所有的服务都是简单的 HTML 静态网页,nginx 作为轻量级的 WEB 服务器,其实我们将它用于更多的地方还是作为我们网站的入口。不管你是后端接口,还是前端页面,我们让用户的请求都到这个服务。原因大致有以下几个:

1. 集中管理更便于管理。

2. 对外服务都是需要公网 IP 的,需要带宽,如果每台机器都专门配置公网 IP 和带宽,实在是太浪费,可以看看最近我整理的几个云服务商带宽收费情况:

带宽越高,费用越高,这种高还不是成几何式增长。

3. 我们的服务一般不会是单点服务,那么前后端如果需要通信,怎么配置地址,每个都配置?会不会太麻烦了点。

4. 在我们生成服务器中,类似 redis / 数据库这类的服务器一般是不允许联网的为了安全,但是我们是不是每次都必须要登录上服务器去查数据呢?

这还是一些简单的理由,接下来我们来聊聊几种代理,顺便说说他们的应用场景,当然这种设计对于中小型公司是足够了,毕竟没去过大厂,不知道他们的具体架构和实现方式。

TCP 代理

在说 TCP 代理之前我们肯定还是要先了解下代理是什么东西?

代理(proxy)其实就是一个网络信息的中转站,我们使用一个图来表示:

比如这样一个场景,用户在外边,能够通过公网能够访问到云服务商集群中的一台具有公网 IP 的服务器,但是集群内部其它服务器都是不具备公网 IP 的,所以通过公网,我们无法访问到,但是有公网 IP 的服务器恰好在集群中,它的内网网卡和这些没有公网 IP 的机器是可以通信的,这意味着这台机器既可以和用户通信,又可以和后端的集群通信。那我们就得想办法,用户要访问后面的集群,让这个有公网 IP 的服务器帮忙传达一下,那么这个,当个中间人,实现用户和后端集群之间互相传话,于是这个有公网 IP 机器就成为了代理服务器。

那啥又是 TCP 代理?

在我们日常访问 WEB 应用,我们都是使用 http://,https://。但是有些服务不是 http 的,比如连接 MySQL 这种,这种明显不是 WEB 服务,所以我们不能像代理 WEB 服务一样代理它。而这类服务,就是 TCP 服务,我们得专门使用 TCP 代理。

我们同时举例 TCP 代理 MySQL 来具体说说如何使用配置。

在我们编译得时候加入了 --with-stream 参数,该参数是我们使用代理不可或缺的。

同样,我们在主配置文件 nginx.conf 中通过 include 来配置单独的目录,用于放置 TCP 配置的配置文件:

值得注意是,TCP 代理不是 HTTP 服务,所有我们的 include 和之前的位置不一样,我们得放在 http 的外层:

user  root;
...
http {
    ...
}
stream {
    include tcp/*.conf;
}

我们新建 tcp 目录:我这里为了方便使用直接 nginx 使用 root 用户

mkdir /data/services/nginx/conf/tcp

在目录下增加 MySQL 代理配置文件:mysql-proxy-demo.conf

upstream MYSQL-PROXY-DEMO {
    hash $remote_addr consistent;
    server 192.168.10.204:3306;
}

server {
    listen  5000;
    proxy_connect_timeout   10s;
    proxy_timeout   300s;
    proxy_pass  MYSQL-PROXY-DEMO;
}

简单说明:

1. 在 nginx 中,如果需要对后端多个机器做代理,就需要使用到 upstream,MYSQL-PROXY-DEMO 是给这个 upstream 取的名称,要求唯一。

2. hash xxx 是一种调度模式,当然这里只写了一条 server 记录,所有不存在调度到其他节点问题。

3. server xxx 是一条需要代理的记录,每一条一个 server。

4. server 段和 http WEB 服务类似,但是不需要 server_name。

5. proxy_connect_timeout 为连接超时时间,proxy_timeout 代理超时时间。

6. proxy_pass,代理中最为关键的一句,指名了我们把这个端口代理到哪个服务或者哪个 upstream。后面还会用到。

重载 nginx 此时我们测试数据库连接:

可以看到,我们成功的使用代理服务器的 IP + 端口通过 Navict 连接到了其它主机的 MySQL 数据库。

正向代理

正向代理不是我们使用的重点,因为在日常的使用中用的并不多,但是在某些特殊的场景下很有用。

比如有个局域网用户,无法访问互联网,但是局域网中另外一台机器却能够访问到互联网,所有我们可以通过那台机器作为代理去访问互联网。

正向代理的好处在于能够对需要访问的网站隐藏用户的真实信息。

这是系统为我提供的解决方案,但是并不是很好用,如果你想直接使用,请直接跳到后面第三方模块搭建正向代理

我们在 vhosts 目录下新建配置:forward-proxy-demo.conf

server {
    resolver 8.8.8.8;
    access_log off;
    listen 6080;
    location / {
        proxy_pass $scheme://$http_host$request_uri;
        proxy_set_header HOST $http_host;

        # 配置缓存大小,关闭磁盘缓存读写减少I/O,以及代理连接超时时间
        proxy_buffers 256 4k;
        proxy_max_temp_file_size 0;
        proxy_connect_timeout 30;

        # 配置代理服务器 Http 状态缓存时间
        proxy_cache_valid 200 302 10m;
        proxy_cache_valid 301 1h;
        proxy_cache_valid any 1m;
        proxy_next_upstream error timeout invalid_header http_502;
    }
}

简单说明:

红色部分为核心配置,这里我们直到了,在 nginx 中我们是可以通过 proxy_set_header 来处理请求头的。

我们在另外一台不能上网的机器上增加配置:

重载 nginx 后我们在不能上网的机器上执行 curl 百度:

curl -I --proxy 192.168.100.111:6080 http://www.baidu.com

结果如下:

当然我们也可以将代理配置定义成环境变量:

export http_proxy=http://192.168.100.111:6080

这样就能直接执行:

第三方模块搭建正向代理

当然,上面的配置都是针对 HTTP 的,对于 HTTPS 代理或者说整个正向代理,我们推荐使用第三方模块:ngx_http_proxy_connect_module

GITHUB 地址:

https://github.com/chobits/ngx_http_proxy_connect_module

将下载的 zip 包上传到服务器,重新编译 nginx,具体方法参考前面的动态添加模块:

https://www.cnblogs.com/Dy1an/p/11227796.html

1. 安装依赖:

yum install -y patch

2. 解压打补丁,编译:

从 GITHUB 上面,我们可以看到各个版本的 nginx 对应的补丁版本:

cd /data/packages/nginx
unzip ngx_http_proxy_connect_module-master.zip
cd nginx-1.16.0/
patch -p1 < /data/packages/nginx/ngx_http_proxy_connect_module-master/patch/proxy_connect_rewrite_101504.patch

编译不安装:

./configure --prefix=/data/services/nginx \
--user=nginx \
--group=nginx \--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-http_secure_link_module \
--with-http_flv_module \
--with-http_ssl_module \
--with-http_mp4_module \
--with-stream \
--with-http_realip_module \
--with-http_v2_module \
--with-http_sub_module \
--with-http_image_filter_module \
--with-pcre=/data/packages/nginx/pcre-8.43 \
--with-openssl=/data/packages/nginx/openssl-1.1.1c \
--with-zlib=/data/packages/nginx/zlib-1.2.11 \
--add-module=/data/packages/nginx/nginx-upload-module-master \
--add-module=/data/packages/nginx/nginx-upstream-fair-master \
--add-module=/data/packages/nginx/ngx_cache_purge-master \
--add-module=/data/packages/nginx/ngx-fancyindex-master \
--add-module=/data/packages/nginx/echo-nginx-module-master \
--add-module=/data/packages/nginx/ngx_http_proxy_connect_module-master

# 编译
make

3. 备份替换旧版:

# 备份
mv /data/services/nginx/sbin/nginx  /data/backup/nginx/nginx_$(date +%F)

# 更新
cp /data/packages/nginx/nginx-1.16.0/objs/nginx /data/services/nginx/sbin/

# 查看
/data/services/nginx/sbin/nginx -V

如图:

4. 添加 nginx 正向代理配置:

server {
    listen       6080;
    resolver 202.96.128.166;
    resolver_timeout 30s;

    # 代理配置
    proxy_connect;
    proxy_connect_allow            443 563;
    proxy_connect_connect_timeout  10s;
    proxy_connect_read_timeout     10s;
    proxy_connect_send_timeout     10s;

    location / {
        proxy_pass http://$host;
        proxy_set_header Host $host;
    }
}

重载配置访问测试:

curl -I --proxy 192.168.100.111:6080  http://www.baidu.com
curl -I --proxy 192.168.100.111:6080  https://www.alipay.com

HTTP 访问结果:

HTTPS 访问结果:

当然,我们也可以设置环境变量:

export http_proxy=http://192.168.100.111:6080
export https_proxy=http://192.168.100.111:6080
no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com" 

最后,小结一下:正向代理配置虽然能够满足我们的一定需求,但是有些时候不是很稳定,包括在配置过程中,有时候并不能一次就能访问成功,需要多测试几次。

反向代理 / 负载均衡

反向代理一直是我们 nginx 服务配置的重中之重,我们工作的项目中大部分其实都是围绕着反向代理展开的。如果你用 nginx,你说你没有配置过静态资源 WEB 我相信,但是你没有用过反向代理,那你一定不是做运维的。

那什么是反向代理?

这需要我们和正向代理结合起来理解,我们之前正向代理的时候是我们代理别人的服务让我们能够访问到。

那么反向代理就是代理我们的服务让别人能够访问到,是不是一下子就清晰了。

我们本次测试环境用到了三台机器,一台是我们的 nginx,另外两台是安装了 tomcat 服务的服务器。我们要实现以下图示:

用户访问 nginx 的 8090 端口调度到后端的 TOMCAT 8080 上面去。

至于 TOMCAT 怎么安装部署这里就不做过多说明,这里做了个小处理,在 TOMCAT webapps 下面默认 ROOT 项目的 index.jsp 文件增加了本机 IP 用于区分:

此时我们启动两个 TOMCAT 访问测试:

节点1结果:

节点2结果:

在 nginx 的 vhosts 目录下增加如下配置:reverse-proxy-demo.conf 

upstream REVERSE-PROXY-DEMO {
    ip_hash;
    server 192.168.100.112:8080 weight=1 max_fails=3 fail_timeout=10s;
    server 192.168.100.113:8080 weight=1 max_fails=3 fail_timeout=10s;
} 

server {
    listen      8090;
    server_name localhost;
    
    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_connect_timeout 30;
        proxy_send_timeout 30;
        proxy_read_timeout 30;
        proxy_pass http://REVERSE-PROXY-DEMO;
    }
}

如 TCP 代理一般,TCP 代理其实也是反向代理的一种,我们定义的 upstream 的名称要求唯一。

重载 nginx 访问测试:

可以看到请求被分配到了 100.113 这台机器上面去了!

我们之前就在使用 upstream,但是 upstream 到底是啥我们一直没说,其实 upstream 就是负载均衡。

从字面上的意思就可以理解,负载均衡就是均衡的,按照特定的调度算法,将请求调度到指定的节点(upstream server)。

upstream 配置说明:

1. nginx 负载均衡调度算法加上我们安装的 fair 模块,大致有以下 4 种:

调度算法 说明
权重轮询(默认) 按照顺序逐一分配到不同的后端。自动剔除失败的机器,使访问不受影响。
ip_hash 每个请求按照 IP 的 Hash 结果分配,使来自同一 IP 的固定访问到同一后端。能解决部分程序 session 没共享的问题
fair 更智能的算法,可以根据页面大小和加载速度进行智能负载,响应快的优先分配。
url_hash 需要按照 nginx hash 模块,按照访问的 URL 定向到某个机器上,能提升后端缓存服务器的效率。

日常用到比较多的就是前三个。

2. server 后面的参数:

参数 说明
weight 分配到请求权重,权重比例多高分配到请求的机会越大。
max_fails 最大的失败连接次数。
fail_timeout 等待请求的目标服务器响应的时长。
backup 当所有机器都 down 掉才会调度到这台机器。
down 手动停用某台机器。

这其实就是一些健康检查参数,但是这些参数存在不足,在实际应用中,可以结合 keepalived 来完成,后面会单独说明。 

server 段关于反向代理的一些配置:

参数 说明
proxy_redirect 重写应答头部的报文
proxy_connect_timeout nginx 将一个请求发送至 upstream server 之前等待的最大时长
proxy_set_header 将发送至 upsream server 的报文的某首部进行重写
proxy_cookie_domain 将 upstream server 通过 Set-Cookie 首部设定的 domain 修改为指定的值,可以为字符串、正则或变量
proxy_cookie_path 将 upstream server 通过 Set-Cookie 首部设定的 path 修改为指定的值,可以为字符串、正则或变量
proxy_hide_header 设定发送给客户端的报文中需要隐藏的首部
proxy_send_timeout 发送至 upstream server 的写操作的超时时长
proxy_read_timeout 发送至 upstream server 的读操作的超时时长
proxy_pass 指定将请求代理至 upstream server 的 URL 路径

其实上面的配置我们可以简单的做个调整就能变成我们反向代理的配置模板。

小结

简单的 TCP / 正向 / 反向代理负载均衡就这些内容,当然还要优化的空间,后面会专门针对 nginx 配置优化再度进行说明。

猜你喜欢

转载自www.cnblogs.com/Dy1an/p/11246021.html