正向代理&反向代理&负载均衡
代理的概念
正向代理
正向代理是一个位于客户端和目标服务器之间的代理服务器。
当客户端需要获取目标服务器上的内容时,客户端向代理服务器(正向)发送一个请求,并且指定目标服务器地址,此时代理服务器(正向)向目标服务器转交并且将获得的内容返回给客户端。
举例:
(正向代理,"它代理的是客户端,替客户端请求目标服务")
用户A无法访问www.google.com,但是能访问服务器B,而服务器B可以访问www.google.com。于是用户A访问服务器B,通过服务器B去访问www.google.com,服务器B收到请求后,去访问www.google.com,Google把响应信息返回给服务器B,服务器B再把响应信息返回给A。这样,通过代理服务器B,用户A就实现了访问www.google.com。
上述这样的正向代理最大的特点就是客户端非常明确要访问的目标服务器地址同时必须知道代理服务器的地址和端口,目标服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端。正向代理模式屏蔽或者隐藏了真实客户端信息。
使用正向代理时客户端需要进行特定的设置。如下图:
反向代理
反向代理与正向代理正好相反。对于客户端来说,反向代理就好像目标服务器,并且客户端不需要进行任何设置。
客户端向代理服务器(反向)发送请求,代理服务器(反向)判断并把请求最终转发到对应的真正服务,并将从真正服务器上获得的内容返回给客户端。此时,客户端并不会感知到代理服务器(反向)后面的真正服务,只需要把代理服务器(反向)当成真正的服务器即可。
举例:
(反向代理,"它代理的是服务端,替真正服务接收客户端的请求")
假设用户A访问 http://www.demo.cn/sign.html,但www.demo.cn上并不存在sign.html页面,于是接收用户请求的这个代理服务器就偷偷从其他服务器上读取sign.html,然后返回给用户,而用户并不知道sign.html页面究竟位于哪台机器上。
上述这样的反向代理最大的特点就是客户端不需要知道真实的服务地址,仅需要知道代理服务器的地址和端口,客户端只清楚请求来自哪代理服务器,而不清楚来自哪个具体的真正服务器。反向代理模式隐藏了真正服务器的信息。
Nginx基础知识
Nginx是什么
Nginx是一个开源的高性能Web服务器和反向代理服务器,主要用于处理客户端和服务器的请求分发和负载均衡。
Nginx的优点和缺点
优点:
1.高并发量:根据官方给出的数据,能够支持高达 50,000 个并发连接数的响应;
2.内存消耗少:处理静态文件会比ApacheWeb服务器占用更少的内存及资源,属于轻量级Web服务器;
3.简单稳定:配置简单,基本在一个conf文件中配置,性能比较稳定,可以7*24小时长时间不间断运行;
4.模块化程度高:Nginx是高度模块化的设计,编写模块相对简单,支持 SSL;
5.支持rewrite重写规则:能够根据域名、URL的不同, 将HTTP请求分发到不同的后端服务器群组;
6.低成本:Nginx可以做高并发的负载均衡,且Nginx是开源免费的,如果使用F5等硬件来做负载均衡,硬件成本比较高;
7.支持多系统:Nginx代码完全用C语言从头写成,已经移植到许多体系结构和操作系统,包括:Linux、Mac以及Windows。
缺点:
1.动态处理差:nginx处理静态文件好,耗费内存少,但是处理动态页面则很鸡肋,现在一般前端用nginx作为反向代理抗住压力,Apache或Tomcat作为后端处理动态请求。
2.rewrite弱:虽然nginx支持rewrite功能,但没有Apache的rewrite功能强大;
Linux中Nginx的安装
可以通过yum方式快速安装,执行以下命令
sudo yum install nginx
稍等一会即可完成安装。
Nginx默认配置文件在/etc/nginx中。
Nginx默认安装路径在/usr/sbin/nginx中。
Nginx启动
启动命令格式:nginx安装目录地址 -c nginx配置文件地址
/usr/sbin/nginx -c /etc/nginx/nginx.conf
Nginx停止
nginx的停止有三种方式:
从容停止
1、查看进程号
[root@LinuxServer ~]# ps -ef|grep nginx
2、杀死进程
[root@LinuxServer ~]# kill -QUIT 2072
快速停止
1、查看进程号
[root@LinuxServer ~]# ps -ef|grep nginx
2、杀死进程
[root@LinuxServer ~]# kill -TERM 2132
或 [root@LinuxServer ~]# kill -INT 2132
强制停止
[root@LinuxServer ~]# pkill -9 nginx
Nginx重启
1、验证nginx配置文件是否正确
方法一:进入nginx安装目录sbin下,输入命令./nginx -t
看到如下显示nginx.conf syntax is ok
nginx.conf test is successful
说明配置文件正确!
方法二:在启动命令-c前加-t
重启Nginx服务
方法一:进入nginx可执行目录sbin下,输入命令./nginx -s reload 即可
方法二:查找当前nginx进程号,然后输入命令:kill -HUP 进程号 实现重启nginx服务
Windows中Nginx的安装
可以通过yum方式快速安装,执行以下命令
首先在命令提示符中进入到Nginx的安装路径
1、测试配置文件是否正确
nginx -t
2、启动:
C:\server\nginx-1.0.2>start nginx
或
C:\server\nginx-1.0.2>nginx.exe
3、停止:
C:\server\nginx-1.0.2>nginx.exe -s stop
或
C:\server\nginx-1.0.2>nginx.exe -s quit
注:stop是快速停止nginx,可能并不保存相关信息;quit是完整有序的停止nginx,并保存相关信息。
3、重新载入Nginx:
C:\server\nginx-1.0.2>nginx.exe -s reload
当配置信息修改,需要重新载入这些配置时使用此命令。
Nginx配置文件概述
Nginx配置文件是由若干个部分组成的。
nginx.conf文件结构如下:
#user nobody;
#指定worker工作进程数,用于处理所有的连接
worker_processes auto;
events {
#单个工作进程可以允许同时建立外部连接的数量数字越大,能同时处理的连接越多
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#指定是否使用sendfile系统调用来传输文件,提高操作效率
sendfile on;
#来指定 KeepAlive 的超时时间(timeout),指定每个 TCP 连接最多可以保持多长时间。
#Nginx 的默认值是 75 秒,有些浏览器最多只保持 60 秒,所以可以设定为 60 秒。
keepalive_timeout 60;
server {
#listen和server_name正好对应Nginx服务地址的host和port。
listen 8090;
server_name localhost;
location / {
proxy_set_header Host api.demo.cn;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass https://www.esign.cn;
}
}
}
全局配置部分:用于配置对这整个服务都有效的参数;
event{}配置部分:定义event模型工作特性;
http{}配置部分:定义http协议相关配置;
server{}配置部分:具体转发服务配置;
http块
http块是Nginx服务器配置中的重要部分,代理、缓存和日志定义等绝大多数的功能和第三方模块的配置都可以放在这模块中。作用包括:文件引入、MIME-Type定义、日志自定义、是否使用sendfile传输文件、连接超时时间、单连接请求数上限等。
server块
server块,虚拟主机(虚拟服务器)。作用:使得Nginx服务器可以在同一台服务器上至运行一组Nginx进程,就可以运行多个网站。
location块
location块是server块的一个指令。作用:基于Nginx服务器接收到的请求字符串,虚拟主机名称(ip,域名)、url匹配,对特定请求进行处理。
常见重要参数讲解
proxy_set_header Host 域名地址
作用:把原http请求
的Header中的Host字段也放到转发的请求里。如果不加这一行的话,nginx转发的请求header里就不会有Host字段,而服务器是靠这个Host值来区分你请求的是哪个域名的资源的。如果未配置,在某些情况下容易出现400 Bad Request 或 404 Not Found错误。
一般配置为目标服务地址的域名。
proxy_set_header X-Real-IP $remote_addr
作用:
将$remote_addr的值放进变量X-Real-IP中,此变量名可变,$remote_addr的值为客户端的真实IP。
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
作用:
设定 X-Forwarded-For 参数来获取客户端真实的ip地址。对于使用了反向代理的客户端,跟踪真实的ip地址。
如果不设置则会认为所有的请求都来在反向代理服务器。
详见可参阅 https://www.cnblogs.com/diaosir/p/6890825.html
proxy_redirect 重定向Url
作用:通过proxy_redirect将被代理服务器的响应头中的location字段进行修改后返回给客户端。
如:
server {
listen 80;
server_name www.boke.com;
location / {
proxy_pass http://192.168.1.154:8080;
proxy_redirect off;
}
}
则curl查看返回结果
[root@localhost nginx]# curl -I http://www.boke.com/wuman
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 24 Dec 2015 12:02:00 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Location: http://192.168.1.154:8080/wuman/
这里location为带有后端服务器实际地址跟端口的响应头信息这样在实际线上是不允许的所以这里我们打算通过proxy_redirect将被代理服务器的响应头中的location字段进行修改后返回给客户端。
server {
listen 80;
server_name www.boke.com;
location / {
proxy_pass http://192.168.1.154:8080;
proxy_redirect ~^http://192.168.1.154:8080(.*) http://www.boke.com$1;
}
则curl查看返回结果
[root@localhost nginx]# curl -I http://www.boke.com/wuman
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 24 Dec 2015 12:08:34 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Location: http://www.boke.com/wuman/
此时查看location已经变成了我们想要的结果了。 此时通过replacement 301重定向到了我们新的页面。
location用法说明
语法: location [=|~|~*|^~] /uri/ { … }
意思是可以以“ = ”或“ ~* ”或“ ~ ”或“ ^~ ”或“ @ ”符号为前缀,当然也可以没有前缀紧接着是 /***/。
=
开头表示精确匹配^~
开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。以xx开头~
开头表示区分大小写的正则匹配 以xx结尾~*
开头表示不区分大小写的正则匹配 以xx结尾!~
和!~*
分别为区分大小写不匹配及不区分大小写不匹配 的正则/
通用匹配,任何请求都会匹配到。
location分为两类,一类为普通 location,一类为正则location。
普通location:
“普通 location ”是以“ = ”或“ ^~ ”为前缀或者没有任何前缀的 /***/
正则location:
“正则 location ”是以“ ~ ”或“ ~* ”为前缀的 /uri/
匹配顺序
对于一个特定的 HTTP 请求,nginx 应该匹配哪个 location 块的指令呢?
匹配规则是:先 匹 配 普 通 location ,再 匹 配 正 则 表 达 式。
多个location场景下的location匹配
Nginx 的 location 匹配规则是:“正则 location ”让步 “普通 location”的严格精确匹配结果;但覆盖 “普通 location ”的最大前缀匹配结果。例子1 先普通location,再正则location匹配。
例子1 先普通location,再正则location匹配
server {
listen 9090;
server_name localhost;
location / {
root html;
index index.html index.htm;
deny all;
}
location ~ \.html$ {
allow all;
}
}
location / {… deny all;} 普通 location 以“ / ”开始的 URI 请求(注意任何 HTTP 请求都必然以“/ ”开始,所以“ / ”的意思是所有的请求都能被匹配上),都拒绝访问; location ~.html$ {allow all;} 正则 location以 .html 结尾的 URI 请求,都允许访问。
测试结果
说明:
curl http://localhost:9090/ 的结果是“ 403 Forbidden ”,说明被匹配到“ location / {…deny all;} ”了,原因很简单HTTP 请求 GET / 被“严格精确”匹配到了普通 location / {} ,则会停止搜索正则 location ;
curl http://localhost:9090/index.html 结果是“ Welcome to nginx! ”,说明没有被“ location / {…deny all;} ”匹配,否则会 403 Forbidden ,但 /index.html 的确也是以“ / ”开头的,只不过此时的普通 location / 的匹配结果是“最大前缀”匹配,所以 Nginx 会继续搜索正则 location , location ~ .html$ 表达了以 .html 结尾的都 allow all; 于是接着就访问到了实际存在的 index.html 页面。
curl http://localhost:9090/index_notfound.html 同样的道理先匹配 location / {} ,但属于“普通 location 的最大前缀匹配”,于是后面被“正则 location ” location ~ .html$ {} 覆盖了,最终 allow all ; 但的确目录下不存在index_notfound.html 页面,于是 404 Not Found 。
如果此时我们访问 http://localhost:9090/index.txt 会是什么结果呢?显然是 deny all ;因为先匹配上了 location / {…deny all;} 尽管属于“普通 location ”的最大前缀匹配结果,继续搜索正则 location ,但是 /index.txt 不是以 .html结尾的,正则 location 失败,最终采纳普通 location 的最大前缀匹配结果,于是 deny all 了。
例子2 普通 location 的“隐式”严格匹配
//在例子1的基础上增加精确匹配
server {
listen 9090;
server_name localhost;
location /exact/match.html {
allow all;
}
location / {
root html;
index index.html index.htm;
deny all;
}
location ~ \.html$ {
allow all;
}
}
测试结果
说明:
结果进一步验证了“普通 location ”的“严格精确”匹配会终止对正则 location 的搜索。这里我们小结下“普通 location”与“正则 location ”的匹配规则:先匹配普通 location ,再匹配正则 location ,但是如果普通 location 的匹配结果恰好是“严格精确( exact match )”的,则 nginx 不再尝试后面的正则 location ;如果普通 location 的匹配结果是“最大前缀”,则正则 location 的匹配覆盖普通 location 的匹配。也就是前面说的“正则 location 让步普通location 的严格精确匹配结果,但覆盖普通 location 的最大前缀匹配结果”。
普通 location 的“显式”严格匹配和“ ^~ ” 前缀
上面我们演示的普通 location 都是不加任何前缀的,其实普通 location 也可以加前缀:“ ^~ ”和“ = ”。其中“ ^~”的意思是“非正则,不需要继续正则匹配”,也就是通常我们的普通 location ,还会继续搜索正则 location (恰好严格精确匹配除外),但是 nginx 很人性化允许配置人员告诉 nginx 某条普通 location ,无论最大前缀匹配,还是严格精确匹配都终止继续搜索正则 location ;而“ = ”则表达的是普通 location 不允许“最大前缀”匹配结果,必须严格等于,严格精确匹配。
例子3
server {
listen 9090;
server_name localhost;
location /exact/match.html {
allow all;
}
location ^~ / {
root html;
index index.html index.htm;
deny all;
}
location ~ \.html$ {
allow all;
}
}
测试结果
正则 location 与编辑顺序
location 的指令与编辑顺序无关,这句话不全对。对于普通 location 指令,匹配规则是:最大前缀匹配(与顺序无关),如果恰好是严格精确匹配结果或者加有前缀“ ^~ ”或“ = ”(符号“ = ”只能严格匹配,不能前缀匹配),则停止搜索正则 location ;但对于正则 location 的匹配规则是:按编辑顺序逐个匹配(与顺序有关),只要匹配上,就立即停止后面的搜索。
server {
listen 9090;
server_name localhost;
location ~ \.html$ {
allow all;
}
location ~ ^/prefix/.*\.html$ {
deny all;
}
}
server {
listen 9090;
server_name localhost;
location ~ ^/prefix/.*\.html$ {
deny all;
}
location ~ \.html$ {
allow all;
}
}
测试结果
说明:
Location ~ ^/prefix/.*\.html$ {deny all;} 表示正则 location 对于以 /prefix/ 开头,
.html 结尾的所有 URI 请求,都拒绝访问; location ~\.html${allow all;}
表示正则 location 对于以 .html 结尾的 URI 请求,都允许访问。 实际上,
prefix 的是 ~\.html$ 的子集。在“配置 3.1 ”下,两个请求都匹配上 location ~\.html$ {allow all;} ,
并且停止后面的搜索,于是都允许访问, 404 Not Found ;在“配置 3.2 ”下, /regextest.html 无法匹配 prefix ,
于是继续搜索 ~\.html$ ,允许访问,于是 404 Not Found ;然而 /prefix/regextest.html 匹配到 prefix ,
于是 deny all , 403 Forbidden 。
什么是负载均衡
当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃。为了避免服务器崩溃,让用户有更好的体验,我们通过负载均衡的方式来分担服务器压力。
我们可以建立很多很多服务器,组成一个服务器集群,当用户访问网站时,先访问一个中间服务器,在让这个中间服务器在服务器集群中选择一个压力较小的服务器,然后将该访问请求引入该服务器。如此以来,用户的每次访问,都会保证服务器集群中的每个服务器压力趋于平衡,分担了服务器压力,避免了服务器崩溃的情况。负载均衡是用反向代理的原理实现的。
如:
负载均衡的几种常用方式
1、轮询
轮询方式是Nginx负载默认的方式,顾名思义,所有请求都按照时间顺序分配到不同的服务上,如果服务Down掉,可以自动剔除,如下配置后轮训10001服务和10002服务。
upstream dalaoyang-server {
server localhost:10001;
server localhost:10002;
}
2、权重
指定每个服务的权重比例,weight和访问比率成正比,通常用于后端服务机器性能不统一,将性能好的分配权重高来发挥服务器最大性能,权重越高,在被访问的概率越大,如下例,分别是30%,70%。
upstream dalaoyang-server {
server localhost:10001 weight=3;
server localhost:10002 weight=7;
}
3、iphash
每个请求都根据访问ip的hash结果分配,经过这样的处理,每个访客固定访问一个后端服务,如下配置(ip_hash可以和weight配合使用)。
upstream dalaoyang-server {
ip_hash;
server localhost:10001 weight=1;
server localhost:10002 weight=2;
}
4、最少连接
将请求分配到连接数最少的服务上。
upstream dalaoyang-server {
least_conn;
server localhost:10001 weight=1;
server localhost:10002 weight=2;
}
5、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream dalaoyang-server {
server localhost:10001 weight=1;
server localhost:10002 weight=2;
fair;
}
6、url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
Nginx配置
以轮训为例,如下是nginx.conf完整代码
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream sign-server {
server localhost:10001;
server localhost:10002;
}
server {
listen 8090;
server_name localhost;
location / {
proxy_set_header Host api.demo.cn;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://sign-server;
}
}
}