第1章 集群简介
1.1 什么是集群
简单的说,集群就是指一组(若干个)相互独立的计算机,利用高速通信网络组成的一个较大的计算机服务系统,每个集群节点(即集群中的每台计算机)都是运行各自服务器的独立服务器。当用户客户机请求集群系统时,集群给用户的感觉就是一个单一独立的服务器,而实际上用户请求的是一组集群服务器。
若要用一句话描述集群,即一堆服务器合作做同一件事,这些机器可能需要整个技术团队架构、设计和统一协调管理,这些机器可以分布在一个机房,也可以分布在全世界各个地区的机房。
1.2 集群的特点
- 高性能:计算机集群的性能不亚于使用大型机等设备的运算能力
- 价格有效性:在达到同样性能需求下,采用计算机集群架构比采用同等运算能力的大型计算机具有更高的性价比
- 可伸缩性:当服务负载、压力增长时,针对集群系统进行较简单的扩展即可满足需求,且不会降低服务质量
- 高可用性:在集群系统中即使部分硬件或软件发生故障,但整个系统的服务仍可以是7×24可用
- 透明性:多个独立计算机组成的松耦合集群系统构成了一个虚拟服务器,用户访问集群系统时,就像访问一台高性能的服务器一样
- 可管理性:这个系统可能在物理上很大,但其实容易管理,就像管理一个单一影像系统一样
- 可编程性:在集群系统上,容易开发及修改各类应用程序
1.3 集群种类
- 负载均衡集群(Load balancing clusters),简称LBC或者LB。
- 高可用性集群(High-availability(HA)clusters),简称HAC。
- 高性能计算集群(High-performance(HP)clusters),简称HPC。
- 网络计算(Grid computing)集群。
提示:负载均衡集群和高可用性集群是互联网行业常用的集群架构模式。
1.3.1 负载均衡集群
负载均衡集群可以把很多客户集中的访问请求负载压力尽可能平均地分摊在计算机集群中处理。负载均衡集群运行时一般是通过一个或多个前端负载均衡器将客户访问请求分发到后端的一组服务器上,从而达到真个系统的高性能和高可用性。
- 负载均衡集群的作用:
- 分担用户访问请求及数据流量(负载均衡)
- 保持业务连续性,即7×24小时服务(高可用性)
- 应用于Web业务及数据库从库服务器的业务
提示:负载均衡集群典型的开源软件包括LVS、Nginx、Haproxy等。
1.3.2 高可用性集群
一般是指集群中任意一个节点失效的情况下该节点上的所有任务会自动转移到其他正常的节点上,此过程不影响整个集群的运行。它们经常利用在多台机器上运行的冗余节点和服务来相互跟踪,当某个节点失效后它的替补者将在非常短的时间内接管它的职责,因此对于用户而言业务不会受到影响。
- 高可用集群的作用:
- 当一台机器宕机时,另外一台机器接管宕机机器的IP资源和服务资源,提供服务
- 常用于不易实现负载均衡的应用,比如负载均衡器、主数据库、主存储对之间
提示:高可用性集群常用的开源软件包括Keepalived、Hearbeat等。
1.3.3 高性能计算集群
高性能计算集群也称并行计算,对外就好像一个超级计算机,这种超级计算机内部由数十至上万个独立服务器组成,并且在公共消息传递层上进行通信以运行并行应用程序。
1.4 常用集群软硬件介绍及选型
1.4.1 企业运维中常见的集群软硬件产品
- 开源集群软件:Nginx、LVS、Haproxy、Keepalived、Hearbeat
- 商业集群硬件:F5、Netscaler、A10、Radware等
Netscaler产品图 F5产品图
1.4.2 集群软硬件产品如何选型
- 当企业业务重要,技术力量又薄弱。并且希望出钱购买产品及获取更好的服务时,可以选择硬件负载均衡产品,如F5、Netscaler、Radware等,此类公司多为传统的大型非互联网企业,如银行、证券、金融及宝马、奔驰公司等。
- 对于门户网站来说,大多会并用软件及硬件产品来分担单一产品的风险,如淘宝、腾讯、新浪等,融资了的企业会购买硬件产品,如赶集网等。
- 中小型互联网企业由于起步阶段无利润可赚或者利润很低,会希望通过使用开源免费的方案来解决问题,因此会雇佣专门的运维人员进行维护,如51CTO等。
相比较而言,商业的负载均衡产品成本高、性能好、更稳定,缺点是不能二次开发,开源的负载均衡软件对运维人员的能力要求较高,如果运维及开发能力强那么开源的负载均衡软件是不错的选择,目前互联网行业更倾向于使用开源的负载均衡软件。
1.4.3 如何选择开源集群软件
- 中小型企业互联网公司网站在并发访问和总访问量不是很大的情况下建议首选Nginx负载均衡;
- 如果考虑Nginx负载均衡的高可用功能,建议首选Keepalived软件;
- 如果是大型企业互联网公司,负载均衡产品可以使用LVS+Keepalived在前端做四层转发(一般是主备或主主,如果需要扩展可以使用DNS或前端使用OSPF),后端使用Nginx或者Haproxy做七层转发(可扩展到百台),再后面是应用服务器,如果是数据库与存储的负载均衡和高可用建议选择LVS+Heartbeat。
第2章 Nginx负载均衡集群介绍
2.1 搭建负载均衡服务的需求
- 把单台计算机无法承受的大规模并发访问或数据流量分担到多台节点设备上分别进行处理,减少用户等待响应的时间,提升用户体验。
- 单个重负载的运算分担到多台节点设备上做并行处理,每个节点设备处理结束后,将结果汇总,返回给用户,系统处理能力得到大幅度提高。
- 7×24小时的服务保证,任意一个或多个有限后端节点设备宕机,不能影响业务。
- 在负载均衡集群中,同组集群的所有计算机节点都应该提供相同的服务。
2.2 反向代理和负载均衡的区别
- 普通负载均衡软件(如LVS)其实实现的功能只是对请求数据包的转发、传递,接收到的请求还是来自访问负载均衡器的客户端的真实用户;
- 反向代理接收访问用户的请求后会代理用户重新发起请求代理下的节点服务器,最后把数据返回给客户端用户,节点服务器看来访问的节点服务器的客户端用户就是反向代理服务器。
一句话概括:负载均衡是转发用户请求的数据包,而Nginx反向代理是接收用户的请求然后重新发起请求去请求其后面的节点。
2.3 实现nginx负载均衡的组件说明
Nginx http功能模块 | 模块说明 |
ngx_http_proxy_module | proxy代理模块,用于把请求抛给服务器节点或upstream服务器池 |
ngx_http_upstream_module | 负载均衡模块,可以实现网站的负载均衡功能及节点的健康检查 |
第3章 Nginx负载均衡核心组件介绍
3.1 Nginx upstream模块
Nginx的负载均衡功能依赖于ngx_http_upstream_module模块,所支持的代理方式包括proxy_pass、fastcgi_pass、memcached_pass等。
ngx_http_upstream_module模块允许Nginx定义一组或多组节点服务器组,使用时可以通过proxy_pass代理方式把网站的请求发送到事先定义好的对应upstream组的名字上。
提示:ngx_http_upstream_module模块官方地址为:http://nginx.org/en/docs/http/ngx_http_upstream_module.html。
3.1.1 语法格式
upstream <em>name</em> { server <em>backend1.example.com </em> <em>weight=5;</em> server <em>backend2.example.com:8080;</em> server <em>unix:/tmp/backend3;</em> server <em>backup1.example.com:8080 backup;</em> server <em>backup2.example.com:8080 backup;</em> }
3.1.2 语法说明
- upstream:固定的命令名称
- name:是一个upstream集群组的名字,可以自己取名,调用时用这个名字
- server:定义服务器地址或域名的关键字
- example.com:要被负载均衡的服务器域名或IP地址
- weight:代表权重,数字越大被分配的请求越多
3.1.3 upstream模块相关说明
upstream模块的内容应放于nginx.conf配置的http{}标签内,其默认的调度节点算法是wrr(weighted round-robin,即权重轮询)。
- server标签参数说明:
upstream模块内参数 | 参数说明 |
server 10.0.0.8:80 | 负载均衡后面的RS配置,可以是IP或域名,如果端口不写默认为80端口。高并发场景下IP可换成域名,通过DNS做负载均衡。 |
weight=1 | 代表服务器的权重,默认值为1。权重越大表示接受的请求比例越大。 |
max_fails=1 | Nginx尝试连接后端主机失败的次数,这个数值是配置proxy_next_upstrea m、fastcgi_next_upstream和memcached_next_upstream这三个参数来使用的,当Nginx接受后端服务器返回这三个参数定义的状态码时,会将这个请求转发给正常工作的后端服务器,例如404、502、503等。Max_fails的默认值是1,企业场景下建议2-3次,如京东1次,蓝汛10次,根据业务需求去配置。 |
backup | 热备配置(RS节点的高可用),当前面激活的RS都失败后会自动启用热备RS,这标志着这个服务器作为备份服务器,若主服务器全部宕机了就会向他转发请求。注意:当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup |
fail_timeout=10 | 在max_fails定义的失败次数后距离下次检查的间隔时间,默认为10秒,如果max_fails是5,它就检查5次,如果5次都是502,那么它就会根据fail_timeout的值等待10秒再去检查,还是只检查一次,如果持续502,在不重新加载Nginx配置的情况下每隔10秒都只检查一次。常规业务2-3秒比较合理,比如京东3秒,蓝汛3秒,可根据业务需求配置。 |
down | 标志服务器永远不可用,可配合ip_hash使用 |
3.1.4 upstream模块调度算法
- 静态调度算法:根据自身设定的规则进行匹配,包括rr、wrr、ip_hash等
- 动态调度算法:根据后端节点的当前状态来决定是否分发请求,包括least_conn、fair等
3.1.4.1 rr轮询(默认调度算法,静态调度算法)
按客户端请求顺序把客户端的请求逐一分配到不同的后端节点服务器,相当于LVS中的算法,如果后端节点服务器宕机,宕机的服务器会被自动从节点服务器池中剔除,以使客户端的用户访问不受影响,新的请求会分配给正常的服务器。
- rr算法示例
upstream server_pools { #默认不配置任何参数即为rr轮询算法 server 10.0.0.7:80; server 10.0.0.8:80; }
- 测试结果:
[root@web01 ~]# for n in `seq 100`;do curl bbs.leon.com/bingbing.html;sleep 2;done bbs web02 bbs web01 bbs web02 bbs web01 ...省略部分输出...
3.1.4.2 wrr(权重轮询,静态调度算法)
在rr轮询算法的基础上加上权重即为权重轮询算法,当使用该算法时权重和用户访问成正比,权重值越大被转发的请求也就越多,可以根据服务器的配置和性能指定权重值的大小,有效解决新旧服务器性能不均带来的请求分配问题。
- wrr算法示例
upstream server_pools { #使用weight参数设定权重值 server 10.0.0.7:80 weight=1; server 10.0.0.8:80 weight=2; }
- 测试结果:
[root@web01 ~]# for n in `seq 100`;do curl bbs.leon.com/bingbing.html;sleep 2;done bbs web01 bbs web02 bbs web01 bbs web01 bbs web02 bbs web01 bbs web01 ...省略部分输出...
3.1.4.3 ip_hash(静态调度算法)
每个请求按客户端IP的hash结果分配,当新的请求到达时先将其客户端IP通过哈希算法算出一个哈希值,在随后的客户端请求中客户IP的哈希值只要相同就会被分配到同一台服务器,该调度算法可以解决动态网页的session共享问题,但有时会导致请求分配不均,即无法保证1:1的负载均衡。
- ip_hash算法示例
upstream server_pools { #使用ip_hash参数设置算法 ip_hash; server 10.0.0.7:80; server 10.0.0.8:80; }
- 测试结果:
[root@web01 ~]# for n in `seq 100`;do curl bbs.leon.com/bingbing.html;sleep 2;done bbs web01 bbs web01 bbs web01 bbs web01 bbs web01 ...省略部分输出...
注意:当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能有weight和backup,即使有也不会生效。
3.1.4.4 fair(动态算法)
此算法依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端节点服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身不支持fair调度算法,可以通过upstream_fair模块进行使用该算法。
- fair算法示例
upstream server_pools { #使用fair参数设置算法 server 10.0.0.7:80; server 10.0.0.8:80; fair; }
- 测试结果:
问题:Nginx如何添加第三方模块
3.1.4.5 least_conn算法
least_conn算法会根据后端节点的连接数来决定分配情况,哪个机器连接数少就分发给哪台机器。
3.1.4.6 url_hash算法
与ip_hash类似,这里是根据访问URL的hash结果来分配请求的,让每个URL定向到同一个后端服务器,后端服务器为缓存服务器时效果显著。url_hash按访问URL的hash结果来分配请求,使每个URL定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率命中率。
- url_hash算法示例
upstream server_pools { server 10.0.0.7:80; server 10.0.0.8:80; hash $request_uri; hash_method crc32; }
提示:Nginx本身不支持url_hash,可以安装hash模块软件包进行支持。
3.1.4.7 一致性hash算法
一致性hash算法一般用于代理后端业务为缓存服务(如Squid、Memcached)的场景,通过将用户请求的URI或者指定字符串进行计算,然后调度到后端的服务器上,此后任何用户查找同一个URI或者指定字符串都会被调度到这台服务器上,因此后端的每个节点缓存的内容都是不同的,一致性hash算法可以解决后端某个或几个节点宕机后缓存的数据动荡最小。
- 一致性hash算法示例
upstream server_pools { consistent_hash $request_uri; server 10.0.0.7:80; server 10.0.0.8:80; }
提示:虽然Nginx本身不支持一致性hash算法,但Nginx的分支Tengine支持。详细可见:http://tengine.taobao.org/document_cn/http_upstream_consisten_hash_cn.html。
3.2 http_proxy_module模块
此模块可以讲请求转发到另一台服务器,在实际的反向代理工作中会通过location功能匹配指定的URI,然后把接收到的符合匹配URI的请求通过proxy_pass抛给定义好的upstream节点池。
提示:ngx_http_proxy_module官方地址为:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass。
3.2.1 命令格式
Syntax: proxy_pass <em>URL</em>; Default: — Context: location, if in location, limit_except
- 将匹配URI为name的请求抛给http://127.0.0.1/remote
location /name/ { proxy_pass http://127.0.0.1/remote/; }
- 将匹配URI为some/path的请求抛给http://127.0.0.1
location /some/path/ { proxy_pass http://127.0.0.1; }
- 将匹配URI为name的请求应用指定的rewrite规则,然后抛给http://127.0.0.1
location /name/ { rewrite /name/([^/]+) /users name=$1 break; proxy_pass http://127.0.0.1; }
3.2.2 http_proxy模块参数
http_proxy模块相关参数 | 说明 |
proxy_set_header | 设置http请求header项传给后端服务器节点。例如:可实现让代理后端的服务器节点获取访问客户端用户的真实IP地址 |
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_buffers*2 |
proxy_temp_file_write_size | 指定proxy缓存临时文件的大小 |
第4章 Nginx负载均衡服务器搭建部署
4.1 逻辑架构图
所有用户的请求统一发送到Nginx负载均衡器上,然后由负载均衡器根据调度算法来请求web01和web02。
4.2 主机规划
主机名 | IP地址 | 说明 |
lb01 | 10.0.0.5 | Nginx主负载均衡器 |
lb02 | 10.0.0.6 | Nginx辅负载均衡器 |
web01 | 10.0.0.8 | web01服务器 |
web02 | 10.0.0.7 | web02服务器 |
web03 | 10.0.0.9 | web03服务器 |
4.3 负载均衡服务器部署
4.3.1 所有主机安装Nginx
此步骤省略,可参照《Nginx介绍》中的安装方法。
4.3.2 配置web服务器
[root@web01 ~]# vim /application/nginx/conf/nginx.conf #(web01和web02相同) worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; server { listen 80; server_name bbs.leon.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.leon.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } }
[root@web01 ~]# nginx -t nginx: the configuration file /application/nginx-1.10.3/conf/nginx.conf syntax is ok nginx: configuration file /application/nginx-1.10.3/conf/nginx.conf test is successful [root@web01 ~]# nginx -s reload
4.3.3 创建web服务器测试文件
[root@web01 ~]# mkdir -p /application/nginx/html/{www,bbs} #(web01和web02相同) [root@web01 ~]# for name in www bbs; do echo $name `hostname` >/application/nginx/html/$name/bingbing.html;done [root@web01 ~]# for name in www bbs; do cat /application/nginx/html/$name/bingbing.html;done www web01 bbs web01
4.3.4 配置web服务器hosts文件
[root@web01 ~]# tail -1 /etc/hosts 10.0.0.5 www.leon.com bbs.leon.com
4.3.5 配置Nginx负载均衡服务器
[root@lb01 ~]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream server_pools { #这里定义web服务器池,包含了web01和web02两个节点的IP信息 server 10.0.0.7:80; server 10.0.0.8:80; } server { #这里定义代理的负载均衡域名虚拟主机(通过此域名访问负载均衡服务器) listen 80; server_name bbs.leon.com; location / { proxy_pass http://server_pools; #访问bbs.leon.com请求将会发送给server_pools里面的节点 } } }
[root@lb01 ~]# nginx -t nginx: the configuration file /application/nginx-1.10.3/conf/nginx.conf syntax is ok nginx: configuration file /application/nginx-1.10.3/conf/nginx.conf test is successful [root@lb01 ~]# nginx -s reload
- 配置说明:
- 默认调度算法是weighted round-robin,即权重轮询算法
- upstream仅仅是定义服务器池,并不会直接处理用户的请求,必须要有其他方式将请求转给这个服务器池才行
- 节点服务器的虚拟主机都是根据访问的主机头字段区分的,所以服务器池名字可以自定义命名,不影响用户访问
4.3.6 配置lb01服务器和windows客户端hosts文件
- lb01服务器:
[root@lb01 ~]# tail -2 /etc/hosts 10.0.0.8 www.leon.com 10.0.0.7 bbs.leon.com [root@lb01 ~]# curl www.leon.com/bingbing.html www web01 [root@lb01 ~]# curl bbs.leon.com/bingbing.html bbs web02
- windows客户端:
C:\Windows\System32\drivers\etc\hosts 10.0.0.5 bbs.leon.com www.leon.com
4.3.7 进行负载均衡测试
[root@web01 ~]# for n in `seq 100`;do curl bbs.leon.com/bingbing.html;sleep 2;done bbs web02 bbs web01 bbs web02 bbs web01 bbs web02 ...省略部分输出... #每次请求都分别分发给web01和web02两台主机 bbs web01 #模拟web02主机宕机的情况,用户仍然可以继续访问,不影响使用 bbs web01 bbs web01 bbs web01 ...省略部分输出... bbs web01 #模拟宕机后的主机再次启动后用户的访问情况 bbs web02 bbs web01 bbs web02
4.4 反向代理多虚拟主机节点服务器企业案例
4.4.1 问题说明
上面的试验中,如果访问www.leon.com/bingbing.html返回的结果仍然是bbs web01,因为用户访问域名时确实是携带了www.leon.com主机头请求Nginx反向代理服务器,但是反向代理向下面节点重新发起请求时默认并没有在请求头里告诉节点服务器要找哪台虚拟主机,所以web节点服务器接收到请求后发现没有主机头信息,因此就把节点服务器的第一个虚拟主机发给了反向代理。解决方法是让反向代理向后重新发起请求时要携带主机头信息,明确告诉节点服务器要找哪台虚拟主机。
4.4.2 解决方案
[root@lb01 ~]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream server_pools { server 10.0.0.7:80; server 10.0.0.8:80; } server { listen 80; server_name bbs.leon.com; location / { proxy_pass http://server_pools; proxy_set_header Host $host; # 添加此行命令,在代理向后端服务器发送http请求头中加入 host字段信息 # 用于后端服务器配置有多个虚拟主机时可以识别代理的是哪个虚拟主机。 } } }
[root@lb01 ~]# nginx -t nginx: the configuration file /application/nginx-1.10.3/conf/nginx.conf syntax is ok nginx: configuration file /application/nginx-1.10.3/conf/nginx.conf test is successful [root@lb01 ~]# nginx -s reload
4.4.3 实验结果
[root@web01 ~]# for n in `seq 100`;do curl www.leon.com/bingbing.html;sleep 2;done www web02 www web01 www web02 www web01 ...省略部分输出... #返回www站点信息,结果正确 [root@web01 ~]# for n in `seq 100`;do curl bbs.leon.com/bingbing.html;sleep 2;done bbs web01 bbs web02 bbs web01 bbs web02 ...省略部分输出... #返回bbs站点信息,结果正确
4.5 反向代理后的节点服务器记录用户IP企业案例
4.5.1 问题说明
通过反向代理服务器访问的节点服务器中www虚拟主机的访问日志的第一个字段记录的并不是客户端的IP,而是反向代理服务器的IP,最后一个字段也是“-”。
[root@web01 ~]# tail -2 /application/nginx/logs/access_www.log 10.0.0.5 - - [15/Sep/2017:10:15:04 +0800] "GET /bingbing.html HTTP/1.0" 200 10 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-" 10.0.0.5 - - [15/Sep/2017:10:15:08 +0800] "GET /bingbing.html HTTP/1.0" 200 10 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "-"
4.5.2 解决方案
[root@lb01 ~]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream server_pools { server 10.0.0.7:80; server 10.0.0.8:80; } server { listen 80; server_name bbs.leon.com; location / { proxy_pass http://server_pools; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; # 在反向代理想后端服务器发送http请求头中加入X-Forwarded-For字段信息 # 用于后端服务器程序或日志等接受记录真实用户的IP,而不是代理服务器的IP。 } } }
提示:X-Forwarded-For详细说明:http://en.wikipedia.org/wiki/X-Forwarded-For。
4.5.3 实验结果
[root@web01 ~]# tail -2 /application/nginx/logs/access_www.log 10.0.0.5 - - [15/Sep/2017:10:32:05 +0800] "GET /bingbing.html HTTP/1.0" 200 10 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "10.0.0.8" #实际客户端IP信息已经记录 10.0.0.5 - - [15/Sep/2017:10:32:09 +0800] "GET /bingbing.html HTTP/1.0" 200 10 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "10.0.0.7" #实际客户端IP信息已经记录
4.6 反向代理配置相关参数说明
Nginx反向代理重要参数 | 解释说明 |
proxy_pass http://server_pools; | 通过proxy_pass功能把用户的请求转向到反向代理定义的upstream服务器池 |
proxy_set_header Host $host; | 在代理向后端服务器发送的http请求头中加入host字段信息,用于当后端服务器配置有多个虚拟主机时可以识别代理的是哪个虚拟主机,这是节点服务器多虚拟主机时的关键配置 |
proxy_set_header X-Forwarded-For $remote_addr; | 在代理向后端服务器发送的http请求头中加入X-Forwarded-For字段信息用于后端服务器程序、日志等接收真实用户的IP,而不是代理副武器的IP。这是反向代理时节点服务器获取用户真实IP的必要功能配置。 |
- 配置示例
[root@lb01 ~]# vim /application/nginx/conf/proxy.conf proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_connect_timeout 60; proxy_send_timeout 60; proxy_read_timeout 60; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; [root@lb01 ~]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream server_pools { server 10.0.0.7:80; server 10.0.0.8:80; } server { listen 80; server_name bbs.leon.com; location / { proxy_pass http://server_pools; include proxy.conf; #包含proxy.conf配置文件 } } }
提示:更多反向代理参数:http://nginx.org/en/docs/http/ngx_http_proxy_module.html。
第5章 根据URL中的目录地址实现代理转发
5.1 案例背景
通过Nginx实现动静态分离,即通过Nginx反向代理配置规则实现让动态资源和静态资源及其他业务分别由不同的服务器解析以解决网站性能、安全、用户体验等重要问题。
5.1.1 动静分离集群架构图
5.2 案例需求
- 当用户请求leon.com/upload/xx地址时,实现由upload上传服务器池处理请求
- 当用户请求leon.com/static/xx地址时,实现由静态服务器池处理请求
- 除此以外对于其他访问请求全部由默认的动态服务器池处理请求
5.3 案例实现
5.3.1 负载均衡服务器配置
5.3.1.1 方案一:以location方案实现
[root@lb01 ~]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream static_pools { server 10.0.0.7:80; } upstream upload_pools { server 10.0.0.8:80; } upstream default_pools { server 10.0.0.9:80; } server { listen 80; server_name www.leon.com; location / { proxy_pass http://default_pools; include proxy.conf; } location /static/ { proxy_pass http://static_pools; include proxy.conf; } location /upload/ { proxy_pass http://upload_pools; include proxy.conf; } } }
5.3.1.2 方案二:使用if语句实现
[root@lb01 nginx-1.10.3]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream static_pools { server 10.0.0.7:80; } upstream upload_pools { server 10.0.0.8:80; } upstream default_pools { server 10.0.0.9:80; } server { listen 80; server_name www.leon.com; location / { if ( $request_uri ~* "^/static(.*)$" ) { proxy_pass http://static_pools/static$1; break; } if ( $request_uri ~* "^/upload(.*)$" ) { proxy_pass http://upload_pools/upload$1; break; } proxy_pass http://default_pools; include proxy.conf; } } }
5.3.2 web服务器配置
- web01配置:
[root@web01 ~]# mkdir -p /application/nginx/html/www/upload [root@web01 ~]# echo "upload_pools" > /application/nginx/html/www/upload/index.html
- web02配置:
[root@web02 ~]# mkdir -p /application/nginx/html/www/static [root@web02 ~]# echo "static_pools" > /application/nginx/html/www/static/index.html
- web03配置:
[root@web03 tools]# echo "default_pools" > /usr/local/nginx/html/www/index.html
5.3.3 测试结果:
[root@m01 ~]# curl www.leon.com/upload/ upload_pools [root@m01 ~]# curl www.leon.com/static/ static_pools [root@m01 ~]# curl www.leon.com default_pools [root@m01 ~]# curl www.leon.com/index.html default_pools
第6章 根据客户端的设备(user_agent)转发
6.1 案例需求
企业中为了让不同的客户端设备用户访问有更好的体验,需要在后端架设不同服务器来满足不同的客户端访问。例如:移动客户端访问网站就需要部署单独的移动服务器及程序。
6.2 案例架构说明
6.2.1 常规4层负载均衡解决方案
在常规4层负载均衡架构下可以使用不同的域名来实现这个需求。此解决方案最大的问题是不同客户端的用户要记住对应的域名,影响用户体验。架构图如下:
图
6.2.2 第7层负载均衡解决方案
在第7层负载均衡架构下可以不需要认为拆分域名了,对外只需使用一个域名,然后通过获取用户请求中的设备信息(利用$http_user_agent获取),根据这些信息转给后端合适的服务器处理,这个方案最大好处就是不需要让用户记忆多个域名,提升了用户体验。
图
6.3 案例实现
6.3.1 负载均衡服务器配置
[root@lb01 ~]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream static_pools { server 10.0.0.7:80; } upstream upload_pools { server 10.0.0.8:80; } upstream default_pools { server 10.0.0.9:80; } server { listen 80; server_name www.leon.com; location / { if ($http_user_agent ~* "MSIE") { #客户端为IE则由static_pools处理 proxy_pass http://static_pools; } if ($http_user_agent ~* "chrome") { #客户端为Chrome则由upload_pools处理 proxy_pass http://upload_pools; } proxy_pass http://default_pools; #其他客户端为则由default_pools处理 include proxy.conf; } } }
6.4 实验结果
6.4.1 IE浏览器测试结果
6.4.2 Chrome测试结果
6.4.3 其他测试结果
[root@m01 ~]# curl www.leon.com/upload <html> <head><title>404 Not Found</title></head> <body bgcolor="white"> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.12.1</center> </body> </html> [root@m01 ~]# curl www.leon.com/static <html> <head><title>404 Not Found</title></head> <body bgcolor="white"> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.12.1</center> </body> </html> [root@m01 ~]# curl www.leon.com default_pools
6.4.4 测试结果说明
- 返回正常的网页说明相应的请求转发到了后端的服务器池中了
- 404错误说明没有匹配到任何规则,最终交给default_pools池服务器,但服务器站点内没有upload和static这两个目录及首页文件,所以显示404错误
- 403错误说明相应的upload服务器和static服务器站点www目录内没有首页文件,所以显示403错误
6.5 模拟不同版本客户端的方法
6.5.1 根据网站的访问日志查找客户端信息
可以根据日志中的$http_user_agent格式记录的日志信息查找对应的设备信息。如下:
10.0.0.5 - - [15/Sep/2017:11:31:25 +0800] "GET /upload/ HTTP/1.0" 200 13 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2" "10.0.0.61" # Linux curl命令 10.0.0.5 - - [15/Sep/2017:13:16:00 +0800] "GET /favicon.ico HTTP/1.0" 404 571 "http://www.leon.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36" "10.0.0.253" # Chrome浏览器 10.0.0.5 - - [15/Sep/2017:13:31:15 +0800] "GET /static/ HTTP/1.0" 404 571 "-" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Mobile Safari/537.36" "10.0.0.253" # Chrome 模拟的Android手机
6.5.2 使用curl命令模拟不同客户端设备
[root@m01 ~]# curl -A iphone -v www.leon.com * About to connect() to www.leon.com port 80 (#0) * Trying 10.0.0.5... connected * Connected to www.leon.com (10.0.0.5) port 80 (#0) > GET / HTTP/1.1 > User-Agent: iphone > Host: www.leon.com > Accept: */* > < HTTP/1.1 200 OK ...省略部分输出... [root@m01 ~]# curl -A chrome -v www.leon.com/upload/ * About to connect() to www.leon.com port 80 (#0) * Trying 10.0.0.5... connected * Connected to www.leon.com (10.0.0.5) port 80 (#0) > GET /upload/ HTTP/1.1 > User-Agent: chrome > Host: www.leon.com > Accept: */* > < HTTP/1.1 200 OK ...省略部分输出... [root@m01 ~]# curl -A MSIE -v www.leon.com/static/ * About to connect() to www.leon.com port 80 (#0) * Trying 10.0.0.5... connected * Connected to www.leon.com (10.0.0.5) port 80 (#0) > GET /static/ HTTP/1.1 > User-Agent: MSIE > Host: www.leon.com > Accept: */* > < HTTP/1.1 200 OK ...省略部分输出... [root@m01 ~]# curl -A andriod -v www.leon.com/index.html * About to connect() to www.leon.com port 80 (#0) * Trying 10.0.0.5... connected * Connected to www.leon.com (10.0.0.5) port 80 (#0) > GET /index.html HTTP/1.1 > User-Agent: andriod > Host: www.leon.com > Accept: */* > < HTTP/1.1 200 OK ...省略部分输出...
6.5.3 使用抓包的方式获取客户端信息
6.6 扩展:根据文件扩展名实现代理转发
根据文件扩展名实现代理转发与根据URI路径以及user_agent转发是相同的,因此不再测试。
6.6.1 应用场景
在开发无法通过程序实现动静分离的时候运维可以根据资源实体进行动静分离,而不依赖于开发,具体实现策略是先把后端的服务器分成不同的组,在前端代理服务器上通过讲解过的路径、扩展名进行规则匹配,从而实现请求的动静分离。
6.6.2 配置示例
[root@lb01 ~]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream static_pools { server 10.0.0.7:80; } upstream upload_pools { server 10.0.0.8:80; } upstream default_pools { server 10.0.0.9:80; } server { listen 80; server_name www.leon.com; location / { proxy_pass http://default_pools; include proxy.conf; } location ~ .*.(gif|jpg|jpeg|png|bmp|swf|css|js)$ { proxy_pass http://static_pools; include proxy.conf } location ~.*.(php|php3|php5)$ { proxy_pass http://upload_pools; include proxy.conf; } } }
第7章 Nginx负载均衡检测节点状态(鸡肋功能)
Nginx需要通过打补丁的方式将nginx_upstream_check_module模块添加进来,nginx_upstream_
check_module模块用于提供主动式后端服务器健康检查,通过它可以检测后端realserver的健康状态,如果后端realserver不可用,则所有的请求就不会转发到该节点上。
提示:补丁下载地址:https://github.com/yaoweibin/nginx_upstream_check_module。
7.1 安装nginx_upstream_check_module模块
7.1.1 安装Nginx软件
此步略。
7.1.2 下载解压补丁包
[root@lb01 tools]# wget https://codeload.github.com/yaoweibin/nginx_upstream_check_module/zip/ master [root@lb01 tools]# unzip nginx_upstream_check_module-master.zip
7.1.3 对源程序打补丁
[root@lb01 tools]# cd nginx-1.10.3 [root@lb01 nginx-1.10.3]# patch -p0 < ../nginx_upstream_check_module-master/check_1.9.2+.patch patching file src/http/modules/ngx_http_upstream_hash_module.c patching file src/http/modules/ngx_http_upstream_ip_hash_module.c patching file src/http/modules/ngx_http_upstream_least_conn_module.c patching file src/http/ngx_http_upstream_round_robin.c patching file src/http/ngx_http_upstream_round_robin.h
提示:需要根据nginx版本选择相应的补丁版本。
7.1.4 重新编译nginx源程序
[root@lb01 nginx-1.10.3]# ./configure --prefix=/application/nginx-1.10.3 --user=www --group=www --with-http_stub_status_module --with-http_ssl_module --add-module=../nginx_upstream_check_module-master/ [root@lb01 nginx-1.10.3]# make
7.1.5 备份并替换nginx执行文件
[root@lb01 objs]# nginx -s stop [root@lb01 nginx-1.10.3]# cp /application/nginx/sbin/nginx{,.bak} [root@lb01 nginx-1.10.3]# cp /server/tools/nginx-1.10.3/objs/nginx /application/nginx/sbin/ cp: overwrite `/application/nginx/sbin/nginx' y [root@lb01 objs]# nginx #启动新的nginx服务 [root@lb01 objs]# nginx -t #测试nginx服务是否正常 nginx: the configuration file /application/nginx-1.10.3/conf/nginx.conf syntax is ok nginx: configuration file /application/nginx-1.10.3/conf/nginx.conf test is successful [root@lb01 objs]# nginx -V #查看nginx是否为新编译的版本 nginx version: nginx/1.10.3 built by gcc 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC) built with OpenSSL 1.0.1e-fips 11 Feb 2013 TLS SNI support enabled configure arguments: --prefix=/application/nginx-1.10.3 --user=www --group=www --with-http_stub_status_module --with-http_ssl_module --add-module=../nginx_upstream_check_module-master/
提示:一定要停止nginx服务后再替换nginx程序文件,否则替换不会成功。
7.2 配置nginx健康检查
[root@lb01 conf]# vim /application/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream static_pools { server 10.0.0.7:80 weight=1; server 10.0.0.8:80 weight=2; check interval=3000 rise=2 fall=5 timeout=1000 type=http; } upstream default_pools { server 10.0.0.9:80 weight=1; check interval=3000 rise=2 fall=5 timeout=1000 type=http; } server { listen 80; server_name www.leon.com; location / { root html/www; index index.html index.htm; proxy_pass http://default_pools; include proxy.conf; } location ~* .*.(gif|jpg|jpeg|png|bmp|swf|css|js)$ { proxy_pass http://static_pools; include proxy.conf; } location /status { check_status; } } } [root@lb01 ~]# nginx -s stop [root@lb01 ~]# nginx
注意:此处必须对nginx进行重启,不能采用平滑重启的方式,否则监控异常。
- 命令说明:
- interval=3000:对负载均衡条目中的所有节点每隔3秒检测一次
- rise=2:请求2次正常则标记realserver状态为up
- fall=5:如果检测5次都失败则标记realserver的状态为down
- timeout=1000:超时时间为1秒
- type=http:检查的协议是HTTP
提示:详细用法参见:http://tengine.taobao.org/document_cn/http_upstream_check_cn.html。
7.3 测试结果
提示:经测试此功能不支持1.10.3版本的nginx服务器。
