news 2026/10/10 5:29:52

BFE 流量均衡(Traffic Balancing)实战指南:从子集群权重调度到连接池与会话保持

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
BFE 流量均衡(Traffic Balancing)实战指南:从子集群权重调度到连接池与会话保持
  • 后端
  • 网络/通信
  • 云原生

【免费下载链接】bfe

A modern layer 7 load balancer from baidu

项目地址:https://gitcode.com/gh_mirrors/bf/bfe
点击查看免费下载

导读

本文围绕 BFE(Baidu Front End,百度开源的七层负载均衡器)的核心能力之一——**流量均衡(Traffic Balancing)**展开,系统讲解其两级的负载均衡体系:子集群级(Sub Cluster Level)与实例级(Instance Level)的调度策略、BLACKHOLE 黑洞集群、后端健康检查状态机、自动重试、连接池复用以及会话保持机制。通过阅读本文,你将掌握 BFE 在多 IDC 场景下如何按权重分配流量、如何配置健康检查与重试参数,并理解每一机制背后的源码实现与配置文件格式,可直接对照本仓库的配置样例落地实践。


一、BFE 流量均衡的整体架构

BFE 的流量均衡是分层的。从转发路径上看,一次请求先被路由到某个集群(Cluster),集群内部再按照以下两级完成后端选择:

  1. 子集群级(Sub Cluster Level):在集群的多个子集群之间分配流量,通常对应多 IDC 场景;
  2. 实例级(Instance Level):在子集群内部的多个后端实例之间分配流量。

这两级逻辑在源码中分别由两个包实现:

  • 子集群级均衡:bfe_balance/bal_gslb/(GSLB 调度,核心文件 bal_gslb.go);
  • 实例级均衡:bfe_balance/bal_slb/(SLB 调度,核心文件 bal_rr.go)。

此外,bfe_balance/backend/目录承载后端实例的数据结构(bfe_backend.go)与健康检查逻辑(health_check.go),是两级均衡共同依赖的基础设施。

二、子集群级负载均衡(Sub Cluster Level Load Balance)

2.1 核心思想:按权重分配跨 IDC 流量

通常一个集群会包含多个子集群。在 BFE 中,可以为每个子集群定义权重,BFE 依据权重将流量分配到各个子集群。这一特性在多 IDC 场景下尤为重要:通过调整各 IDC 对应子集群的权重,即可在不改动代码的情况下灵活控制各机房承接的流量比例。

从源码看,子集群级均衡由BalanceGslb结构体承载(bal_gslb.go),其内部维护了:

  • subClusters:子集群列表;
  • totalWeight:所有权重大于 0 的子集群的权重之和;
  • single/avail:当仅有一个可用子集群时的快速路径优化;
  • retryMax/crossRetry:集群内重试次数与跨集群重试次数。

subClusterBalance()函数(bal_gslb.go)实现了权重区间选子集群的算法:先对哈希键求哈希值并对totalWeight取模,再按权重依次减去,落入哪个子集群的权重区间就选择哪个子集群。

2.2 BLACKHOLE 黑洞子集群

每个集群都内置一个特殊的虚拟子集群BLACKHOLE:

  • 分配到 BLACKHOLE 的流量会被直接丢弃;
  • 其作用是在集群整体过载时吸收多余流量,防止流量打满整个集群,起到"卸压阀"的效果。

在源码中,当选中子集群类型为黑洞时,Balance()会直接返回ErrGslbBlackhole并累加state.ErrGslbBlackhole计数(bal_gslb.go),请求不会被转发到任何后端。

2.3 配置示例与权重计算

官方文档给出的典型多 IDC 场景为:

  • 两个 IDC:IDC_1、IDC_2;
  • 两个 BFE 集群:BFE_1、BFE_2;
  • 两个后端子集群:SubCluster_1、SubCluster_2。

各 BFE 集群的权重配置形如:

  • BFE_1:{SubCluster_1: W11, SubCluster_2: W12, Blackhole: W1B}
  • BFE_2:{SubCluster_1: W21, SubCluster_2: W22, Blackhole: W2B}

例如,若 BFE_1 的配置为{W11, W12, W1B} = {45, 45, 10},则流量按45%、45%、10%的比例分别流向 SubCluster_1、SubCluster_2 和 BLACKHOLE。

alt: BFE 依据子集群权重表(Forwarding Table)在多个子集群间分发流量的转发示意图

在仓库中,这类权重表以 JSON 数据文件的形式存放,例如 gslb_1.data:

