本文最后更新于:2023年12月5日 晚上
web 架构介绍
单机房架构
多机房架构
公有云架构
私有云架构
负载均衡
负载均衡:Load Balance,简称 LB
负载均衡类型
四层(传输层):LVS、Nginx(1.9 之后)、HAProxy
LVS 是集成在内核中的功能,真四层;Nginx 和 HAProxy 是用户空间的软件,伪四层
七层(应用层):Nginx、HAProxy
硬件:F5、Netscaler、Array、深信服、北京灵州
大公司都用 F5
应用场景
企业生产环境中,每天会有很多的需求变更,比如增加服务器、新业务上线、url 路由修改、域名配置等等,对于前端负载均衡设备来说,容易维护,复杂度低,是首选指标
LVS 性能最高,最稳定,但是只支持四层负载 ,百万级并发
HAProxy 四层负载和七层代理都支持,如果只做反向代理,推荐 HAProxy,功能丰富,方便管理,万级并发
Nginx 的功能基于模块实现,HAProxy 有的功能 Nginx 都有,小型系统可以使用 Nginx
HAProxy
C 语言开发,高性能的 TCP 和 HTTP 负载均衡器,支持基于 cookie 的持久性,自动故障切换,支持正则表达式及 web 状态统计,目前最新 TLS 版本为 2.2
分为企业版和社区版
- TCP 和 HTTP 反向代理
- SSL/TSL 服务器
- 可以针对 HTTP 请求添加 cookie,进行路由后端服务器
- 可平衡负载至后端服务器,并支持持久连接
- 支持所有主服务器故障切换至备用服务器
- 支持专用端口实现监控服务
- 支持停止接受新连接请求,而不影响现有连接
- 可以在双向添加,修改或删除 HTTP 报文首部
- 响应报文压缩
- 支持基于 pattern 实现连接请求的访问控制
- 通过特定的 URI 为授权用户提供详细的状态信息
HAProxy 安装
yum 或者 apt 安装的版本较老,推荐编译安装
HAProxy 支持基于 Lua 实现功能扩展
编译安装 Lua:
编译安装 HAProxy:
http://www.haproxy.org/ # 优先下载 LTS 版
http://www.haproxy.org/download/
配置文件
查看配置文件示例:
创建自定义的配置文件:
HAProxy 的配置文件 haproxy.cfg 由两大部分组成,分别是 global 和 proxies 部分
以下列举的是部分配置,官方文档:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html
global
HAproxy 本身不记录客户端的访问日志,此外为减少服务器负载,一般生产中 HAProxy 不记录日志
defaults
default-server 指定后端服务器的默认配置,以下是主要配置项:
注意:HAProxy server 的 weight 和 Nginx server 的 weight 表示的意义是一样的,和 Keepalived real_server 的 weight 表示的意义不一样
frontend
backend
listen
使用子配置文件保存配置
按业务分类,将配置信息拆分,放在不同的子配置文件中,从而达到方便维护的目的
注意:配置文件必须为 cfg 后缀非.开头
因为没有类似include
的指令引入子配置,所以要在启动命令上指定子配置文件
systemctl 启动文件
HAProxy 调度算法
官方文档:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#4-balance
HAProxy 的调度算法分为静态和动态两种:
- 静态算法:按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、连接数和响应速度等,且无法实时修改权重(只能为 0 和 1,不支持其它值),只能靠重启 HAProxy 生效
- 动态算法:基于后端服务器状态进行调度适当调整,优先调度至当前负载较低的服务器,且权重可以 haproxy 运行时动态调整无需重启
静态算法
static-rr
基于权重的轮询调度,不支持运行时利用 socat 进行权重的动态调整(只支持 0 和 1)及后端服务器慢启动,其后端主机数量没有限制,相当于 LVS 中的 wrr
first
根据服务器在列表中的位置,自上而下进行调度,但是其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务,因此会忽略服务器的权重设置,此方式使用较少
不支持用 socat 进行动态修改权重,可以设置 0 和 1
动态算法
socat 工具
Socat 是 Linux 下的一个多功能的网络工具,名字来由是 「Socket CAT」。其功能与有瑞士军刀之称的 Netcat 类似,可以看做是 Netcat 的加强版。
Socat 的主要特点就是在两个数据流之间建立通道,且支持众多协议和链接方式。如 IP、TCP、 UDP、IPv6、PIPE、EXEC、System、Open、Proxy、Openssl、Socket 等。
这里利用 socat 工具,对服务器动态权重和其它状态进行调整
socat stdio:对文件进行标准写入和标准读取
一个进程就有一个 haproxy.socket 文件,以上的操作针对的都是单进程
roundrobin
基于权重的轮询动态调度算法,支持权重的运行时调整,不同于 lvs 中的 rr 轮训模式,HAProxy 中的 roundrobin 支持慢启动(新加的服务器会逐渐增加转发数),其每个后端 backend 中最多支持 4095 个 real server,支持对 real server 权重动态调整,roundrobin 为默认调度算法,此算法使用广泛
支持动态调整权重:
leastconn
leastconn 加权的最少连接的动态,支持权重的运行时调整和慢启动,即根据当前连接最少的后端服务器而非权重进行优先调度(新客户端连接),比较适合长连接的场景使用,比如:MySQL 等场景
random
1.9 版本增加,负载平衡算法,其基于随机数作为一致性 hash 的 key,随机负载平衡对于大型服务器场或经常添加或删除服务器非常有用,支持 weight 的动态调整,weight 较大的主机有更大概率获取新请求
其他算法
其它算法即可作为静态算法,又可以通过选项成为动态算法
source
源地址 hash,基于用户源地址 hash 并将请求转发到后端服务器,后续同一个源地址请求将被转发至同一个后端 web 服务器。此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服务器,默认为静态方式,但是可以通过 hash-type 支持的选项更改
这个算法一般是在不插入 Cookie 的 TCP 模式下使用,也可给拒绝会话 cookie 的客户提供最好的会话粘性,适用于 session 会话保持但不支持 cookie 和缓存的场景
源地址有两种转发客户端请求到后端服务器的服务器选取计算方式:取模法、一致性 hash
map-base 取模法
对 source 地址进行 hash 计算,再基于服务器总权重的取模,最终结果决定将此请求转发至对应的后端服务器。此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度。缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变,hash-type 指定的默认值为此算法
一致性 hash
当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动,hash(o)mod n ,该 hash 算法是动态的,支持使用 socat 等工具进行在线权重调整,支持慢启动
uri
基于对用户请求的 uri 的左半部分或整个 uri 做 hash,再将 hash 结果对总权重进行取模后,根据最终结果将请求转发到后端指定服务器,适用于后端是缓存服务器场景,默认是静态算法,也可以通过 hash-type 指定 map-based 和 consistent,来定义使用取模法还是一致性 hash
注意:此算法基于应用层,所以只支持 mode http ,不支持 mode tcp
url_param
对用户请求的 url 中的 params 部分中的一个参数 key 对应的 value 值作 hash 计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个 real server,如果没有 key,将按 roundrobin 算法
hdr
针对用户每个 http 头部(header)请求中的指定信息做 hash,此处由 name 指定的 http 首部将会被取出并做 hash 计算,然后由服务器总权重取模以后派发至某挑出的服务器,如果无有效值,则会使用默认的轮询调度
测试访问:
rdp-cookie
各种算法使用场景
高级功能及配置
基于 cookie 的会话保持
为当前 server 指定 cookie 值,实现基于 cookie 的会话黏性,相对于基于 source 地址 hash 调度算法对客户端的粒度更精准,但同时也加大了 haproxy 负载,目前此模式使用较少, 已经被 session 共享服务器代替
HAProxy 状态页
通过 web 界面,显示当前 HAProxy 的运行状态
状态页配置项:
backend server 信息:
利用状态页实现 haproxy 服务器的健康性检查:
IP 透传
web 服务器中需要记录客户端的真实 IP 地址,用于做访问统计、安全防护、行为分析、区域排行等场景
四层负载 和 七层代理
四层负载:
四层负载均衡设备不参与建立链接(实际上还是建立的,haproxy 和 lvs 不同,haproxy 是伪四层负载均衡)
七层代理:
七层负载均衡设备起到了代理服务器的作用,七层代理需要和 Client 以及后端服务器分别建立连接
四层 IP 透传
七层 IP 透传
当 haproxy 工作在七层的时候,也可以透传客户端真实 IP 至后端服务器
HAProxy 配置:
在由 haproxy 发往后端主机的请求报文中添加“X-Forwarded-For”首部
示例:
web 服务器日志格式配置:
配置 web 服务器,记录负载均衡透传的客户端 IP 地址
示例:
报文修改
在 http 模式下,基于实际需求修改客户端的请求报文与响应报文
官方文档:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#4-http-request
fmt:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#8.2.4
注意:以上指令适用于 2.1 版本以上,2.1 版本以下的指令是 reqadd、reqdel 等
自定义日志格式
压缩功能
对响应给客户端的报文进行压缩,以节省网络带宽,但是会占用部分 CPU 性能
建议在后端服务器开启压缩功能,而非在 HAProxy 上开启压缩
web 服务器状态监测
四层监测节省系统资源,但是不够准确,可能发生监测通过,但是网站打不开的情况,工作中更推荐使用七层监测
ACL ★★★
访问控制列表(ACL,Access Control Lists),特定过滤条件的集合
首先定义 ACL,然后调用 ACL
官方文档:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#7
ACL 配置选项
aclname
ACL 名称,严格区分大小写
criterion
定义 ACL 匹配规范,即:判断条件,以下列举的只是一部分:
flags
-f、-m 可选的 pattern 匹配方法:
operator
ACL 操作符
整数比较:eq、ge、gt、le、lt
字符比较:
value
value 类型
多个 ACL 的组合调用方式
多个 ACL 的逻辑处理关系:
ACL 示例-域名匹配
ACL 示例-基于源 IP 或子网调度访问
ACL 示例-基于源地址的访问控制
ACL 示例-匹配浏览器类型
ACL 示例-基于文件后缀名实现动静分离
ACL 示例-匹配访问路径实现动静分离
ACL 示例-预定义 ACL 使用
官方文档:http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#7.4
ACL name |
Equivalent to |
Usage |
FALSE |
always_false |
never match |
HTTP |
req_proto_http |
match if protocol is valid HTTP |
HTTP_1.0 |
req_ver 1.0 |
match HTTP version 1.0 |
HTTP_1.1 |
req_ver 1.1 |
match HTTP version 1.1 |
HTTP_CONTENT |
hdr_val(content-length) gt 0 |
match an existing content-length |
HTTP_URL_ABS |
url_reg ^[^/:]*:// |
match absolute URL with scheme |
HTTP_URL_SLASH |
url_beg / |
match URL beginning with “/“ |
HTTP_URL_STAR |
url * |
match URL equal to “*“ |
LOCALHOST |
src 127.0.0.1/8 |
match connection from local host |
METH_CONNECT |
method CONNECT |
match HTTP CONNECT method |
METH_DELETE |
method DELETE |
match HTTP DELETE method |
METH_GET |
method GET HEAD |
match HTTP GET or HEAD method |
METH_HEAD |
method HEAD |
match HTTP HEAD method |
METH_OPTIONS |
method OPTIONS |
match HTTP OPTIONS method |
METH_POST |
method POST |
match HTTP POST method |
METH_PUT |
method PUT |
match HTTP PUT method |
METH_TRACE |
method TRACE |
match HTTP TRACE method |
RDP_COOKIE |
req_rdp_cookie_cnt gt 0 |
match presence of an RDP cookie |
REQ_CONTENT |
req_len gt 0 |
match data in the request buffer |
TRUE |
always_true |
always match |
WAIT_END |
wait_end |
wait for end of content analysis |
示例:
自定义 HAProxy 错误界面
:
示例:
HAProxy 四层负载
问题: 后端服务器和 haproxy 还是和客户端建立三次握手?
答:HAProxy,因为 HAProxy 是伪四层,LVS 是真四层,不过,即使是伪四层,四层负载也比七层代理性能要高
四层负载示例:
注意:如果使用 frontend 和 backend,一定在 frontend 和 backend 段中都指定 mode tcp
HAProxy https 实现
haproxy 可以实现 https 的证书安全,但基于性能考虑,生产中证书都是在后端服务器比如 nginx 上实现,在 HAProxy 上采用四层负载,监听 ip:443,然后直接转发,让后端服务器去处理 https 证书
本章重点总结
- HAProxy 调度算法
- 动静分离与客户端源 IP 透传
- ACL 使用与报文修改
- 服务器动态下线
- 编写 shell 脚本,实现能够基于参数传递 Real Server 服务器 IP,并实现将其从多个 HAProxy 进程下线与上线