go 实现负载均衡器代码细节
文章目录
代码实现
原理介绍
版本1.0
版本2.0
为了实现main函数等待所有其他协程执行完毕后再结束,使用了 sync.WaitGroup。WaitGroup是一个同步原语,它等待一组操作完成。你可以通过调用Add方法来增加计数,然后在协程中调用Done方法来减少计数,最后调用Wait方法来阻塞直到计数归零。
版本2.0
版本2.1
8、修改BalancerManager变量的作用域以及AddServer方法
为了后面更加方便的增加、移除节点,修改服务器列表变量的作用域。
// BalancerManager 管理负载均衡器和服务器列表。
// 它封装了负载均衡器的实例和服务器列表,提供了获取、添加和删除服务器的方法。
type BalancerManager struct {
LoadBalancerInstance LoadBalancer // 当前使用的负载均衡器实例
Servers []*server.Node // 服务器列表
}
// AddServer 向服务器列表中添加一个新服务器。
func (lbm *BalancerManager) AddServer(server *server.Node) {
// 向服务器列表中追加新服务器
lbm.Servers = lbm.LoadBalancerInstance.AddServer(lbm.Servers, server)
}
9、增加移除物理服务器节点的方法
首先需要修改 LoadBalancer 接口,增加RemoveServer方法:
type LoadBalancer interface {
// SelectServer 是 LoadBalancer 接口的核心方法,它接收一个服务器列表作为参数,
// 并从中选择一个服务器返回其地址。如果服务器列表为空,应该返回一个错误。
// SelectServer 函数接受一个 ...interface{} 类型的参数,这样你就可以选择性地传递 data 参数。当没有提供 data 参数时,data 将是一个空的切片,可以检查其长度或者第一个元素是否为 nil 来判断是否提供了数据
SelectServer(servers []*server.Node, data ...interface{}) (*server.Node, error)
// AddServer 函数用于向负载均衡器中添加服务器。
AddServer(servers []*server.Node, server *server.Node) []*server.Node
RemoveServer(servers []*server.Node, server *server.Node) []*server.Node
}
load_balancer_manager 中增加RemoveServer方法:
// RemoveServer 从服务器列表中移除一个服务器。
// 如果服务器不存在于列表中,该方法不会产生任何效果。
func (lbm *BalancerManager) RemoveServer(server *server.Node) {
lbm.Servers = lbm.LoadBalancerInstance.RemoveServer(lbm.Servers, server)
}
一致性散列算法:
一致性哈希策略这里增加一个 RemoveNodes 方法用于将虚拟节点从哈希环移除。
// RemoveNodes 将虚拟节点从哈希环移除
func (c *ConsistentHash) RemoveNodes(nodes ...*server.Node) {
for _, node := range nodes {
// 每个真实的服务器节点都要创建 replicas 个虚拟节点
for i := 0; i < c.replicas; i++ {
// 对每一个真实节点 key,对应创建 c.replicas 个虚拟节点,虚拟节点的名称是:
// strconv.Itoa(i) + key,即通过添加编号的方式区分不同虚拟节点
hash := int(c.hash([]byte(node.NodeIpAddr + "_" + strconv.Itoa(i) + node.Port)))
// 使用 c.hash() 计算虚拟节点的哈希值,使用 append(c.keys, hash) 添加到环上。
for j, r := range c.hashRing {
if r == hash {
c.hashRing = append(c.hashRing[:j], c.hashRing[j+1:]...)
}
}
// 在 virtualNodeMap 中增加虚拟节点和真实节点的映射关系。
delete(c.virtualNodeMap, hash)
}
}
// 最后一步,环上的哈希值排序。
sort.Ints(c.hashRing)
}
增加一个 RemoveServer 方法移除服务器节点,实际上只是将服务器的状态改为不可用。
// RemoveServer 移除服务器节点
func (c *ConsistentHash) RemoveServer(servers []*server.Node, server *server.Node) []*server.Node {
c.mu.Lock()
// 遍历服务器列表,查找并移除指定的服务器
for _, s := range servers {
if s.NodeId == server.NodeId {
// 移除找到的服务器
//servers = append(servers[:i], servers[i+1:]...)
s.Status = 0
c.RemoveNodes(server)
break
}
}
c.mu.Unlock()
return servers
}
加权轮询算法:
加权轮询算法中,移除节点后需要及时更新权重节点列表。
// RemoveServer 移除服务器节点
func (w *WeightedRoundRobin) RemoveServer(servers []*server.Node, server *server.Node) []*server.Node {
w.mu.Lock()
// 遍历服务器列表,查找并移除指定的服务器
for _, s := range servers {
if s.NodeId == server.NodeId {
// 移除找到的服务器
//servers = append(servers[:i], servers[i+1:]...)
s.Status = 0
break
}
}
w.mu.Unlock()
// 通过通道通知进行服务器节点权重列表的更新
w.detectServersChan <- servers
return servers
}
总结
其余的策略的实现方法比较简单,这里不作详细讲解,具体可以看git的提交记录。同时这次还对 SelectServer 方法进行了修复,增加了对选择的服务器的Status的检查以及选中的服务器不可用时如何选择可用的服务器。我的实现比较简单,可自行探索更为合理的方法。
后续不一定有时间继续更新优化负载均衡器这个项目了。可能会学点别的,发点新的笔记。