前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除
一、代理原理
1、反向代理产生的背景
单个服务器的处理客户端(用户)请求能力有一个极限,当接入请求过多时,会造成服务器繁忙,可以使用多个服务器来共同分担成千上万的用户请求,这些服务器提供相同的服务,但对用户来说,感觉不到任何区别。
2、反向代理服务的实现
需要有一个负载均衡设备(即反向代理服务器)来分发用户请求,将用户请求分发到空闲的服务器上。服务器返回自己的服务到负载均衡设备。负载均衡设备将服务器返回用户。
3、正/反向代理的区别
正向代理:代理客户端,正向代理的过程隐藏了真实的请求客户端,服务器不知道真实的客户端是谁,客户端的服务都被代理服务器代替请求
反向代理:代理服务端,反向代理的过程隐藏了真实的服务器,客户端不知道真正提供服务的是谁,客户端请求的服务都被代理服务器接收
4、知识扩展
4.1、HTTP Server和Application Server的区别和联系
Apache/nignx是静态服务器(HTTP Server):
- Nginx优点:负载均衡、反向代理、处理静态文件优势。nginx处理静态请求的速度高于apache;
-
Apache优点:相对于Tomcat服务器来说处理静态文件是它的优势,速度快。Apache是静态解析, 适合静态HTML、图片等。
HTTP Server 关心的是 HTTP 协议层面的传输和访问控制,所以在 Apache/Nginx 上你可以看到代理、负载均衡等功能
HTTP Server(Nginx/Apache)常用做静态内容服务和代理服务器,将外来请求转发给后面的应用服务(tomcat,jboss,jetty等)。
应用服务器(tomcat/jboss/jetty)是动态服务器(Application Server):
应用服务器Application Server,则是一个应用执行的容器。它首先需要支持开发语言的 Runtime (对于 Tomcat 来说,就是 Java,若是Ruby/Python 等其他语言开发的应用也无法直接运行在Tomcat 上)。
4.2、 应用服务器与HTTP服务器的集成与协同工作
应用服务器(如tomcat)往往也会集成 HTTP Server 的功能,nginx也可以通过模块开发来提供应用功能,只是不如专业的 HTTP Server 那么强大,所以应用服务器往往是运行在 HTTP Server 的背后,执行应用,将动态的内容转化为静态的内容之后,通过 HTTP Server分发到客户端
4.3、常用软硬件
常用开源集群软件有:lvs,keepalived,haproxy,nginx,apache,heartbeat
常用商业集群硬件有:F5, Netscaler,Radware,A10等
二、Nginx Proxy配置
1、代理模块
1.1、代理配置
# ----------------代理--------------------#
Syntax: proxy_pass URL; #代理的后端服务器URL
Default: —
Context: location, if in location, limit_except
# ---------------缓冲区--------------------#
Syntax: proxy_buffering on | off;
Default: proxy_buffering on; #缓冲开关
Context: http, server, location
proxy_buffering # 开启的情况下,nignx会把后端返回的内容先放到缓冲区当中,然后再返回给客户端(边收边传,不是全部接收完再传给客户端)。
Syntax: proxy_buffer_size size;
Default: proxy_buffer_size 4k|8k; #缓冲区大小
Context: http, server, location
Syntax: proxy_buffers number size;
Default: proxy_buffers 8 4k|8k; #缓冲区数量
Context: http, server, location
Syntax: proxy_busy_buffers_size size;
Default: proxy_busy_buffers_size 8k|16k;#忙碌的缓冲区大小控制同时传递给客户端的
buffer数量
Context: http, server, location
# ----------------头信息--------------------#
Syntax: proxy_set_header field value;
Default: proxy_set_header Host $proxy_host; #设置真实客户端地址
proxy_set_header Connection close;
Context: http, server, location
# ----------------超时--------------------#
Syntax: proxy_connect_timeout time;
Default: proxy_connect_timeout 60s; #链接超时
Context: http, server, location
Syntax: proxy_read_timeout time;
Default: proxy_read_timeout 60s;
Context: http, server, location
Syntax: proxy_send_timeout time; #nginx进程向fastcgi进程发送request的整个过程的超时时间
Default: proxy_send_timeout 60s;
Context: http, server, location
1.2、buffer/缓冲区工作原理
- 缓冲区分配:每个请求都有自己的缓冲区,这些缓冲区不是全局的,而是针对每个请求的。
- 缓冲开关:proxy_buffering用于控制是否开启代理服务器的响应缓冲。只有开启时,proxy_buffers和proxy_busy_buffers_size参数才会生效。
- 主缓冲区:无论proxy_buffering是否开启,proxy_buffer_size设置的主缓冲区始终工作,用于存储上游服务器响应的头部信息。
- 数据读取与传输:
-
在proxy_buffering开启的情况下,Nginx会尝试将上游服务器的所有数据读入缓冲区,直到所有proxy_buffers被填满或数据结束。
-
数据开始向客户端传输,同时Nginx继续接收数据并可能将其写入临时文件,由proxy_max_temp_file_size控制大小。
-
如果响应内容很大,Nginx会从临时文件继续读取数据,直到传输完成。
-
-
忙碌缓冲区:一旦proxy_buffers中的缓冲区被填满,它们就会处于忙碌状态,直到其中的数据完全传输给客户端。忙碌缓冲区的总大小不能超过proxy_busy_buffers_size,这个参数用来控制同时向客户端传输的缓冲区数量。
2、代理实验
2.1、环境准备
角色 | |
---|---|
nginx-1:10.0.0.2 | 网站服务器 |
nginx-2:10.0.0.3 | 代理服务器 |
2.2、nginx-1启动网站
[root@centos ~]# cat /usr/share/nginx/html/index.html
This is proxy test!
[root@centos ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@centos ~]# nginx -s reload
2.3、nginx-2启动代理程序
[root@centos ~]# cat /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://10.0.0.2:80; # 真实服务器地址:IP/域名
proxy_redirect default; # 代理后的URL重定向行为,默认情况下不进行重定向
proxy_set_header Host $http_host; # 转发请求时使用原始请求中的Host头
proxy_set_header X-Real-IP $remote_addr; # X-Real-IP头:客户端IP地址
#proxy_set_header REMOTE-HOST $remote_addr; # REMOTE-HOST:客户端IP地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 跟踪请求经过的代理服务器
proxy_connect_timeout 30; # 与后端服务器建立连接的超时时间
proxy_send_timeout 60; # 向后端服务器发送请求的超时时间
proxy_read_timeout 60; # 从后端服务器读取响应的超时时间
proxy_buffering on; # 开启响应缓冲,可以提高代理性能
proxy_buffer_size 32k; # 缓冲区的大小
proxy_buffers 4 128k; # 缓冲区的数量和大小
proxy_busy_buffers_size 256k; # 忙碌缓冲区的大小
proxy_max_temp_file_size 256k; # 临时文件的最大大小
}
}
[root@centos ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@centos ~]# nginx -s reload
2.4、浏览器访问
(1)使用PC客户端访问nginx-2服务器地址
成功访问nginx-1服务器页面
(2)客户端配置路由映射
若想使用域名进行访问,在 C:\Windows\System32\drivers\etc\hosts 文件中添加一行 | (linux:/etc/hosts)
# 主机IP 配置的域名
10.0.0.3 www.test.com
(3)、观察nginx-1服务器的日志
[root@centos ~]# cat /var/log/nginx/access.log
10.0.0.3 - - [09/Aug/2024:18:41:08 +0800] "GET /favicon.ico HTTP/1.0" 404 555 "http://10.0.0.3/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" "10.0.0.1"
# 10.0.0.3:代理服务器地址
# 10.0.0.1:客户机地址
访问成功。记录了客户机的IP和代理服务器的IP
三、负载均衡
1、负载均衡的作用
在计算机的世界里,负载均衡就是让多个服务器或者网络资源来分担工作,这样即使某个服务器或者资源很忙或者出现问题,其他的服务器或资源还可以继续工作,保证整个系统的稳定和效率。
下面的配置是解决方案之一
proxy_connect_timeout 1; #nginx服务器与被代理的服务器建立连接的超时时间,默认60秒 proxy_read_timeout 1; #nginx服务器想被代理服务器组发出read请求后,等待响应的超时间,默认为60秒
proxy_send_timeout 1; #nginx服务器想被代理服务器组发出write请求后,等待响应的超时间,默认为60秒
proxy_ignore_client_abort on; #客户端断网时,nginx服务器是否中断对被代理服务器的请求。默认为off
使用upstream指令配置一组服务器作为被代理服务器,服务器中的访问算法遵循配置的负载均衡规则,同时可以使用该指令配置在发生哪些异常情况时,将请求顺次交由下一组服务器处理
proxy_next_upstream timeout; #反向代理upstream中设置的服务器组,出现故障时,被代理服务器返回的状态值。 error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off
- error:建立连接或向被代理的服务器发送请求或读取响应信息时服务器发生错误
- timeout:建立连接,想被代理服务器发送请求或读取响应信息时服务器发生超时
- invalid_header:被代理服务器返回的响应头异常
- off:无法将请求分发给被代理的服务器
- http_400,...:被代理服务器返回的状态码为400,500,502等
2、Nginx负载均衡组件模块
实现Nginx负载均衡的组件主要有两个:
- ngx_http_upstream_module:负载均衡模块;实现网站的负载均衡功能以及节点的健康检查
-
ngx_http_proxy_module:proxy代理模块;用于把请求转发给服务器节点或upstream服务器池
2.1、upstream模块
(1)模块介绍
upstream模块允许Nginx定义一组或多组节点服务器组,使用时可以通过proxy_pass代理方式把网站的请求发送到事先定义好的对应upstream组的名字上,具体写法为:
proxy_pass http://server_pools
server_pools就是一个upstream节点服务器组名字
(2)upstream配置示例
upstream server_pool {
server 10.0.0.2; # 默认80端口
server 10.0.0.3;
}
(3)upstream模块参数
参数 | 说明 |
---|---|
server | 负载后面的RS配置,可以是ip或者域名 |
weight | 请求服务器的权重。默认值为1,越大表示接受的请求比例越大 |
max_fails | nginx 尝试连接后端主机失败的次数,需要配合proxy_net_upstream ,fastcgi_next_upstream 和memcached_next_upstream 这三个参数来使用 |
fail_timeout | 在max_fails 定义的失败次数后,距离下次检查的时间间隔,默认10s |
backup | 热备配置,标志这台服务器作为备份服务器,若主服务器全部宕机了,就会向它转发请求 |
down | 表示这个服务器永不可用,可配合ip_hash使用 |
下面给出一个示例:
upstream web_pools {
server linux.example.com weight=5;
server 127.0.0.1:8080 max_fail=5 fail_timeout=10s;
# 当5次连续检查失败后,间隔10s后重新检测。
server linux.example.com:8080 backup;
# 指定备份服务器。作用:等上面服务器全部不可访问时就向它转发请求。
}
2.2、http_proxy_module模块
(1)proxy_pass指令介绍
proxy_pass指令属于ngx_http_proxy_module模块,此模块可以将请求转发到另一台服务器上。在实际的反向代理工作中,会通过location功能匹配指定的URI,然后把接收到的符合匹配URI的请求通过proxy_pass抛给定义好的upstream节点池
(2)http proxy模块参数
参数 | 说明 |
---|---|
proxy_set_header | 设置http请求header项传给后端服务器节点 |
client_body_buffer_size | 指定客户端请求主题缓冲区大小 |
proxy_connect_timeout | 表反向代理与后端节点服务器连接的超时时间,即发起握手等候响应的超时时间 |
proxy_send_timeout | 表示代理后端服务器的数据回传时间,即在规定时间之内,后端服务器必须传完所有的数据,否则,nginx将断开这个连接 |
proxy_read_timeout | 设置nginx从代理的后端服务器获取信息的时间,表示连接建立成功后,nginx等待后端服务器的响应时间,其实是nginx在后端排队等候处理的时间 |
proxy_buffer_size | 设置缓冲区大小,默认该缓冲区大小等于指令proxy_buffers设置的大小 |
proxy_buffers | 设置缓冲区的数量和大小,nginx从代理的后端服务器获取的响应信息,会放置在缓冲区 |
proxy_busy_buffers_size | 用于设置系统很忙时可以使用的proxy_buffers大小,官方推荐的大小为proxy_bufer*2 |
proxy_temp_file_write_size | 指定proxy缓存临时文件的大小 |
3、负载均衡算法
upstream支持4种负载均衡调度算法:
4.1、rr轮询(默认)
默认调度算法,每个请求按时间顺序逐一分配到不同的后端服务器,宕机的服务器会自动从节点服务器池中剔除。
upstream server_pool {
server 10.0.0.2;
server 10.0.0.2;
}
注意:对于服务器性能不同的集群,该算法容易引发资源分配不合理等问题
4.2、wrr加权轮询(weight)
在rr轮询算法的基础上加上权重,权重和用户访问成正比,权重值越大,被转发的请求也就越多
upstream server_pool {
server 10.0.0.2 weight=5;
server 10.0.0.2 weight=10;
}
加权轮询应用于服务器性能不等的集群中,使资源分配更加合理化
4.3、ip_hash(会话保持)
每个请求按访问IP的hash结果分配,同一个IP客户端固定访问一个后端服务器。可以保证来自同一ip的请求被打到固定的机器上,可以解决session问题
upstream server_pool {
ip_hash;
server 10.0.0.2;
server 10.0.0.2;
}
4.4、fair(动态调度算法)
此种算法根据后端服务器的响应时间来分配请求,响应时间短的优先分配。 Nginx 本身是 不支持 fair 的,如果需要使用这种调度算法,必须下载Nginx的 upstream_fair 模块
upstream server_pool {
server 10.0.0.2;
server 10.0.0.2;
fair;
}
4.5、url_hash算法(web缓存节点)
根据访问URL的hash结果来分配请求,让每个URL定向到同一个后端服务器, 同样,Nginx本身是不支持url_hash,如果需要使用这种调度算法,必须安装Nginx的hash模块软件包。
upstream server_pool {
server 10.0.0.2; # 指定后端服务器的地址和端口
server 10.0.0.2;
hash $request_uri; # 使用哈希方法来分配请求并使用请求的URI作为哈希的键
hash_method crc32; # 使用CRC32算法来计算哈希值
}
4、Nginx负载均衡配置示例
4.1、实现效果
在浏览器输入http://testapp.com,实现负载均衡效果(平均访问到两台服务器)
4.2、环境准备
这边使用两台服务器以及一台负载均衡器
主机名 | IP地址 | 角色 |
---|---|---|
centos-1 | 10.0.0.2 | nginx服务器 |
centos-2 | 10.0.0.3 | nginx服务器 |
centos-3 | 10.0.0.4 | nginx 负载均衡服务器 |
4.3、三台服务器均安装Nginx
4.4、配置用于测试的nginx首页
为了更便于观察到负载均衡实现出的效果,下面为两台服务器编写不同的首页文件
# 配置文件参数默认即可,下面修改首页测试文件
[root@centos-1 ~]# cat /usr/share/nginx/html/index.html
My domain IP is 10.0.0.2
[root@centos-2 ~]# cat /usr/share/nginx/html/index.html
My domain IP is 10.0.0.3
[root@centos ~]# nginx -s reload
# nginx服务别忘记启动
4.5、配置nginx负载均衡服务器
[root@centos-3 ~]# cat /etc/nginx/conf.d/default.conf
upstream testapp {
server 10.0.0.2:80;
server 10.0.0.3:80;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://testapp;
}
}
4.6客户端配置路由映射
因为使用域名进行访问,在 C:\Windows\System32\drivers\etc\hosts 文件中添加一行 | (linux:/etc/hosts)
# 主机IP 配置的域名
10.0.0.4 www.testapp.com
4.7、浏览器访问
不断刷新会发现所有请求被负载均衡器(10.0.0.4)均分配到10.0.0.2和10.0.0.3服务器上,实现了负载均衡的效果
四、Nginx配置7层协议及4层协议方法(扩展)
1、7层协议
OSI(Open System Interconnection)是一个开放性的通行系统互连参考模型,他是一个定义的非常好的协议规范,共包含七层协议
2、4层协议
TCP/IP协议
之所以说TCP/IP是一个协议族,是因为TCP/IP协议包括TCP、IP、UDP、ICMP、RIP、TELNETFTP、SMTP、ARP、TFTP等许多协议,这些协议一起称为TCP/IP协议。
从协议分层模型方面来讲,TCP/IP由四个层次组成:网络接口层、网络层、传输层、应用层:
3、协议配置
在nginx做负载均衡,负载多个服务,部分服务是需要7层的,部分服务是需要4层的,也就是说7层和4层配置在同一个配置文件中
3.1、环境准备
在这同样使用第三点负载均衡中的机器环境
3.2、配置代理服务器的nginx配置文件实现7层协议
使用负载均衡来分发请求到多个上游服务器,编辑/etc/nginx/nginx.conf:
worker_processes 4;
worker_rlimit_nofile 102400;
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;
keepalive_timeout 65;
gzip on;
# 定义两个上游服务器组,testweb和testapp,用于负载均衡
upstream testweb {
ip_hash;
server 10.0.0.2:80 weight=2 max_fails=2 fail_timeout=2s;
server 10.0.0.3:80 weight=2 max_fails=2 fail_timeout=2s;
}
server {
listen 80;
server_name www.test.com;
charset utf-8;
#access_log logs/host.access.log main;
location / {
proxy_pass http://testweb;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
upstream testapp {
server 10.0.0.2:8081 weight=2 max_fails=2 fail_timeout=2s;
server 10.0.0.3:8081 weight=2 max_fails=2 fail_timeout=2s;
}
server {
listen 81;
server_name www.app.com;
charset utf-8;
#access_log logs/host.access.log main;
location / {
proxy_pass http://testapp;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
3.3、4层协议配置
在使用yum安装的nginx版本大于1.9.0的时候,增加了一个stream模块,来实现4层协议(网络层和传输层)的转发、代理、负载均衡等。stream模块的用法跟http的用法类似,允许我们配置一组TCP或者UDP等协议的监听,然后通过proxy_pass来转发我们的请求,通过upstream添加多个后端服务,实现负载均衡。
stream {
upstream myweb {
hash $remote_addr consistent;
server 172.17.14.2:8080;
server 172.17.14.3:8080;
}
server {
listen 82;
proxy_connect_timeout 10s;
proxy_timeout 30s;
proxy_pass myweb;
}
}
五、Nginx会话保持
1、ip_hash
这个上述介绍过;ip_hash使用源地址哈希算法,将同一客户端的请求总是发往同一个后端服务器,除非该服务器不可用
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
}
ip_hash简单易用,但有如下问题:
- 当后端服务器宕机后,session会丢失;
- 来自同一局域网的客户端会被转发到同一个后端服务器,可能导致负载失衡;
- 不适用于CDN网络,不适用于前段还有代理的情况。
2、sticky_cookie_insert
使用sticky_cookie_insert启用会话亲缘关系,这会导致来自同一客户端的请求被传递到一组服务器的同一台服务器。与ip_hash不同之处在于,它不是基于IP来判断客户端的,而是基于cookie来判断。因此可以避免上述ip_hash中来自同一局域网的客户端和前段代理导致负载失衡的情况。(需要引入第三方模块才能实现)
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky_cookie_insert srv_id expires=1h domain=3evip.cn path=/;
}
# expires:设置浏览器中保持cookie的时间
# domain:定义cookie的域
# path:为cookie定义路径
3、jvm_route方式
jvm_route是通过session_cookie这种方式来实现session粘性。将特定会话附属到特定tomca上,从而解决session不同步问题,但是无法解决宕机后会话转移问题。如果在cookie和url中并没有session,则这只是个简单的round-robin负载均衡。
jvm_route的原理:
- 一开始请求过来,没有带session的信息,jvm_route就根据round robin的方法,发到一台Tomcat上
- Tomcat添加上session信息,并返回给客户
- 用户再次请求,jvm_route看到session中有后端服务器的名称,他就把请求转到对应的服务器上
暂时jvm_route模块还不支持fair的模式。jvm_route的工作模式和fair是冲突的。对于某个特定用户,当一直为他服务的Tomcat宕机后,默认情况下它会重试max_fails的次数,如果还是失败,就重新启用round robin的方式,而这种情况下就会导致用户的session丢失
4、使用后端服务器自身通过相关机制保持session同步
使用数据库、redis、memcached等做session复制
致谢
在此,我要对所有为知识共享做出贡献的个人和机构表示最深切的感谢。同时也感谢每一位花时间阅读这篇文章的读者,如果文章中有任何错误,欢迎留言指正。
学习永无止境,让我们共同进步!!