如果我们有多个服务器,比如我们只有一个域名;我们可以利用其中一台服务器,通过nginx为这一个域名实现反向代理;进一步,我们可以利用这多台服务器,为这一个域名基于nginx的反向代理实现负载均衡。
文章目录
本文参考文献:
https://hashnode.blog.csdn.net/article/details/124518526
https://zhuanlan.zhihu.com/p/491075761
一、先搞明白什么是反向代理
讲清楚反向代理和负载均衡之前,我们要先搞明白什么是反向代理;
1.1 什么是代理
举个通俗易懂的例子来解释什么是代理:
比如我们要买一间二手房,虽然我们可以自己去找房源,但是这太花费时间精力了,而且房屋质量检测以及房屋过户等一系列手续也都得我们去办,再说现在这个社会,等我们找到房源,说不定房子都已经涨价了,那么怎么办呢?最简单快捷的方法就是找二手房中介公司(为什么?别人那里房源多啊),于是我们就委托中介公司来给我找合适的房子,以及后续的质量检测过户等操作,我们只需要选好自己想要的房子,然后交钱就行了。
代理简单来说,就是如果我们想做什么,但又不想直接去做,那么这时候就找另外一个人帮我们去做。那么这个例子里面的中介公司就是给我们做代理服务的,我们委托中介公司帮我们找房子。
1.2 什么是正向代理
弄清楚什么是代理了,那么什么又是正向代理呢?
这里再举一个例子:大家都知道,现在国内是访问不了 Google的,那么怎么才能访问 Google呢?我们又想,美国人不是能访问 Google吗(这不废话,Google就是美国的),如果我们电脑的对外公网 IP 地址能变成美国的 IP 地址,那不就可以访问 Google了。你很聪明,VPN 就是这样产生的。我们在访问 Google 时,先连上 VPN 服务器将我们的 IP 地址变成美国的 IP 地址,然后就可以顺利的访问了。
这里的 VPN 就是做正向代理的。正向代理服务器位于客户端和服务器之间,为了向服务器获取数据,客户端要向代理服务器发送一个请求,并指定目标服务器,代理服务器将目标服务器返回的数据转交给客户端。这里客户端是要进行一些正向代理的设置的。
PS:这里介绍一下什么是 VPN,VPN 通俗的讲就是一种中转服务,当我们电脑接入 VPN 后,我们对外 IP 地址就会变成 VPN 服务器的 公网 IP,我们请求或接受任何数据都会通过这个VPN 服务器然后传入到我们本机。这样做有什么好处呢?比如 VPN 游戏加速方面的原理,我们要玩网通区的 LOL,但是本机接入的是电信的宽带,玩网通区的会比较卡,这时候就利用 VPN 将电信网络变为网通网络,然后在玩网通区的LOL就不会卡了(注意:VPN 是不能增加带宽的,不要以为不卡了是因为网速提升了)。
可能听到这里大家还是很抽象,没关系,和下面的反向代理对比理解就简单了。
1.3 什么是反向代理
反向代理和正向代理的区别就是:正向代理代理客户端,反向代理代理服务器。
反向代理,其实客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器IP地址。
下面我们通过两张图来对比正向代理和方向代理:
理解这两种代理的关键在于代理服务器所代理的对象是什么,正向代理代理的是客户端,我们需要在客户端进行一些代理的设置。而反向代理代理的是服务器,作为客户端的我们是无法感知到服务器的真实存在的。
总结起来还是一句话:正向代理代理客户端,反向代理代理服务器。
二、反向代理的应用场景
反向代理方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
反向代理服务器通常有两种模型,一种是作为内容服务器的替身,另一种作为内容服务器集群的负载均衡器。
2.1 做内容服务器的替身
.
如果您的内容服务器具有必须保持安全的敏感信息,如信用卡号数据库,可在防火墙外部设置一个代理服务器作为内容服务器的替身。当外部客户机尝试访问内容服务器时,会将其送到代理服务器。实际内容位于内容服务器上,在防火墙内部受到安全保护。代理服务器位于防火墙外部,在客户机看来就像是内容服务器。
当客户机向站点提出请求时,请求将转到代理服务器。然后,代理服务器通过防火墙中的特定通路,将客户机的请求发送到内容服务器。内容服务器再通过该通道将结果回传给代理服务器。代理服务器将检索到的信息发送给客户机,好像代理服务器就是实际的内容服务器。如果内容服务器返回错误消息,代理服务器会先行截取该消息并更改标头中列出的任何 URL,然后再将消息发送给客户机。如此可防止外部客户机获取内部内容服务器的重定向 URL。
这样,代理服务器就在安全数据库和可能的恶意攻击之间提供了又一道屏障。与有权访问整个数据库的情况相对比,就算是侥幸攻击成功,作恶者充其量也仅限于访问单个事务中所涉及的信息。未经授权的用户无法访问到真正的内容服务器,因为防火墙通路只允许代理服务器有权进行访问。
2.2 作为内容服务器的负载均衡器
.
可以在一个组织内使用多个代理服务器来平衡各 Web 服务器间的网络负载。在此模型中,可以利用代理服务器的高速缓存特性,创建一个用于负载平衡的服务器池。此时,代理服务器可以位于防火墙的任意一侧。如果 Web 服务器每天都会接收大量的请求,则可以使用代理服务器分担 Web 服务器的负载并提高网络访问效率。
对于客户机发往真正服务器的请求,代理服务器起着中间调停者的作用。代理服务器会将所请求的文档存入高速缓存。如果有不止一个代理服务器,DNS 可以采用“轮询法”选择其 IP 地址,随机地为请求选择路由。客户机每次都使用同一个 URL,但请求所采取的路由每次都可能经过不同的代理服务器。
可以使用多个代理服务器来处理对一个高用量内容服务器的请求,这样做的好处是内容服务器可以处理更高的负载,并且比其独自工作时更有效率。在初始启动期间,代理服务器首次从内容服务器检索文档,此后,对内容服务器的请求数会大大下降。
三、反向代理的实现和负载均衡的实现
3.1 反向代理的实现
Nginx的反向代理配置过程
nginx实现反向代理配置的配置文件如下:
在/etc/nginx
目录下:
打开nginx.cong文件,并做以下修改
通过上面的配置可以看到,我们用我们自己的服务器ip(192.168.92.101)
来代理www.baidu.com;此时我们保存配置,并重启nginx服务,此时再去浏览器输入我们的ip,会发现打开的就是百度的页面,这样就实现了利用nginx反向代理;即我们用我们自己的服务器反向代理百度,效果就是用我们自己服务器ip访问我们自己服务器,最后访问的是百度页面。
另外:把ip换成自己服务器的域名也是一样的道理,比如原博客中的例子:
该博主将自己的服务器(test80.xzj520520.cn)反向代理http://bilibili.com;保存并重启nginx后,去浏览器访问http://test80.xzj520520.cn/,出现的是哔哩哔哩的页面,如下:
3.2 负载均衡器的实现
基于反向代理实现负载均衡器的过程,按照参考博客中的例子,并按照我的理解对其过程进行讲解:
3.2.1 准备工作
本来有个服务器,ip为192.168.8.101,另外再克隆两个centos服务器,ip分别设为192.168.8.102,192.168.8.103(如果你要复现,网段要改用和自己的电脑对应)
修改静态ip
vim /etc/sysconfig/network-scripts/ifcfg-ens33
如以下配置:
重启网络服务:
systemctl restart network
另一个虚拟机的配置也是一样。
另外配置好这两个虚拟机之后,配置nginx.cfg:
102的nginx.cfg:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include 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 logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
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$ {
# 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;
#}
}
# 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;
# }
#}
}
102的nginx在html目录下的index.html文件:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>I am from 192.168.8.102</h1>
</body>
</html>
103的nginx.cfg:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include 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 logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
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$ {
# 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;
#}
}
# 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;
# }
#}
}
103的nginx在html目录下的index.html文件
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>I am from 192.168.8.103</h1>
</body>
</html>
此时进行测试:
访问http://192.168.8.102/,结果如下:
访问http://192.168.8.103/,结果如下:
此时准备工作已经做好了。现在我们手头有三个服务器,分别是192.168.8.101、192.168.8.102、192.168.8.103;直接对其进行访问得到的结果如上图所示。
下面我们再次进行反向代理,以及进行负载均衡的演示。
3.2.2 再次进行反向代理的演示
将101代理到102
101的nginx.conf
worker_processes 1; #允许进程数量,建议设置为cpu核心数或者auto自动检测,注意Windows服务器上虽然可以启动多个processes,但是实际只会用其中一个
events {
#单个进程最大连接数(最大连接数=连接数*进程数)
#根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。
worker_connections 1024;
}
http {
#文件扩展名与文件类型映射表(是conf目录下的一个文件)
include mime.types;
#默认文件类型,如果mime.types预先定义的类型没匹配上,默认使用二进制流的方式传输
default_type application/octet-stream;
#sendfile指令指定nginx是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度。
sendfile on;
#长连接超时时间,单位是秒
keepalive_timeout 65;
#虚拟主机的配置
server {
#监听端口
listen 80;
#域名,可以有多个,用空格隔开
server_name test80.xzj520520.cn;
#配置根目录以及默认页面
location / {
proxy_pass http://192.168.8.102;
# root /www/test80;
# index index.html index.htm;
}
#出错页面配置
error_page 500 502 503 504 /50x.html;
#/50x.html文件所在位置
location = /50x.html {
root html;
}
}
}
经过上面的配置,我们用192.168.8.101来代理192.168.8.102;重启nginx,此时,如果顺利,我们访问192.168.8.101,访问到的页面应该是192.168.8.102服务器的页面;下面我们测试一下:访问192.168.8.101,结果如下:
确实访问的是192.168.8.102服务器的页面。
3.2.3 实现负载均衡(轮询模式)
轮询模式,顾名思义,就是轮流访问,即用来实现负载均衡的两台服务器被访问到的概率是一样的,具体过程如下:
配置101的负载均衡(轮询模式),如下配置,截图如下
完整配置文件如下:
worker_processes 1; #允许进程数量,建议设置为cpu核心数或者auto自动检测,注意Windows服务器上虽然可以启动多个processes,但是实际只会用其中一个
events {
#单个进程最大连接数(最大连接数=连接数*进程数)
#根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。
worker_connections 1024;
}
http {
#文件扩展名与文件类型映射表(是conf目录下的一个文件)
include mime.types;
#默认文件类型,如果mime.types预先定义的类型没匹配上,默认使用二进制流的方式传输
default_type application/octet-stream;
#sendfile指令指定nginx是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度。
sendfile on;
#长连接超时时间,单位是秒
keepalive_timeout 65;
#定义一组服务器
upstream httpds{
server 192.168.8.102:80;
server 192.168.8.103:80;
}
#虚拟主机的配置
server {
#监听端口
listen 80;
#域名,可以有多个,用空格隔开
server_name test80.xzj520520.cn;
#配置根目录以及默认页面
location / {
proxy_pass http://httpds;
# root /www/test80;
# index index.html index.htm;
}
#出错页面配置
error_page 500 502 503 504 /50x.html;
#/50x.html文件所在位置
location = /50x.html {
root html;
}
}
}
解释:
我们用192.168.8.102:80以及192.168.8.103:80来负载192.168.8.101,这样,我们在访问192.168.8.101时,最终应该访问的是192.168.8.102和192.168.8.103。
实际测试:
多次访问http://192.168.8.101/,发现确实102和103被交替访问。
3.2.4 实现负载均衡(权重模式)
权重模式的意思是,我们配置的两个负载均衡服务器,被访问到的概率(即权重)是不一样的,权重越大的服务器,被访问到的概率越大,权重越小的服务器,被访问到的概率越小。具体过程如下:
配置101的负载均衡(权重模式),配置文件如下:
worker_processes 1; #允许进程数量,建议设置为cpu核心数或者auto自动检测,注意Windows服务器上虽然可以启动多个processes,但是实际只会用其中一个
events {
#单个进程最大连接数(最大连接数=连接数*进程数)
#根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。
worker_connections 1024;
}
http {
#文件扩展名与文件类型映射表(是conf目录下的一个文件)
include mime.types;
#默认文件类型,如果mime.types预先定义的类型没匹配上,默认使用二进制流的方式传输
default_type application/octet-stream;
#sendfile指令指定nginx是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度。
sendfile on;
#长连接超时时间,单位是秒
keepalive_timeout 65;
#定义一组服务器
upstream httpds{
server 192.168.8.102 weight=10;
server 192.168.8.103 weight=1;
# server 192.168.8.102 weight=10 down; #down表示不参与负载均衡
# server 192.168.8.102 weight=10 backup; #backup表示是备用服务器,没有服务器可用的时候使用
}
#虚拟主机的配置
server {
#监听端口
listen 80;
#域名,可以有多个,用空格隔开
server_name test80.xzj520520.cn;
#配置根目录以及默认页面
location / {
proxy_pass http://httpds;
# root /www/test80;
# index index.html index.htm;
}
#出错页面配置
error_page 500 502 503 504 /50x.html;
#/50x.html文件所在位置
location = /50x.html {
root html;
}
}
}
讲解:配置文件中的以下代码就是在配置权重模式的负载均衡
#定义一组服务器
upstream httpds{
server 192.168.8.102 weight=10;
server 192.168.8.103 weight=1;
# server 192.168.8.102 weight=10 down; #down表示不参与负载均衡
# server 192.168.8.102 weight=10 backup; #backup表示是备用服务器,没有服务器可用的时候使用
}
192.168.8.102的权重是10,192.168.8.103的权重是1;所以如果多次访问192.168.8.101的话,最终访问到的界面,大多数是192.168.8.102服务器,少数是192.168.8.103服务器。让我们来看一下结果:
多次访问http://192.168.8.101/,发现确实102访问的次数多余103访问的次数。
3.2.5 其他负载均衡策略(不常用)
- ip_hash
根据客户端的ip地址转发同一台服务器,可以保持会话,但是很少用这种方式去保持会话,例如我们当前正在使用wifi访问,当切换成手机信号访问时,会话就不保持了。
- least_conn
最少连接访问,优先访问连接最少的那一台服务器,这种方式也很少使用,因为连接少,可能是由于该服务器配置较低,刚开始赋予的权重较低。
- url_hash(需要第三方插件)
根据用户访问的url定向转发请求,不同的url转发到不同的服务器进行处理(定向流量转发)。
- fair(需要第三方插件)
根据后端服务器响应时间转发请求,这种方式也很少使用,因为容易造成流量倾斜,给某一台服务器压垮。