{ "clusters": { "c1": { "GSLB_BLACKHOLE": 0, "c1.example.a": 0, "c1.example.b": 50, "c1.example.c": 20, "c1.example.d": 30 }, "c2": { "GSLB_BLACKHOLE": 0, "c2.example.a": 0, "c2.example.b": 100 } }, "hostname": "gslb-sch.b", "ts": "20190516151616" }

可以看到:子集群权重值即配置为整数(如 50/20/30),GSLB_BLACKHOLE同样作为普通子集群出现在表中,权重为 0 表示当前不向其分配流量。配置加载逻辑见 gslb_conf_load.go。

2.4 子集群选择的哈希策略

子集群级均衡默认基于哈希完成,以保持同一特征的请求稳定落在同一子集群。HashConf定义了哈希策略(cluster_conf_load.go):

HashStrategy 取值说明
ClientIdOnly仅使用请求头中的 Client ID 作为哈希键
ClientIpOnly仅使用客户端 IP 作为哈希键(默认策略)
ClientIdPreferred优先使用 Client ID,取不到时回退到客户端 IP
RequestURI使用请求 URI 作为哈希键

对应实现位于BalanceGslb.getHashKey()(bal_gslb.go),其中还支持通过HashHeader指定"代表唯一客户端"的请求头字段,特殊格式Cookie:Key可指定从 Cookie 中取值(bal_gslb.go)。若最终哈希键为空,则退化为随机值,避免全部请求集中到同一子集群。

三、实例级负载均衡(Instance Level Load Balance)

3.1 两种内置调度算法

一个子集群通常由多个后端实例组成。BFE 在子集群内部提供了多种实例分发策略,文档明确列出的两种为:

  • WRR(Weighted Round Robin,加权轮询);
  • WLC(Weighted Least Connection,加权最少连接)。

实例可以依据其容量被赋予不同的权重。BalanceRR.Balance()通过algor参数分发到具体算法(bal_rr.go),支持的模式常量包括:

WrrSimple = 0 // 简单加权轮询 WrrSmooth = 1 // 平滑加权轮询 WrrSticky = 2 // 加权轮询 + 会话保持 WlcSimple = 3 // 简单加权最少连接 WlcSmooth = 4 // 平滑加权最少连接

在集群配置中,BalanceMode取值WRR或WLC(cluster_conf_load.go),默认是WRR。Balance()中根据该模式选择WlcSmooth或WrrSmooth(bal_gslb.go)。

3.2 平滑加权轮询(Smooth WRR)原理

bal_rr.go头部注释给出了平滑 WRR 的完整算法与推演:

在每次选择后端时:① 将每个可用后端的CurrentWeight增加其weight;② 选择CurrentWeight最大的后端,并将其CurrentWeight减去所有后端权重之和。

例如权重为{a:5, b:1, c:1}时,得到的选择序列是aabacaa,而不是简单的abcaaaa——这正是平滑算法的价值:避免权重大的后端被连续打满,使流量分布更均匀。完整推演过程见 bal_rr.go。

3.3 加权最少连接(WLC)

WLC 先筛选出connNum / weight比值最小的候选后端集合(leastConnsBalance(),bal_rr.go)。为避免浮点比较,源码使用交叉相乘connNum*bWeight - bConnNum*weight来比较(compLCWeight(),bal_rr.go)。当候选集只有一个时直接返回;多个候选时,WlcSmooth再叠加平滑轮询、WlcSimple则随机挑选,兼顾"最少连接"与"分布均匀"。

每个后端实例当前持有的连接数由BfeBackend.connNum维护,并提供ConnNum()/IncConnNum()/DecConnNum()访问接口(bfe_backend.go)。

3.4 实例权重的配置方式

实例列表与权重配置在集群后端表中定义,参见 cluster_table_1.conf:

{ "Config": { "p1": { "light.p1.dx": [ { "name": "p1.example10.a", "addr": "10.38.133.59", "port": 8060, "weight": 10 } ], "light.p1.wt": [ { "name": "p1.example0.b", "addr": "10.23.238.42", "port": 8060, "weight": 10 } ] } } }

每个后端实例由name、addr、port、weight四个字段描述,权重值即实例级调度依据。此外BackendBasic还提供SlowStartTime(秒)实现慢启动:新恢复的后端在指定时间内权重逐步增加到全量值,避免刚上线的实例被瞬间打满(cluster_conf_load.go)。

四、健康检查(Health Check)

4.1 每个实例的两态状态机

BFE 为每个后端实例维护一个状态机,仅有两个状态:

  • NORMAL:实例正常处理请求;
  • CHECKING:实例处理请求失败,BFE 启动健康检查,直到实例恢复正常。

状态迁移条件如下:

迁移方向触发条件
NORMAL → CHECKING连接实例或向其发送请求的连续失败次数超过阈值
CHECKING → NORMALBFE 收到该实例对健康检查请求的正确响应

