- 前言
- 读者对象
- 如何阅读本书
- 勘误和支持
- 致谢
- 第 1 篇 高性能网站构建
- 第 1 章 深入理解 DNS 原理与部署 BIND
- 第 2 章 全面解析 CDN 技术与实战
- 第 3 章 负载均衡和高可用技术
- 第 4 章 配置及调优 LVS
- 第 5 章 使用 HAProxy 实现 4 层和 7 层代理
- 第 6 章 实践 Nginx 的反向代理和负载均衡
- 第 7 章 部署商业负载均衡设备 NetScaler
- 第 8 章 配置高性能网站
- 第 9 章 优化 MySQL 数据库
- 第 2 篇 服务器安全和监控
- 第 10 章 构建企业级虚拟专用网络
- 第 11 章 实施 Linux 系统安全策略与入侵检测
- 第 12 章 实践 Zabbix 自定义模板技术
- 第 13 章 服务器硬件监控
- 第 3 篇 网络分析技术
- 第 14 章 使用 tcpdump 与 Wireshark 解决疑难问题
- 第 15 章 分析与解决运营商劫持问题
- 第 16 章 深度实践 iptables
- 第 4 篇 运维自动化和游戏运维
- 第 17 章 使用 Kickstart 完成批量系统安装
- 第 18 章 利用 Perl 编程实施高效运维
- 第 19 章 精通 Ansible 实现运维自动化
- 第 20 章 掌握端游运维的技术要点
- 第 21 章 精通手游运维的架构体系
最佳实践 27:安装与优化
HAProxy 的安装过程比较简单,参照如下命令:
wget http://www.haproxy.org/download/1.5/src/haproxy-1.5.15.tar.gz tar zxvf haproxy-1.5.15.tar.gz cd haproxy-1.5.15 make TARGET=linux26 make install
前一小节讲到 HAProxy 同时支持对 TCP 和 HTTP 的负载均衡,那就先从对 TCP 的负载均衡开始实践。
HAProxy TCP 负载均衡
HAProxy 的 TCP 负载均衡方式,与第 4 章中提到 LVS 的 3 种模式均不同。
- HAProxy 不要求后端服务器的网关指向负载均衡器的内网地址,在 LVS-NAT 模式下,该配置为必须。
- HAProxy 不要求后端服务器和负载均衡处于同一个网段,在 LVS-DR 模式下,这个是前提条件。
- HAProxy 不要求后端服务器配置 IPIP 隧道,这个与 LVS-Tun 模式不同。
- HAProxy 仅仅要求后端服务器能够在网络上连通,可以跨网段。
本次配置实现的架构图如图 5-1 所示。
图 5-1 HAProxy TCP 负载均衡架构图
在 HAProxy 安装完成后,启用 haproxy.cfg 进行配置,如下所示:
# cat /etc/haproxy/haproxy.cfg global daemon maxconn 50000 defaults mode http listen www bind 0.0.0.0:80 mode tcp #注意,此处是 tcp server s1 10.1.6.21:80 #后端服务器 1 的 IP 和端口 server s2 10.1.6.44:80 #后端服务器 2 的 IP 和端口
在测试机器上使用 curl 命令测试,2 台后端服务器都会被访问到。使用命令如下:
# curl http://10.1.6.28/index.html web1 # curl http://10.1.6.28/index.html web2
HAProxy HTTP 负载均衡
HTTP 负载均衡的架构图和图 5-1 相同,基于 7 层负载均衡,要求实现以下功能。
- 请求域名 www1.example.com 的访问调度到 web1。
- 请求域名 www2.example.com 的访问调度到 web2。
本案例中使用到的配置文件内容如下:
global daemon maxconn 50000 log 127.0.0.1 local0 uid 99 gid 99 pidfile /var/run/haproxy-private.pid chroot /var/empty #chroot 增加系统安全性 frontend public bind 0.0.0.0:80 mode http #注意,此处是 http log global timeout http-request 3s #客户端必须在 3s 内传输完成请求 timeout http-keep-alive 3s #和客户端的 keep-alive 时间 timeout client 10s #和客户端的连接保活超时 option httplog option forwardfor #使用 X-Forwarded-For 向后端服务器传递客户端来源 IP option dontlognull option http-keep-alive #使用 keep-alive,减少对后端服务器的连接数 capture request header Host len 30 #日志中记录 Host 头部 capture request header Referer len 60 #日志中记录 Referer #以下 5 行配置,使 HAProxy 根据请求里面的 Host 字段进行负载均衡 acl www1_example_com hdr_beg(host) -i www1.example.com use_backend backend_www1_example_com if www1_example_com acl www2_example_com hdr_beg(host) -i www2.example.com use_backend backend_www2_example_com if www2_example_com default_backend backend_www1_example_com backend backend_www1_example_com mode http #模式为 http balance source #使用基于源地址的分配方法 cookie appsession insert indirect preserve timeout http-request 3s timeout http-keep-alive 3s timeout connect 1s timeout server 10s timeout check 500ms option redispatch #后端服务器故障时,重新分发请求 option http-keep-alive option httpchk GET /test.html HTTP/1.1\r\nHost:\ www1.example.com #基于 http 的监控检查方法 http-check expect string ok retries 2 server www1_example_com_srv1 10.1.6.21:80 cookie b1 weight 8 check inter 2s rise 3 fall 5 stats enable #HAProxy 状态监控使用 stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin:6w5_xbkRGU backend backend_www2_example_com mode http balance source cookie appsession insert indirect preserve timeout http-request 3s timeout http-keep-alive 3s timeout connect 1s timeout server 10s timeout check 500ms option redispatch option http-keep-alive option httpchk GET /test.html HTTP/1.1\r\nHost:\ www2.example.com http-check expect string ok retries 2 server www2_example_com_srv1 10.1.6.44:80 cookie b2 weight 8 check inter 2s rise 3 fall 5 stats enable stats scope . stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin:6w5_xbkRGU
注意
默认 HAProxy 会把日志记录到/var/log/messages 文件,本例配置中它单独记录到/app/logs/haproxy.log 中。
配置 HAProxy 把访问日志记录到/app/logs/haproxy.log 需要执行以下操作:
# /etc/sysconfig/syslog ==> SYSLOGD_OPTIONS="-r -m 0" # /etc/syslog.conf ==> local0.* # chown nobody.nobody /app/logs/haproxy.log # /etc/init.d/syslog restart
HAProxy 的核心配置参数
HAProxy 的核心配置参数如下:
1)mode{tcp|http|health}:设置该实例运行的协议。可配置的值有如下几个。
- tcp:该实例运行在纯 TCP 模式,在客户端和服务器之间建立一个全双工的通道,不会进行任何 7 层的内容检查,为默认值。在负载均衡 SMTP 和 SSH 等时,必须使用该模式。
- http:该实例运行在 HTTP 模式,在被调度到后端服务器之前,客户端的请求会被深度分析,任何不符合 RFC 兼容的请求都被拒绝掉。可以实现 7 层过滤、处理、内容交换。在这种模式下,HAProxy 可以发挥最大的价值。
2)balance<algorithm>[<arguments>]:负载均衡算法。
- <algorithm>:是在选择一台后端服务器时使用到的算法。在没有其他可以作为持久连接的信息时,使用该算法进行调度。一般用到以下有的几个。
- roundrobin:轮询。
- static-rr:轮询,在线修改权重时不生效。
- leastconn:最小连接数。
- first:有可用连接的服务器组里面选择一台后端服务器(没有达到 maxconn 的)。先让一台达到 maxconn,然后再使用另外一台没达到的。
- source:基于客户端来源的哈希。
- uri:根据 uri 的部分或者完整 uri 进行哈希。
3)acl:HAProxy 的配置里面,最能体现灵活性的地方是 ACL(Access Control List,访问控制链),配置指令是 acl。ACL 的使用,提供了一个灵活的方法,根据从请求、响应或者任何环境状态里面解析出来的内容来实现内容交换和做决策(比如丢弃、变换或转发等)。
在该指令(acl)中,我们可以指定使用如下规则予以匹配需要特殊处理的请求:
- 3 层网络层的匹配:dst,src 目的 IP 和源 IP。
- 4 层 TCP 的匹配:dst_port,src_port 目的端口和源端口。
- 7 层应用层信息匹配:req.hdr([<name>[,<occ>]])匹配 HTTP 请求里面的 Header 字段。例如 req.hdr(Host)则匹配 HTTP 请求 Header 里面的 Host 字段。
HAProxy 的会话保持机制
会话保持,是指在应用中,保证同一个客户端的连续的请求被持续地调度到一台后端服务器的过程。在以下业务场景中需要用到此种技术。
- 购物车。里面存储了客户端已确认购买的商品列表,需要由同一台后端服务器进行处理。
- 访问登录后的内容。接受客户端登录的服务器上存储了其临时信息作为有效性的判断,后续的请求必须调度到同一台后端服务器,否则可能被其他后端服务器检测为未登录状态。
HAProxy 有 2 种基本的方法。
- 使用基于源地址的负载调度算法。配置指令是:
balance source
- 使用基于 cookie 的技术。配置指令是:
cookie appsession insert indirect preserve
这个是什么意思呢?举个例子。
假设李三(客户端)第一次到派出所办事(需要访问业务),到了办事大厅之后,引导员(HAProxy)根据李三要办理的业务内容,将李三的业务提交给了一个民警 X(后端服务器),民警完成后把处理结果给了引导员(处理结果),引导员看到李三第一次来,就额外给了李三一个令牌,是一个字符串(cookie);下次李三再来办理业务的时候,出具了该令牌,则引导员可以迅速判断是由原来的民警 X 来处理他的业务。
这样就保持了会话的连续性。下面来看具体指令。
appsession 是指 HAProxy 在第一次响应中插入到后端服务器给客户端的响应里面的 cookie 名字。
insert 是指如果 HAProxy 没有在用户的请求中发现该 cookie,那么在后端服务器给客户端的响应中,它会加入该 cookie。如果没有和 preserve 联合使用,那么后端服务器发送的响应中若有相同名字(appsession)的 cookie,则同名 cookie 会被删除,这就可能导致问题。
indirect 是指如果 HAProxy 发现客户端已经有该名字(appsession)的 cookie,则不操作;如果和 insert 合用,在向后端服务器转发请求的时候,会把该名字(appsession)的 cookie 删除,此时对后端服务器端完全透明。
preserve 与 insert 和/或 indirect 合用,使得后端服务器发送该名字(appsession)的 cookie 时不被 HAProxy 删除或者替换掉。
理解 HAProxy 的会话保持机制,在进行排查问题时具有很重要的作用。
下面看一下效果:
# wget -S --header="Host: www1.example.com" http://10.1.6.18/index.html --2015-12-07 15:32:58-- http://10.1.6.18/index.html Connecting to 10.1.6.18:80... connected. HTTP request sent, awaiting response... HTTP/1.1 200 OK Server: nginx/0.8.55 Date: Mon, 07 Dec 2015 07:32:58 GMT Content-Type: text/html Content-Length: 5 Last-Modified: Mon, 30 Nov 2015 09:53:22 GMT Accept-Ranges: bytes Set-Cookie: appsession=b1; path=/ #注意该行,即是 HAProxy 插入的 cookie。作为客户端后续请求选择后端服务器的依据 Connection: close Length: 5 [text/html] Saving to: `index.html' 100%[================================================================================================================================================================>] 5 --.-K/s in 0s 2015-12-07 15:32:58 (610 KB/s) - `index.html' saved [5/5]
HAProxy 中 ip_local_port_range 问题
前面的章节使用 HAProxy 配置了两种模式的负载均衡:TCP 和 HTTP。在这两种模式下,都需要注意负载均衡器上的 ip_local_port_range 问题。
HAProxy 在 TCP 和 HTTP 负载均衡时,都是使用本机的 TCP 端口作为源端口、本机的 IP 地址作为源地址向后端服务器进行转发。此时,请注意单个 IP 可以使用到的 TCP 源端口号是有限制的,使用如下命令可以看到当前服务器配置的范围:
# sysctl net.ipv4.ip_local_port_range net.ipv4.ip_local_port_range = 32768 61000 #单个 IP 可以使用的 TCP 端口范围是 32768 到 61000
在代理了多台(如 20 台以上)后端服务器并且并发访问量比较大时,需要注意该参数。如果负载均衡器对后端服务器发起的 TCP 连接数过多,则可能导致负载均衡器本地端口用光(使用 netstat 统计),无法向后端服务器建立新的 TCP 连接导致负载均衡失败。
使用如下命令修改该参数的值,增加可用端口号:
echo 1024 61000 > /proc/sys/net/ipv4/ip_local_port_range
在 sysctl.conf 中进行修改,以便在服务器重启后依然有效:
# echo "net.ipv4.ip_local_port_range=1024 61000" >> /etc/sysctl.conf
HAProxy 后端服务器获取客户端 IP
虽然 HAProxy 支持 TCP 和 HTTP 的负载均衡,但这 2 种方式在网络层面,无法使得后端服务器直接获取到客户端的 IP,后端服务器上看到的来源 IP 是 HAProxy 的内网 IP。
后端服务器的程序在审计需要或者需要对来源 IP 做某些限制时,怎么才能获取到客户端的 IP 呢?
通常的做法是配置如下命令:
option forwardfor
此时,后端服务器可以使用分析请求中的 X-Forwarded-For 字段来解析客户端来源 IP。
在 PHP 中的代码如下:
$_SERVER["HTTP_X_FORWARDED_FOR"]
TCP 负载均衡和 HTTP 负载均衡的对比
对于同一个负载均衡的需求,配置 HAProxy 分别使用 TCP 和 HTTP 的方式进行了负载均衡转发,从结果上看是相同的,但在 HAProxy 内部的实现上,是否完全相同呢?
先看看 TCP 方式下,HAProxy 上的网络行为(文件:HAProxy_TCP.pcap,Frame 23、24、25)如图 5-2 所示。
图 5-2 HAProxy TCP 负载均衡网络行为
客户端在和 HAProxy 完成 3 次握手(Frame 23、24、25)建立了 TCP 连接后,HAProxy 立即向后端发送了 SYN 包(Frame 26),要求和其选择的后端服务器建立 TCP 连接。
在 HTTP 模式下,HAProxy 上的网络行为(文件:HAProxy_HTTP.pcap,Frame 58、59、60)如图 5-3 所示。
图 5-3 HAProxy HTTP 负载均衡网络行为
客户端在和 HAProxy 完成 3 次握手(Frame 58、59、60)建立了 TCP 连接,客户端发送了 TCP Data(Frame 61),也就是 HTTP 请求后,HAProxy 才开始向后端服务器发送 SYN 包(Frame 62),要求建立 TCP 连接。
在应用实践中,如基于 HTTP 的应用,一般建议使用 HTTP 模式进行调度,这样,可以对后端服务器进行更精确的调度,比如使用 Host 头部、URI 规则等,都可以作为调度的匹配依据。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论