项目:TinyBalancer [1]
简述
TinyBalancer 项目是 丸子 的 Tiny系列是帮助 gopher 入门的项目之一,整个项目的实现思路可以看他的文章:用 Go 轻松实现高性能负载均衡器 [2] 。由于该文章上未说明其项目的负载均衡的算法实现的介绍。
那么这篇笔记会补充自己在看代码过程中反应的一些资料和对项目代码的一些备注。
笔记
TinyBalancer 项目中的目录如下:
zhi@linksystem tinybalancer % tree -L 1
.
├── balancer # 负载均衡的实现
├── proxy # 代理的实现
└── util # 工具类的实现
那么笔记上,我们只重点关注 balancer 的实现。balancer 中的抽象实现可以重点看 balancer.go 这一文件的实现。代码如下:
// balancer.go
type Balancer interface {
Add(string)
Remove(string)
Balance(string) (string, error)
Inc(string)
Done(string)
}
以下是对于 Balancer 的方法的理解:
- Balance 方法是关键,用于均衡的调用
- Add / Inc 方法这是用于进行均衡的时的计数调用
- Done 方法是在代理完成时进行调用
- Remove 方法是删除存在问题的 host ,即需要均衡的服务
那么在了解 balancer.go 的抽象之后,我们需要知道常用的负载均衡策略有以下这些:
- 随机选择
- 轮询选择
- 最少连接
- 一致性哈希
- 两次随机选择
上述的这些策略,我推荐大家去看以下这些文章来学习相关的实现原理,文章如下:
这些文章通过简单的概述策略的实现思路来让我们了解这些策略实现的关键是什么。
而其中 两次随机选择,即 The Power of Two Random Choices ,相对来说会难于理解,因为它需要我们去理解 balls-into-bins 模型背后的概率。如果希望深入了解 两次随机选择 之所以是一个优秀的实现,大家可以去阅读论文 《The Power of Two Random Choices: A Survey of Techniques and Results》 [3] 。而 balls-into-bins 模型的话,这推荐大家去看知乎的这一问题 投b个球到b个盒子,盒子中最大球数的期望? 。
那么在理解 两次随机选择 这一策略之后,我们就可以知道 p2c.go 这一文件实现的策略的思路是什么。那么代码的主要备注如下:
func (p *P2C) Balance(key string) (string, error) {
p.RLock()
defer p.RUnlock()
if len(p.hosts) == 0 {
return "", NoHostError
}
// 调用 随机算法 来找到两个 host ,在比较其负载,选择负载低的那一个
n1, n2 := p.hash(key)
host := n2
if p.loadMap[n1].load <= p.loadMap[n2].load {
host = n1
}
return host, nil
}
func (p *P2C) hash(key string) (string, string) {
var n1, n2 string
if len(key) > 0 {
saltKey := key + Salt
n1 = p.hosts[crc32.ChecksumIEEE([]byte(key))%uint32(len(p.hosts))].name
n2 = p.hosts[crc32.ChecksumIEEE([]byte(saltKey))%uint32(len(p.hosts))].name
return n1, n2
}
n1 = p.hosts[p.rnd.Intn(len(p.hosts))].name
n2 = p.hosts[p.rnd.Intn(len(p.hosts))].name
return n1, n2
}
到此,笔记结束!
References
[1]: TinyBalancer: github.com/zehuamama/t…
[2]: 用 Go 轻松实现高性能负载均衡器: zhuanlan.zhihu.com/p/506415782
[3]:《The Power of Two Random Choices: A Survey of Techniques and Results》: www.eecs.harvard.edu/~michaelm/p…