当前位置: 首页 > news >正文

用 Go 从零实现一个简易负载均衡器

🚀 用 Go 从零实现一个简易负载均衡器

在日常开发中,我们经常会遇到这样的场景:前端用户请求数量太多,而一台后端服务器已经撑不住了。这个时候,**负载均衡(Load Balancing)**就派上用场了。

本文将带你一步步用 Go 实现一个 简易的 HTTP 负载均衡器,支持轮询调度,把请求转发到多台后端服务器,就像一个 mini 版的 Nginx/HAProxy。


🔎 什么是负载均衡?

负载均衡的目标是:把用户的请求合理地分配到多台后端服务器,从而避免某一台服务器过载,提高系统整体性能和可用性。

常见的策略有:

  • 轮询 (Round Robin):请求依次分发到不同服务器,像轮流排队。
  • 随机 (Random):每次随机挑选一台服务器。
  • 最少连接数 (Least Connections):优先选择当前连接最少的服务器。

在实际生产中,Nginx、HAProxy 等软件会结合更多特性(健康检查、权重、会话保持等)。
但我们今天的目标是写一个 能跑起来的简易版本


🛠️ 基础架构

我们要实现的是:

Client -----> Go 负载均衡器 -----> 后端服务器池
  • 客户端:发 HTTP 请求到负载均衡器
  • 负载均衡器:接收请求,挑选一台后端,转发请求
  • 后端服务器:返回响应

💻 核心代码

下面给出一个简易的 HTTP 轮询负载均衡器

1. 定义负载均衡器结构

package mainimport ("fmt""log""math/rand""net/http""net/http/httputil""net/url""sync""time"
)// 后端服务器结构
type Backend struct {URL          *url.URLReverseProxy *httputil.ReverseProxyAlive        boolmu           sync.RWMutex
}// 设置服务器状态
func (b *Backend) SetAlive(alive bool) {b.mu.Lock()b.Alive = aliveb.mu.Unlock()
}// 获取服务器状态
func (b *Backend) IsAlive() bool {b.mu.RLock()defer b.mu.RUnlock()return b.Alive
}// 负载均衡器
type LoadBalancer struct {backends []*Backendcounter  intmu       sync.Mutex
}

2. 轮询调度算法

// 选择下一个可用的后端(轮询)
func (lb *LoadBalancer) NextBackend() *Backend {lb.mu.Lock()defer lb.mu.Unlock()// 简单轮询for i := 0; i < len(lb.backends); i++ {b := lb.backends[lb.counter%len(lb.backends)]lb.counter++if b.IsAlive() {return b}}return nil
}

3. 健康检查(确保后端存活)

// 定期检查后端是否存活
func (lb *LoadBalancer) HealthCheck() {for {for _, b := range lb.backends {resp, err := http.Head(b.URL.String())if err != nil || resp.StatusCode >= 500 {b.SetAlive(false)fmt.Printf("❌ 后端 %s 下线\n", b.URL)} else {b.SetAlive(true)fmt.Printf("✅ 后端 %s 存活\n", b.URL)}}time.Sleep(5 * time.Second)}
}

4. 请求处理(转发到后端)

func (lb *LoadBalancer) ServeHTTP(w http.ResponseWriter, r *http.Request) {backend := lb.NextBackend()if backend != nil {backend.ReverseProxy.ServeHTTP(w, r)} else {http.Error(w, "Service not available", http.StatusServiceUnavailable)}
}

5. 主函数

func main() {// 后端服务器池backends := []*Backend{}servers := []string{"http://localhost:8081","http://localhost:8082","http://localhost:8083",}// 初始化反向代理for _, addr := range servers {serverURL, _ := url.Parse(addr)proxy := httputil.NewSingleHostReverseProxy(serverURL)backends = append(backends, &Backend{URL:          serverURL,ReverseProxy: proxy,Alive:        true,})}// 创建负载均衡器lb := &LoadBalancer{backends: backends}// 启动健康检查go lb.HealthCheck()// 启动负载均衡器fmt.Println("🚀 负载均衡器启动,监听 :8080")if err := http.ListenAndServe(":8080", lb); err != nil {log.Fatal(err)}
}

🎯 测试效果

  1. 启动三个后端服务(例如写简单的 HTTP 服务器返回不同响应):
// backend.go
package mainimport ("fmt""net/http""os"
)func main() {port := os.Args[1]http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello from backend %s\n", port)})http.ListenAndServe(":"+port, nil)
}

运行:

go run backend.go 8081
go run backend.go 8082
go run backend.go 8083
  1. 启动负载均衡器:
go run main.go
  1. 测试访问:
curl http://localhost:8080/

多次请求,你会发现它会轮流返回:

Hello from backend 8081
Hello from backend 8082
Hello from backend 8083

✅ 总结

在这篇文章中,我们:

  • 理解了负载均衡的概念和常见策略
  • 用 Go 实现了一个支持轮询调度的 简易 HTTP 负载均衡器
  • 加入了 健康检查,确保下线的后端不会被调度
  • 测试了多台后端的请求分发

虽然这个实现还很基础,但它已经展示了负载均衡的核心思想。如果要进一步增强,可以考虑:

  • 加权轮询(不同服务器分配不同权重)
  • 会话保持(同一用户请求始终打到同一后端)
  • TLS 支持
  • Prometheus 监控指标

这样,一个小巧的 Go 版 mini Nginx 就完成了 🎉。


http://www.dtcms.com/a/344881.html

相关文章:

  • SSM从入门到实战: 2.7 MyBatis与Spring集成
  • 计算机内存中的整型存储奥秘、大小端字节序及其判断方法
  • Bluedroid vs NimBLE
  • 北京-测试-入职甲方金融-上班第三天
  • AR眼镜巡检系统在工业互联网的应用:AR+IoT
  • JAVA后端开发——API状态字段设计规范与实践
  • 目标检测数据集转换为图像分类数据集
  • Pandas中的SettingWithCopyWarning警告出现原因及解决方法
  • 共享内存详细解释
  • 前端在WebSocket中加入Token的方法
  • 12-Linux系统用户管理及基础权限
  • 塞尔达传说 王国之泪 PC/手机双端 免安装中文版
  • celery
  • C语言翻译环境作业
  • 大学校园安消一体化平台——多警合一实现智能联动与网格化管理
  • 【链表 - LeetCode】19. 删除链表的倒数第 N 个结点
  • Android.mk 基础
  • Electron 核心 API 全解析:从基础到实战场景
  • 从零开始搭 Linux 环境:VMware 下 CentOS 7 的安装与配置全流程(附图解)
  • openstack的novnc兼容问题
  • 【日常学习】2025-8-20 框架中控件子类实例化设计
  • FPGA学习笔记——简单的IIC读写EEPROM
  • LeetCode 3195.包含所有 1 的最小矩形面积 I:简单题-求长方形四个范围
  • 化工生产场景下设备状态监测与智能润滑预测性维护路径
  • 校园作品互评管理移动端的设计与实现
  • Boost库中boost::random::normal_distribution(正态分布)详解和实战示例
  • 腾讯云EdgeOne安全防护:快速上手,全面抵御Web攻击
  • 如何优雅的监听dom的变化(尺寸)
  • php apache无法接收到Authorization header
  • JDK17 升级避坑指南:技术原理与解决方案详解