在源码中,这两个状态由BfeBackend的avail字段体现,并伴随两个计数器:

  • failNum:正常请求的连续失败次数;
  • succNum:健康检查请求的连续成功次数(bfe_backend.go)。

当后端被判定为失败时,UpdateStatus()会启动一个健康检查 goroutine(每个后端至多一个),见 health_check.go。

4.2 健康检查流程

check()是健康检查主循环(health_check.go):

  1. 按CheckInterval周期执行探测;
  2. 探测失败则重置succNum,继续等待下一次检查;
  3. 探测成功后累加succNum,直到达到SuccNum阈值;
  4. 达到阈值后调用SetAvail(true)将实例状态置回 NORMAL,并标记SetRestart(true)触发慢启动。

CheckConnect()根据配置的协议(Schem)分派到不同探测实现(health_check.go):

  • http:发送 HTTP GET 请求并校验状态码(checkHTTPConnect);
  • tcp:仅做 TCP 连接探测(checkTCPConnect);
  • https/tls:建立 TLS 连接并完成握手,可选校验响应状态码(checkHTTPSConnect)。

4.3 健康检查配置参数

健康检查的完整可配置项在BackendCheck结构体中定义(cluster_conf_load.go):

配置项含义
Schem探测协议:HTTP / HTTPS / TCP
Uri健康检查请求的 URI
Host探测请求使用的 Host 头
StatusCode期望的响应状态码,默认 200
StatusCodeRange状态码范围,如3xx、4xx、5xx,或用\|组合,如"503" \| "4xx"
FailNum判定实例不健康的连续失败阈值
SuccNum判定实例恢复健康的连续成功阈值
CheckTimeout探测超时,单位毫秒
CheckInterval探测间隔,单位毫秒

对应配置文件示例(cluster_conf_1.conf):

"CheckConf": { "Uri": "/health", "FailNum": 3, "CheckInterval": 1000, "Response": "200 OK" }

注意该示例中的Response为旧字段;现代配置中建议使用StatusCode/StatusCodeRange表达期望响应。健康检查配置是按集群独立存储的,通过SetCheckConfFetcher注入获取回调(health_check.go)。

五、自动重试(Automatic Retries)

当请求转发失败时,BFE 支持两种重试方式:

  • In-Sub-Cluster Retry(子集群内重试):在同一个子集群内重新转发请求;
  • Cross-Sub-Cluster Retry(跨子集群重试):转发失败后,改向其他子集群重试。

重试次数由GslbBasicConf控制(cluster_conf_load.go):

配置项含义源码默认值
RetryMax在指定子集群内的最大重试次数DefaultRetryMax = 3
CrossRetry跨子集群的最大重试次数DefaultCrossRetryMax = 1

对应常量定义见 bal_gslb.go。配置示例(cluster_conf_1.conf):

"GslbBasic": { "CrossRetry": 1, "RetryMax": 3 }

在Balance()的实现中(bal_gslb.go):

  1. 当req.RetryTime > retryMax + crossRetry时,判定重试次数耗尽,返回ErrBkRetryTooMany;
  2. 在retryMax范围内优先在当前子集群内选后端;
  3. 若当前子集群所有后端均不可用,且crossRetry > 0,则调用randomSelectExclude()(bal_gslb.go)随机挑选一个排除当前子集群与黑洞的子集群进行跨集群转发;
  4. 若crossRetry <= 0,则禁用跨集群重试,直接返回ErrBkNoBackend。

六、连接池(Connection Pool)

BFE 与后端实例之间支持两种 TCP 连接方式:

  1. 短连接(Short-Lived Connection):每个请求都新建 TCP 连接转发;
  2. 连接池(Connection Pool):复用已有连接。

连接池的工作流程(对应 bal_gslb.go 所依赖的 backend 连接管理):

  • BFE 为每个后端实例维护一个连接池;
  • 请求转发到某实例时:若池中有空闲连接则取出复用,否则新建 TCP 连接;
  • 请求处理完毕后:若池中空闲连接数小于配置容量,则将该连接回收入池;否则直接关闭。

连接池容量由BackendBasic中的两个参数控制(cluster_conf_load.go):

  • MaxIdleConnsPerHost:每个后端实例允许保留的最大空闲连接数(即"配置容量");
  • MaxConnsPerHost:每个后端实例允许的最大连接总数(0 表示不限制)。

这两个参数在配置加载时均有默认值兜底(cluster_conf_load.go)。合理设置MaxIdleConnsPerHost可在"连接复用收益"与"空闲连接占用"之间取得平衡。

七、会话保持(Session Stickiness)

7.1 会话的标识方式

