用 Golang 从零实现的简易负载均衡器
Source: Dev.to
(未提供需要翻译的正文内容。如需翻译,请提供完整的文本。)
负载均衡基础
| 层 | 类型 | 描述 |
|---|---|---|
| L7 (应用层) | HTTP / gRPC | 在应用层运行。 |
| L4 (传输层) | TCP / UDP | 在传输层运行。 |
核心职责
- 接收来自客户端的请求。
- 将请求转发给后端服务器池中的一台服务器。
- 将后端的响应返回给客户端。
其他关注点(本简易项目未涉及)
- 同步响应 vs. 流式响应
- 后端选择算法
- 错误处理
- 会话亲和性 / 粘性会话
- 监控与可观测性
生产就绪的替代方案
| Solution / Service | Type / Role | OSI Layer | Notes |
|---|---|---|---|
| NGINX | 反向代理、Web 服务器、负载均衡 | L7 | 路径路由通过 location 块。 |
| Envoy | L7 代理 / 服务代理 | L7 | 核心模型:Listener → Route → Cluster。 |
| AWS Application Load Balancer | 托管的应用层负载均衡 | L7 | 支持基于路径和主机的路由规则。 |
| AWS Network Load Balancer | 托管的网络层负载均衡 | L4 | 仅 TCP/UDP;不具备 HTTP 感知。 |
| GCP HTTP(S) Load Balancer | 托管的全球应用层负载均衡 | L7 | 全局主机和路径路由。 |
| GCP TCP/UDP Load Balancer | 托管的网络层负载均衡 | L4 | 无第 7 层检查。 |
| Azure Application Gateway | 托管的应用层负载均衡 | L7 | 主机/路径路由 + WAF 集成。 |
| Azure Load Balancer | 托管的网络层负载均衡 | L4 | 仅基本的 TCP/UDP 分发。 |
本项目特性
- Traffic Proxying – HTTP 请求代理,支持多种负载均衡策略。
- Load‑Balancing Strategies
- Round Robin – 循环分配。
- Weighted Round Robin – 根据服务器权重进行分配。
- Least Connections – 将请求发送到活动连接最少的服务器。
- Random – 随机选择。
- Health Checks – 定期进行 TCP 拨号检查;不健康的后端会被暂时移除。
- Request Retry – 失败时,请求会在不同的后端重新尝试。
- Configuration – 使用 JSON 文件(
config.json)或命令行标志进行配置。可配置项包括:- 负载均衡器端口
- 请求超时时间
- 健康检查间隔
- 负载均衡策略
- 后端服务器列表
架构 模块化、可测试且易于理解,遵循 关注点分离 原则。每个组件只有单一且明确的职责,使代码简洁,并且与生产系统中使用的模式相吻合。
高层流程
+-------------------+ +-------------------+ +-------------------+
| LoadBalancer | --> | Strategy (SB) | --> | Backend (RB) |
| (receives request)| | (chooses backend) | | (reverse proxy) |
+-------------------+ +-------------------+ +-------------------+
- LoadBalancer 接收请求。
- 它请求当前的 Strategy 从池中选择一个后端。
- LoadBalancer 使用所选 Backend 的反向代理转发请求。
组件详情
strategy 模块 – 大脑
后端选择逻辑通过接口定义——经典的 Strategy Design Pattern(策略设计模式)。
type LoadBalancingStrategy interface {
// SelectBackend returns the backend that should handle the request.
SelectBackend(pool []*Backend) *Backend
}
LoadBalancer 持有该接口类型的变量,使得可以在不修改核心负载均衡器代码的情况下,随意切换各种策略(轮询、最少连接等)。
backend 模块 – 工作者
后端是一个有状态的对象,而不仅仅是一个 URL 字符串。
type Backend struct {
Url url.URL
proxy *httputil.ReverseProxy
isHealthy bool
activeConnections int64
// ... other fields ...
mu sync.RWMutex
}
- 跟踪健康状态、活动连接数和权重。
- 持有执行请求转发的
httputil.ReverseProxy。 - 使用互斥锁在并发请求和健康检查之间安全地读写状态。
loadbalancer 模块 – 协调者
将所有部分连接在一起的核心组件。
type LoadBalancer struct {
pool []*Backend
strategy LoadBalancingStrategy
// ... other fields (e.g., health‑check ticker, retry config) ...
}
职责
- 管理
Backend对象池。 - 处理传入的 HTTP 流量,并使用当前的
Strategy选择后端。 - 对所有后端执行定期健康检查。
- 在请求选定后端失败时实现重试逻辑。
config 模块 – 蓝图
一个简单但重要的模块,负责从 JSON 文件或命令行标志加载配置。它会填充以下字段:
- 监听端口
- 请求超时
- 健康检查间隔
- 选定的负载均衡策略
- 后端服务器定义(URL、权重等)
结束语
通过将逻辑隔离——例如,将后端选择与请求代理分离——我们可以 对每个部分进行独立的单元测试,并以最小的副作用添加新功能。该项目是一个扎实的学习练习,也是构建更复杂、生产级负载均衡器的基础。
加载和解析配置
应用程序从 config.json 文件加载其配置。这将负载均衡器的逻辑与硬编码设置解耦,使您能够在不更改代码的情况下重新配置它。
我们构建的
在本文中,我们从头开始使用 Go 语言构建了一个简单而实用的 HTTP 负载均衡器,并逐步演示了整个过程。我们实现了多个核心功能,包括:
- 多种负载均衡策略
- 定期健康检查
- 动态配置
最终得到一个可运行的应用程序,展示了流量管理的基本原理。
设计模式实战
更重要的是,这个项目是对关键软件设计模式的实际探索。通过为我们的平衡算法使用 interface(策略模式),我们创建了一个:
- 灵活的
- 易于扩展的
对模块化和关注点分离的强调,使代码库保持清晰、可测试,并且更易于理解。
未来改进
虽然我们的负载均衡器很简单,但它提供了坚实的基础,可在许多方面进行扩展。可能的增强包括:
- 更高级的策略 – 实现 IP 哈希以进行会话亲和(粘性会话)。
- 增强可观测性 – 添加 Prometheus 指标,以监控请求延迟、错误率和活动连接数。
- HTTPS 支持 – 添加 TLS 终止以实现安全通信。
- 动态配置 – 实现配置文件的热加载,无需重启服务。
结束语
我希望本文能让您深入了解负载均衡器的内部工作原理,并激发您自行构建的兴趣。欢迎在 GitHub 上查看完整源码,亲自尝试,甚至贡献自己的想法!