反向代理与负载均衡
反向代理与负载均衡
正向代理
正向代理可以理解为「客户端」的代理
反向代理
反向代理可以理解为「服务器」的代理
反向代理:是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。这种代理方式叫做,隧道代理。有性能瓶颈,因为所有的数据都经过Nginx,所以Nginx服务器的性能至关重要。反向代理服务器通常有两种模型,一种是作为内容服务器的替身,另一种作为内容服务器集群的负载均衡器。
- 作内容服务器的替身
如果您的内容服务器具有必须保持安全的敏感信息,如信用卡号数据库,可在防火墙外部设置一个代理服务器作为内容服务器的替身。当外部客户机尝试访问内容服务器时,会将其送到代理服务器。实际内容位于内容服务器上,在防火墙内部受到安全保护。代理服务器位于防火墙外部,在客户机看来就像是内容服务器。
当客户机向站点提出请求时,请求将转到代理服务器。然后,代理服务器通过防火墙中的特定通路,将客户机的请求发送到内容服务器。内容服务器再通过该通道将结果回传给代理服务器。代理服务器将检索到的信息发送给客户机,好像代理服务器就是实际的内容服务器。如果内容服务器返回错误消息,代理服务器会先行截取该消息并更改标头中列出的任何 URL,然后再将消息发送给客户机。如此可防止外部客户机获取内部内容服务器的重定向 URL。
这样,代理服务器就在安全数据库和可能的恶意攻击之间提供了又一道屏障。与有权访问整个数据库的情况相对比,就算是侥幸攻击成功,作恶者充其量也仅限于访问单个事务中所涉及的信息。未经授权的用户无法访问到真正的内容服务器,因为防火墙通路只允许代理服务器有权进行访问。
- 作为内容服务器的负载均衡器
可以在一个组织内使用多个代理服务器来平衡各 Web 服务器间的网络负载。在此模型中,可以利用代理服务器的高速缓存特性,创建一个用于负载平衡的服务器池。此时,代理服务器可以位于防火墙的任意一侧。如果 Web 服务器每天都会接收大量的请求,则可以使用代理服务器分担 Web 服务器的负载并提高网络访问效率。
对于客户机发往真正服务器的请求,代理服务器起着中间调停者的作用。代理服务器会将所请求的文档存入高速缓存。如果有不止一个代理服务器,DNS 可以采用“轮询法”选择其 IP 地址,随机地为请求选择路由。客户机每次都使用同一个 URL,但请求所采取的路由每次都可能经过不同的代理服务器。
可以使用多个代理服务器来处理对一个高用量内容服务器的请求,这样做的好处是内容服务器可以处理更高的负载,并且比其独自工作时更有效率。在初始启动期间,代理服务器首次从内容服务器检索文档,此后,对内容服务器的请求数会大大下降。
负载均衡:把请求,按照一定算法规则,分配给多台业务服务器(即使其中一个坏了/维护升级,还有其他服务器可以继续提供服务)
反向代理+负载均衡
nginx.conf配置文件
启用proxy_pass,root和index字段就会失效
proxy_pass后的地址必须写完整 http://xxx
,不支持https
当访问localhost时(Nginx服务器),网页打开的是http://xxx
(应用服务器),网页地址栏写的还是localhost
http{
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://xxx;
#root html/test;
#index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
**定义地址别名 **
使用upstream定义一组地址【在server字段下】
访问localhost,访问都会代理到192.168.174.133:80
和192.168.174.134:80
这两个地址之一,每次访问这两个地址轮着切换(后面讲到,因为默认权重相等)
http{
upstream httpds{
server 192.168.174.133:80; #如果是80端口,可以省略不写
server 192.168.174.134:80;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://httpds;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
设置权重
访问使用哪个地址的权重
upstream httpds{
server 192.168.174.133:80 weight=10;
server 192.168.174.134:80 weight=80;
}
2
3
4
关闭
upstream httpds{
server 192.168.174.133:80 weight=10 down;
server 192.168.174.134:80 weight=80;
}
2
3
4
备用机
如果192.168.174.133:80
出现故障,无法提供服务,就用使用backup的这个机器
upstream httpds{
server 192.168.174.133:80 weight=10;
server 192.168.174.134:80 weight=80 backup;
}
2
3
4
动静分离
为了提高网站的响应速度,减轻程序服务器(Tomcat,Jboss等)的负载,对于静态资源,如图片、js、css等文件,可以在反向代理服务器中进行缓存,这样浏览器在请求一个静态资源时,代理服务器就可以直接处理,而不用将请求转发给后端服务器。对于用户请求的动态文件,如servlet、jsp,则转发给Tomcat,Jboss服务器处理,这就是动静分离。即动态文件与静态文件的分离。
动静分离原理
动静分离可通过location对请求url进行匹配,将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问。通常将静态资源放到nginx中,动态资源转发到tomcat服务器中。
当用户请求时,动态请求分配到Tomcat业务服务器,静态资源请求放在Nginx服务器中
例子:
- 如果请求的资源地址是
location/
,/
的优先级比较低,如果下面的location没匹配到,就会走http://xxx这个地址的机器 - 如果请求的资源地址是
location/css/*
,就会被匹配到nginx的html目录下的css文件夹中(我们把css静态资源放在这个位置)
server {
listen 80;
server_name localhost;
location / { # /的优先级比较低,如果下面的location没匹配到,就会走http://xxx这个地址的机器
proxy_pass http://xxx;
}
location /css { # root指的是html,location/css指的是root下的css,所以地址就是html/css
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
使用正则
location ~*/(js|css|img){
root html;
index index.html index.htm;
}
2
3
4
常见的Nginx正则表达式
^ :匹配输入字符串的起始位置
$ :匹配输入字符串的结束位置
* :匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll”
+ :匹配前面的字符一次或多次。如“ol+”能匹配“ol”及“oll”、“olll”,但不能匹配“o”
? :匹配前面的字符零次或一次,例如“do(es)?”能匹配“do”或者“does”,”?”等效于”{0,1}”
. :匹配除“\n”之外的任何单个字符,若要匹配包括“\n”在内的任意字符,请使用诸如“[.\n]”之类的模式
\ :将后面接着的字符标记为一个特殊字符或一个原义字符或一个向后引用。如“\n”匹配一个换行符,而“\$”则匹配“$”
\d :匹配纯数字
{n} :重复 n 次
{n,} :重复 n 次或更多次
{n,m} :重复 n 到 m 次
[] :定义匹配的字符范围
[c] :匹配单个字符 c
[a-z] :匹配 a-z 小写字母的任意一个
[a-zA-Z0-9] :匹配所有大小写字母或数字
() :表达式的开始和结束位置
| :或运算符 //例(js|img|css)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
location正则:
//location大致可以分为三类
精准匹配:location = /{}
一般匹配:location /{}
正则匹配:location ~/{}
//location常用的匹配规则:
= :进行普通字符精确匹配,也就是完全匹配。
^~ :表示前缀字符串匹配(不是正则匹配,需要使用字符串),如果匹配成功,则不再匹配其它 location。
~ :区分大小写的匹配(需要使用正则表达式)。
~* :不区分大小写的匹配(需要使用正则表达式)。
!~ :区分大小写的匹配取非(需要使用正则表达式)。
!~* :不区分大小写的匹配取非(需要使用正则表达式)。
//优先级
首先精确匹配 =
其次前缀匹配 ^~
其次是按文件中顺序的正则匹配 ~或~*
然后匹配不带任何修饰的前缀匹配
最后是交给 / 通用匹配
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
注意:
- 精确匹配:
=
, 后面的表达式中写的是纯字符串 - 字符串匹配:
^~
和无符号匹配
, 后面的表达式中写的是纯字符串 - 正则匹配:
~
和~*
和!~
和!~*
, 后面的表达式中写的是正则表达式
location的说明
(1)location = / {}
=为精确匹配 / ,主机名后面不能带任何字符串,比如访问 / 和 /data,则 / 匹配,/data 不匹配
再比如 location = /abc,则只匹配/abc ,/abc/或 /abcd不匹配。若 location /abc,则即匹配/abc 、/abcd/ 同时也匹配 /abc/。
(2)location / {}
因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求 比如访问 / 和 /data, 则 / 匹配, /data 也匹配,
但若后面是正则表达式会和最长字符串优先匹配(最长匹配)
(3)location /documents/ {}
匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索其它 location
只有其它 location后面的正则表达式没有匹配到时,才会采用这一条
(4)location /documents/abc {}
匹配任何以 /documents/abc 开头的地址,匹配符合以后,还要继续往下搜索其它 location
只有其它 location后面的正则表达式没有匹配到时,才会采用这一条
(5)location ^~ /images/ {}
匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条
(6)location ~* \.(gif|jpg|jpeg)$ {}
匹配所有以 gif、jpg或jpeg 结尾的请求
然而,所有请求 /images/ 下的图片会被 location ^~ /images/ 处理,因为 ^~ 的优先级更高,所以到达不了这一条正则
(7)location /images/abc {}
最长字符匹配到 /images/abc,优先级最低,继续往下搜索其它 location,会发现 ^~ 和 ~ 存在
(8)location ~ /images/abc {}
匹配以/images/abc 开头的,优先级次之,只有去掉 location ^~ /images/ 才会采用这一条
(9)location /images/abc/1.html {}
匹配/images/abc/1.html 文件,如果和正则 ~ /images/abc/1.html 相比,正则优先级更高
优先级总结:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (location /)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
实际网站使用中,至少有三个匹配规则定义:
- 第一个必选规则
直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,比如说官网。这里是直接转发给后端应用服务器了,也可以是一个静态首页
location = / {
proxy_pass http://127.0.0.1:8080/;
}
2
3
- 第二个必选规则
处理静态文件请求,这是nginx作为http服务器的强项,有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
root /webroot/static/;
}
location ~* \.(html|gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}
2
3
4
5
6
7
- 第三个规则
通用规则,用来转发动态请求到后端应用服务器
location /api/ {
proxy_pass http://127.0.0.1:3000/api/
}
2
3
URL重写
rewrite是URL重写的关键指令,根据regex(正则表达式)部分内容,重定向到replacement,结尾是flag标记。
rewrite <regex> <replacement> [flag];
关键字 正则 替代内容 flagt标记
正则:per1森容正则表达式语句进行规则匹配
替代内容:将正则匹配的内容替换成replacement
flag标记说明:
last #本条规则匹配完成后,继续向下匹配新的1ocation URI规则
break #本条规则匹配完成即终止,不再匹配后面的任何规则
redirect #返回302临重定向,游览器地址会显示跳转后的URL地址
permanent #返回301永久重定向,测览器地址栏会显示跳转后的URL地址
2
3
4
5
6
7
8
9
10
11
12
13
14
浏览器地址栏访问 xxx/123.html
实际上是访问xxx/index.jsp?pageNum=123
server {
listen 80;
server_name localhost;
location / {
rewrite ^/([0-9]+).html$ /index.jsp?pageNum=$1 break;
proxy_pass http://xxx;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
网关服务器
上图中,应用服务器,不能直接被外网访问到,只能通过Nginx服务器进行访问(使用proxy_pass),这时候这台Nginx服务器就成为了网关服务器(承担入口的功能)
所以,我们启动应用服务器的防火墙,设置其只能接受这台Nginx服务器的请求
添加rich规则
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.174.135" port protocol="tcp" port="8080" accept" #这里的192.168.174.135是网关 服务器地址
移除rich规则
firewall-cmd --permanent --remove-rich-rule="rule family="ipv4" source address="192.168.174.135" port port="8080" protocol="tcp" accept"
重启
移除和添加规则都要重启才能生效
firewall-cmd --reload
查看所有规则
firewall-cmd --list-all #所有开启的规则
防盗链
当我们请求到一个页面后,这个页面一般会再去请求其中的静态资源,这时候请求头中,会有一个refer字段,表示当前这个请求的来源,我们可以限制指定来源的请求才返回,否则就不返回,这样可以节省资源

valid_referers none|server_name
设置有效的refer值
- none:检测地址没有refer,则有效
- server_name:检测主机地址,refer显示是从这个地址来的,则有效(server_name必须是完整的
http://xxxx
)
注意:if ($invalid_referer)
中if后有个空格,不写就会报错
nginx: [emerg] unknown directive "if($invalid_referer)" in /usr/local/nginx/conf/nginx.conf:27
例子:这里设置nginx服务器中的img目录下的图片必须refer为http:192.168.174/133才能访问
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://xxx;
}
location /img{
valid_referers http:192.168.174/133;
if ($invalid_referer){#无效的
return 403;#返回状态码403
}
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
如果引用这张图片的页面且refer并没有被设置,图片无法加载出来
如果直接访问图片地址,因为没有refer字段指向来源,会直接显示Nginx的页面
设置盗链图片
将提示图片放在html/img/x.png,访问设置防盗链图片时,就返回这x.png张图
location /img{
valid_referers http:192.168.174/133;
if ($invalid_referer){#无效的
rewrite ^/ /img/x.png break;
}
root html;
index index.html index.htm;
}
2
3
4
5
6
7
8
高可用场景
用户访问时,访问的是一个虚拟IP,keepalived会选定一个主服务器使用这个虚拟IP
每台机器上的keepalived会相互通信,根据其他机器上的keepalived进程是否存在,判断服务器状态,如果默认的Master停止了,就会在剩下的Backup机器中,竞选出一台Nginx服务器作为Master
安装keepalived
yum install -y keepalived
安装成功
修改keepalived配置
- 配置文件在/etc/keepalived/keepalived.conf
vrrp_instance
、authentication
、virtual_router_id
、virtual_ipaddress
这几个一样的机器,才算是同一个组里。这个组才会选出一个作为Master机器
这里我们设置两台机器,分别下载好keepalived,然后进行配置
机器一:
! Configuration File for keepalived
global_defs {
router_id lb1 # 名字与其他配置了keepalive的机器不重复就行
}
vrrp_instance heyingjie {#vrrp实例名可以随意取
state MASTER #只能有一个默认的Master,其他写BACKUP
interface ens33 # ip addr查看下网卡名,默认时ens33
virtual_router_id 51
priority 100 # 多台安装了keepalived的机器竞争成为Master的优先级
advert_int 1 #通信时间
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.16 #虚拟IP
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
机器二:
! Configuration File for keepalived
global_defs {
router_id lb2
}
vrrp_instance heyingjie {
state BACKUP #只能有一个默认的Master,其他写BACKUP
interface ens33
virtual_router_id 51
priority 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.200.16 #虚拟IP
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
通过命令ip addr
查看机器一的ip信息,可以看到虚拟IP
配置证书
购买服务器——>购买域名,并解析到这个主机——>购买证书,绑定到域名上,并且把证书文件安装到服务器,并在Nginx上配置好
这时候,这个域名就可以使用https进行访问里(https://xxxx
),浏览器上会有一个小锁
上面的流程我比较熟悉了,就直接跳过了,这里直接写申请到证书后的Nginx配置部分
下载证书文件


下载后,解压压缩包,可以看到两个文件,一个是 xxx.key
(私钥)和xxx.pem
(证书)
配置
将两个文件上传到Nginx目录中,记得放置的位置。我这里直接放在nginx.conf配置文件所在的目录(/user/local/nginx/conf
),所以写的都是相对路径
server {
listen 443 ss1;
ssl_certificate xxx.pem; #这里是证书路径
ssl_certificate_key xxx.key #这里是私钥路径
}
2
3
4
5
6