BFE 支持会话保持,即同一会话的请求被固定转发到同一后端。会话可以基于以下请求信息定义:

  • 源 IP(Source IP);
  • 请求头中的字段、Cookie 等(如Cookie:BAIDUID)。

7.2 两个粒度的会话保持

文档明确区分了两个支持层级:

  • 子集群级(Sub Cluster Level):同一会话的请求被转发到同一个子集群(子集群内可以是不同实例)。实现上对应HashConf.SessionSticky配置:开启后,实例级算法切换为WrrSticky,结合哈希键将同一会话的请求稳定映射到同一子集群(bal_gslb.go)。
  • 实例级(Instance Level):同一会话的请求被转发到同一个实例。源码通过LookupStickyBackend()在请求上下文中查找之前绑定的后端(bal_gslb.go),对应的mod_session_sticky模块(mod_session_sticky)负责生成并维护会话与后端的绑定关系。

配置层面,会话保持相关字段集中在HashConf(cluster_conf_load.go):

配置项含义
HashStrategy哈希策略(决定会话键来源)
HashHeader代表唯一客户端的请求头,支持Cookie:Key格式
SessionSticky是否开启会话保持(布尔值,默认关闭)

开启会话保持后,stickyBalance()会基于哈希键与各可用后端的权重,将同一会话稳定映射到同一后端(bal_rr.go)。

八、小结

BFE 的流量均衡能力可以概括为一张"两级调度 + 四类保障"的完整体系:

层级/机制核心实现关键配置
子集群级均衡bal_gslb.go子集群权重表、HashStrategy、SessionSticky
实例级均衡bal_rr.goBalanceMode(WRR/WLC)、实例weight、SlowStartTime
健康检查health_check.goFailNum、SuccNum、CheckInterval、Schem
自动重试bal_gslb.goRetryMax、CrossRetry
连接池backend 连接管理MaxIdleConnsPerHost、MaxConnsPerHost
会话保持mod_session_stickySessionSticky、HashHeader

实际部署时,你可以参考仓库中的真实配置样例快速起步:gslb 权重表样例、集群基础配置样例、后端实例表样例。三者分别对应子集群权重、集群级参数(重试/健康检查/超时)与实例列表,组合起来即构成一次完整的两级流量均衡配置。

  • 后端
  • 网络/通信
  • 云原生

【免费下载链接】bfe

A modern layer 7 load balancer from baidu

项目地址:https://gitcode.com/gh_mirrors/bf/bfe
点击查看免费下载

相关推荐

上一篇:ClawX 飞书双插件迁移守护:Gateway 配置清洗中的单插件契约保障
下一篇:darktable 免费 RAW 开发指南:一张照片从导入到出片的完整路径

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 5:25:04

claude-mem:为 Claude 对话补上持久记忆的本地工具

开门见山地说&#xff1a;claude-mem 是给 Claude 对话补上"长期记忆"的本地工具。我把它接入日常的终端工作流之后&#xff0c;最大的感受是——终于不用每次新开会话都把项目背景、技术选型、踩坑记录从头讲一遍了。这个东西解决的是很多人忽略的一个痛点&#xff…

作者头像 李华
网站建设 2026/10/10 5:24:45

最强智能版本:ANSYS/ABAQUS质量刚度矩阵提取与自动化工作流

搞仿真的朋友迟早都会撞上同一个需求&#xff1a;模型算完、云图看完&#xff0c;但项目那边要的偏偏不是位移和应力&#xff0c;而是要你把“质量矩阵”和“刚度矩阵”导出来。这东西不像后处理云图那样点两下就出结果&#xff0c;它藏在求解器内部。我自己是从ANSYS和ABAQUS两…

作者头像 李华
网站建设 2026/10/10 5:24:12

问卷星逆向实战:参数复现与会话模拟两种路线全解析

“问卷星逆向”这个话题&#xff0c;常年挂在自动化测试、数据采集、业务流程验证这几类需求下面。你可能是想把自己搭的问卷系统跟问卷星上的公开问卷做数据打通&#xff0c;也可能是想给一套答题系统做接口自动化回归&#xff0c;还可能是需要一个受控的数据采集程序去处理已…

作者头像 李华
网站建设 2026/10/10 5:23:52

老游戏低配优化指南:CPU单核与显存管理实战

1. 为什么十几年后还有人折腾这款老游戏每次看到有人问“这游戏都这么多年了&#xff0c;还有必要优化吗”&#xff0c;我都想回一句&#xff1a;你去试试在现在的机器上直接跑原版&#xff0c;看看那个帧数曲线有多酸爽。这款游戏当年是出了名的吃CPU&#xff0c;双核时代它能…

作者头像 李华