本文目录:
1. 配置 haproxy 需要考虑的事情
2. 配置 haproxy 提供反向代理功能
haproxy 是一个非常优秀的负载均衡工具, 它的特性非常丰富, 功能也非常非常强大, 要想好好使用它, 将它的功能和性能挖掘出来, 多多阅读官方手册是必不可少的
本文提供一个简单的配置示例, 后面将分别开文章详细解释它的配置文件 cookie 会话保持 stick table 的功能 haproxy 主主模型的复制 (replication) 抵御攻击等等
1. 配置 haproxy 需要考虑的事情
尽管 haproxy 大多数配置选项都可以采用默认配置, 但有些选项, 特别是关于实际需求连接数和超时时间相关的选项必须独立配置
大致总结了下以下几点需要考虑的问题:
haproxy 支持 5 种 http 事务模型一般只会选择其中两种:
(1). 当后端为静态 web 或静态缓存服务器时, 使用 http-keep-alive 模型, 由于响应速度快, 频繁建立 tcp 连接的代价比较大;
(2). 当后端为动态应用程序服务器或者静态但传输的资源对象体积较大时, 使用 http-server-close 模型, 因为响应速度相对较慢, 占用空闲连接的资源比建立 tcp 连接的代价更大
haproxy 反向代理的调度算法优先级是低于 cookie 的, 因此当一个连接已经保持了会话, 调度算法对该连接就无效只有新的连接请求或者长连接已经失效时, 才会使用调度算法进行调度在调度算法的选择上, 如果不考虑服务器性能差距的话:
(1). 如果后端会话时间比较长(mysql), 建议使用 leastconn, 因为调度过程中, 后端释放连接时动荡不大, 比较稳定
(2). 如果后端是静态 web, 建议使用 roundrobin 算法
(3). 如果后端需要保持会话信息, 但又不使用 cookie 时, 可以使用源地址 hash 算法 source, 保证将同一客户端引导到同一后端服务器上如果使用 cookie, 则可以使用 roundrobin 或 leastconn 算法源地址 hash 算法, 一般只在没有办法的时候但又要调度到同一后端服务器时, 才作为最后手段
(4). 如果配置了 session 共享, 则对于 haproxy 来说, 动态资源的请求是 "无状态" 的, 可以使用 roundrobin 算法或 leastconn
(5). 如果后端是缓存服务器, 为了保证命中率, 建议使用 uri 算法, 同时将 hash-type 设置为 consistent 方法(一致性 hash), 保证后端缓存服务器 down 掉后对客户端的影响足够小
haproxy 是单进程事件驱动模型的软件, 单进程下工作效率已经非常好, 不建议开启的多进程 / 多实例
maxconn 指令控制最大并发连接数, 可以在多处设置, 设置位置不同, 代表意义不同:
(1). 设置在 global 段或 frontend/listen/defaults 段的 maxconn 代表的是和客户端 (即 frontend) 的最大连接并发数; 其中 global 段的值是硬限制, frontend/listen/defaults 段的 maxconn 值不能超过 global 段的值
(2). 设置在 server 指令中时, 代表的是 haproxy 和某台后端服务器维持的最大并发连接数
(3). 前端的最大并发数 (即 global 段的 maxconn) 可以根据内存来估算, haproxy 为每个连接维持两个缓存区, 每个大致 16K 左右, 加上一些额外数据, 共约 33-34K 左右, 因此理论上 1G 的空闲内存能维持 2W-2.5W 个纯 HTTP 的并发连接(只是理论上), 如果代理的是 https, 则允许的最大并发数量要小的多前端 maxconn 默认值为 2000, 非常有必要将其增加几倍一般代理纯 http 服务时, 如果后端能处理及时, 这里设置 20000 以上都不会有什么问题以上只是大致估算代理能力, 实际设置时必须根据后端处理能力以及 haproxy 自身能力设置前端 maxconn, 否则将前端接进来后端也无法立即处理
(4). 后端所有服务器的 maxconn 值之和应接近前端的 maxconn 值, 计算两者差距时, 还需要考虑后端的等待队列长度 maxqueue 其中和静态 web 服务器的 maxconn 可以设置大一些
开启 haproxy 和后端的连接重用功能当某客户端的请求到来后, haproxy 和后端某服务器建立一个 TCP 连接, 并将请求调度到该服务器上, 该客户端后续的请求也会通过该 TCP 连接转发给后端 (假设没有采用关闭后端连接的 http 事务模型) 但在响应后和该客户端的下一个请求到来前, 这个连接是空闲的和后端建立的 TCP 连接只是为了调度转发, 保证持有合适 cookie 的客户端请求能调度到同一后端, 完全可以为其它客户端的请求调度也使用这个 TCP 连接, 保证 TCP 连接资源不浪费可以使用
http-reuse strategy_name
指令设置连接重用的策略, 而默认策略禁用连接重用
(1).never: 这是默认设置表示禁用连接重用, 因为老版本的 haproxy 认为来源不同的请求不应该共享同一个后端连接
(2).safe: 这是建议使用的策略 "安全" 策略下, haproxy 为客户端的每个第一个请求都单独建立一个和后端的 TCP 连接, 但是后续的请求则会重用和该后端的空闲 TCP 连接这样的转发不仅提高了资源使用率, 还保持了 keep-alive 的功能因此, safe 策略配合 http-keep-alive 事务模式比 http-server-close 事务模式更高效, 无论后端是静态缓存还是动态应用服务器
(3).aggressive: 一种激进的策略, 该策略的 haproxy 会重用空闲 TCP 连接来转发大多数客户端的第一次请求之所以是大多数而不是所有, 是因为 haproxy 会挑选那些已经被重用过至少一次的连接 (即从建立开始转发过至少两次, 不管源是否是同一客户端) 进行重用, 因为 haproxy 认为只有这样的连接才具有重用能力
(4).always: 它将总是为第一个请求重用空闲连接当后端是缓存服务器时, 这种策略比 safe 策略的性能要高许多, 因为这样的请求行为都是一样的, 且可以共享同一连接来获取资源不过不建议使用这种策略, 因为大多数情况下, 它和 aggressive 的性能是一样的, 但是却带来了很多风险
因此, 为了性能的提升, 将它设置为 safe 或 aggressive 吧, 同时再将 http 事务模型设置为 http-keep-alive
对于 haproxy 是否开启 cookie 以及 stick table 相关功能的设置必须严加考虑, 它直接影响调度算法的选择和负载均衡的性能不过如果后端应用程序服务器共享了 session,haproxy 可以不用设置会话粘性相关的选项
haproxy 的默认配置文件中关于超时时间的设置应该修改, 不少项设置都很不合理
建议开启 haproxy 的 X-Forwarded-For 选项, 使得后端服务器能够记录客户端的真实源 IP 地址
建议开启 haproxy 的状态页面, 并设置访问权限
为了实现 Haproxy 完善的功能, 上面几个问题是远远不够的, 但可以在边使用 haproxy 过程中边增加功能使其不断完美
2. 配置 haproxy 提供反向代理功能
假如要实现这样的环境: haproxy 反向代理 4 个 nginx 节点, nginx1 和 nginx2 结合 php 提供动态 web 服务, nginx3 和 nginx4 提供静态 web 服务如下图:
由于默认配置文件中和超时时间相关的设置比较不合理, 所以建议修改这些时间另外还有些建议开启或关闭的的项也尽量开启或关闭
默认配置如下:
- global
- log 127.0.0.1 local2 # 需要设置 / etc/rsyslog.conf 加上 local2 设备的日志记录级别和日志路径
- chroot /var/lib/haproxy
- pidfile /var/run/haproxy.pid
- maxconn 4000 # 这是前段对外的最大连接数代理 http 时, 1G 空闲内存承载 20000 以上没大问题
- user haproxy
- group haproxy
- daemon
- stats socket /var/lib/haproxy/stats # 开启动态查看管理 haproxy 的状态文件
- # 另外建议设置 spread-checks 全局项, 且百分比建议为 2-5 之间
- defaults
- mode http # 7 层 http 代理, 另有 4 层 tcp 代理
- log global
- option httplog # 在日志中记录 http 请求 session 信息等
- option dontlognull # 不要在日志中记录空连接
- option http-server-close # 后端为动态应用程序建议使用 http-server-close, 后端为静态建议使用 http-keep-alive
- option forwardfor except 127.0.0.0/8 # haproxy 将在发往后端的请求中加上 "X-Forwarded-For" 首部字段
- option redispatch # 当某后端 down 掉使得 haproxy 无法转发携带 cookie 的请求到该后端时, 将其转发到别的后端上
- timeout http-request 10s # 此为等待客户端发送完整请求的最大时长, 应该设置较短些防止洪水攻击, 如设置为 2-3 秒
- # haproxy 总是要求一次请求或响应全部发送完成后才会处理转发,
- timeout queue 1m # 请求在队列中的最大时长, 1 分钟太长了设置为 10 秒都有点长, 10 秒请求不到资源客户端会失去耐心
- timeout connect 10s # haproxy 和服务端建立连接的最大时长, 设置为 1 秒就足够了局域网内建立连接一般都是瞬间的
- timeout client 1m # 和客户端保持空闲连接的超时时长, 在高并发下可稍微短一点, 可设置为 10 秒以尽快释放连接
- timeout server 1m # 和服务端保持空闲连接的超时时长, 局域网内建立连接很快, 所以尽量设置短一些, 特别是并发时, 如设置为 1-3 秒
- timeout http-keep-alive 10s # 和客户端保持长连接的最大时长优先级高于 timeout http-request 高于 timeout client
- timeout check 10s # 和后端服务器成功建立连接后到最终完成检查的时长(不包括建立连接的时间, 只是读取到检查结果的时长),
- # 可设置短一点, 如 1-2 秒
- maxconn 3000 # 默认和前段的最大连接数, 但不能超过 global 中的 maxconn 硬限制数
所以修改后建议配置为如下:
- global
- log 127.0.0.1 local2
- chroot /var/lib/haproxy
- pidfile /var/run/haproxy.pid
- maxconn 20000
- user haproxy
- group haproxy
- daemon
- stats socket /var/lib/haproxy/stats
- spread-checks 2
- defaults
- mode http
- log global
- option httplog
- option dontlognull
- option http-server-close
- option forwardfor except 127.0.0.0/8
- option redispatch
- timeout http-request 2s
- timeout queue 3s
- timeout connect 1s
- timeout client 10s
- timeout server 2s
- timeout http-keep-alive 10s
- timeout check 2s
- maxconn 18000
- frontend http-in
- bind *:80
- mode http
- log global
- capture request header Host len 20
- capture request header Referer len 60
- acl url_static path_beg -i /static /images /stylesheets
- acl url_static path_end -i .jpg .jpeg .gif .png .ico .bmp .CSS .js
- acl url_static path_end -i .html .htm .shtml .shtm .pdf .mp3 .mp4 .rm .rmvb .txt
- acl url_static path_end -i .zip .rar .gz .tgz .bz2 .tgz
- use_backend static_group if url_static
- default_backend dynamic_group
- backend static_group
- balance roundrobin
- option http-keep-alive
- http-reuse safe
- option httpchk GET /index.html
- http-check expect status 200
- server staticsrv1 192.168.100.62:80 check rise 1 maxconn 5000
- server staticsrv2 192.168.100.63:80 check rise 1 maxconn 5000
- backend dynamic_group
- cookie appsrv insert nocache
- balance roundrobin
- option http-server-close
- option httpchk GET /index.php
- http-check expect status 200
- server appsrv1 192.168.100.60:80 check rise 1 maxconn 3000 cookie appsrv1
- server appsrv2 192.168.100.61:80 check rise 1 maxconn 3000 cookie appsrv2
- listen report_stats
- bind *:8081
- stats enable
- stats hide-version
- stats uri /hastats
- stats realm "pls enter your name"
- stats auth admin:admin
- stats admin if TRUE
上面的配置中:
(1). 静态请求将分配给 static_group 并进行 roundrobin 调度, 同时通过获取 index.html 来做健康状况检查, 此外还设置了 haproxy 和后端连接重用的功能
(2). 动态请求将分配给 dynamic_group 并进行 roundrobin 调度, 但是向响应报文中插入了一个 cookie, 保证被调度过的服务端和客户端能保持会话此外还设置了通过获取 index.php 来做健康状况检查
最后配置 nginx 和 php+php-fpm
yum -y install nginx php php-fpm
为了区分, 分别为 nginx1/nginx2 的 index.phpnginx3/nginx4 的 index.html 文件中加入响应的主机来源提示, 并在 php 文件中设置 cookie 项其中 index.php 的内容参考如下:
- <h1>response from webapp 192.168.100.60</h1>
- <?php
- session_start();
- echo "Server IP:"."<font color=red>".$_SERVER['SERVER_ADDR']."</font>"."<br>";
- echo "Server Name:"."<font color=red>".$_SERVER['SERVER_NAME']."</font>"."<br>";
- echo "SESSIONNAME:"."<font color=red>".session_name()."</font>"."<br>";
- echo "SESSIONID:"."<font color=red>".session_id()."</font>"."<br>";
- ?>
测试其中 php 页面返回内容大致如此:
回到 Linux 系列文章大纲: http://www.cnblogs.com/f-ck-need-u/p/7048359.html
回到网站架构系列文章大纲: http://www.cnblogs.com/f-ck-need-u/p/7576137.html
回到数据库系列文章大纲: http://www.cnblogs.com/f-ck-need-u/p/7586194.html
来源: https://www.cnblogs.com/f-ck-need-u/p/8540805.html