脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Golang实现四种负载均衡的算法(随机,轮询等)

Golang实现四种负载均衡的算法(随机,轮询等)

2021-08-09 01:34Gundy_ Golang

本文介绍了示例介绍了Golang 负载均衡的四种实现,主要包括了随机,轮询,加权轮询负载,一致性hash,感兴趣的小伙伴们可以参考一下

随机负载

随机挑选目标服务器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package load_balance
 
import (
 "errors"
 "math/rand"
)
 
//随机负载均衡
type RandomBalance struct {
 curIndex int
 
 rss []string
}
 
func (r *RandomBalance) Add(params ...string) error {
 if len(params) == 0 {
  return errors.New("params len 1 at least")
 }
 addr := params[0]
 r.rss = append(r.rss, addr)
 
 return nil
}
 
func (r *RandomBalance) Next() string {
 if len(r.rss) == 0 {
  return ""
 }
 r.curIndex = rand.Intn(len(r.rss))
 return r.rss[r.curIndex]
}
 
func (r *RandomBalance) Get(string) (string, error) {
 return r.Next(), nil
}

轮询负载

服务器依次轮询

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package load_balance
 
import "errors"
 
//轮询负载均衡
type RoundRobinBalance struct {
 curIndex int
 rss      []string
}
 
func (r *RoundRobinBalance) Add(params ...string) error {
 if len(params) == 0 {
  return errors.New("params len 1 at least")
 }
 
 addr := params[0]
 r.rss = append(r.rss, addr)
 return nil
}
 
func (r *RoundRobinBalance) Next() string {
 if len(r.rss) == 0 {
  return ""
 }
 lens := len(r.rss)
 if r.curIndex >= lens {
  r.curIndex = 0
 }
 
 curAddr := r.rss[r.curIndex]
 r.curIndex = (r.curIndex + 1) % lens
 return curAddr
}
 
func (r *RoundRobinBalance) Get(string) (string, error) {
 return r.Next(), nil
}

加权轮询负载

给目标设置访问权重,按照权重轮询

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package load_balance
 
import (
 "errors"
 "strconv"
)
 
type WeightRoundRobinBalance struct {
 curIndex int
 rss      []*WeightNode
 rsw      []int
}
 
type WeightNode struct {
 addr            string
 Weight          int //初始化时对节点约定的权重
 currentWeight   int //节点临时权重,每轮都会变化
 effectiveWeight int //有效权重, 默认与weight相同 , totalWeight = sum(effectiveWeight)  //出现故障就-1
}
 
//1, currentWeight = currentWeight + effectiveWeight
//2, 选中最大的currentWeight节点为选中节点
//3, currentWeight = currentWeight - totalWeight
 
func (r *WeightRoundRobinBalance) Add(params ...string) error {
 if len(params) != 2 {
  return errors.New("params len need 2")
 }
 parInt, err := strconv.ParseInt(params[1], 10, 64)
 if err != nil {
  return err
 }
 node := &WeightNode{
  addr:   params[0],
  Weight: int(parInt),
 }
 node.effectiveWeight = node.Weight
 r.rss = append(r.rss, node)
 return nil
}
 
func (r *WeightRoundRobinBalance) Next() string {
 var best *WeightNode
 total := 0
 for i := 0; i < len(r.rss); i++ {
  w := r.rss[i]
  //1 计算所有有效权重
  total += w.effectiveWeight
  //2 修改当前节点临时权重
  w.currentWeight += w.effectiveWeight
  //3 有效权重默认与权重相同,通讯异常时-1, 通讯成功+1,直到恢复到weight大小
  if w.effectiveWeight < w.Weight {
   w.effectiveWeight++
  }
 
  //4 选中最大临时权重节点
  if best == nil || w.currentWeight > best.currentWeight {
   best = w
  }
 }
 
 if best == nil {
  return ""
 }
 //5 变更临时权重为 临时权重-有效权重之和
 best.currentWeight -= total
 return best.addr
}
 
func (r *WeightRoundRobinBalance) Get(string) (string, error) {
 return r.Next(), nil
}
 
func (r *WeightRoundRobinBalance) Update()  {
 
}

一致性hash

请求固定的URL访问指定的IP

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package load_balance
 
import (
 "errors"
 "hash/crc32"
 "sort"
 "strconv"
 "sync"
)
 
//1 单调性(唯一) 2平衡性 (数据 目标元素均衡) 3分散性(散列)
type Hash func(data []byte) uint32
 
type UInt32Slice []uint32
 
func (s UInt32Slice) Len() int {
 return len(s)
}
 
func (s UInt32Slice) Less(i, j int) bool {
 return s[i] < s[j]
}
 
func (s UInt32Slice) Swap(i, j int) {
 s[i], s[j] = s[j], s[i]
}
 
type ConsistentHashBalance struct {
 mux      sync.RWMutex
 hash     Hash
 replicas int               //复制因子
 keys     UInt32Slice       //已排序的节点hash切片
 hashMap  map[uint32]string //节点哈希和key的map, 键是hash值,值是节点key
}
 
func NewConsistentHashBalance(replicas int, fn Hash) *ConsistentHashBalance {
 m := &ConsistentHashBalance{
  replicas: replicas,
  hash:     fn,
  hashMap:  make(map[uint32]string),
 }
 if m.hash == nil {
  //最多32位,保证是一个2^32-1环
  m.hash = crc32.ChecksumIEEE
 }
 return m
}
 
func (c *ConsistentHashBalance) IsEmpty() bool {
 return len(c.keys) == 0
}
 
// Add 方法用来添加缓存节点,参数为节点key,比如使用IP
func (c *ConsistentHashBalance) Add(params ...string) error {
 if len(params) == 0 {
  return errors.New("param len 1 at least")
 }
 
 addr := params[0]
 c.mux.Lock()
 defer c.mux.Unlock()
 
 // 结合复制因子计算所有虚拟节点的hash值,并存入m.keys中,同时在m.hashMap中保存哈希值和key的映射
 for i := 0; i < c.replicas; i++ {
  hash := c.hash([]byte(strconv.Itoa(i) + addr))
  c.keys = append(c.keys, hash)
  c.hashMap[hash] = addr
 }
 
 // 对所有虚拟节点的哈希值进行排序,方便之后进行二分查找
 sort.Sort(c.keys)
 return nil
}
 
// Get 方法根据给定的对象获取最靠近它的那个节点
func (c *ConsistentHashBalance) Get(key string) (string, error) {
 if c.IsEmpty() {
  return "", errors.New("node is empty")
 }
 hash := c.hash([]byte(key))
 
 // 通过二分查找获取最优节点,第一个"服务器hash"值大于"数据hash"值的就是最优"服务器节点"
 idx := sort.Search(len(c.keys), func(i int) bool { return c.keys[i] >= hash })
 
 // 如果查找结果 大于 服务器节点哈希数组的最大索引,表示此时该对象哈希值位于最后一个节点之后,那么放入第一个节点中
 if idx == len(c.keys) {
  idx = 0
 }
 c.mux.RLock()
 defer c.mux.RUnlock()
 return c.hashMap[c.keys[idx]], nil
}

封装

定义LoadBalance接口

?
1
2
3
4
5
6
7
package load_balance
 
type LoadBalance interface {
 Add(...string) error
 Get(string)(string, error)
 
}

工厂方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package load_balance
 
type LbType int
 
const (
 LbRandom LbType = iota
 LbRoundRobin
 LbWeightRoundRobin
 LbConsistentHash
)
 
func LoadBalanceFactory(lbType LbType) LoadBalance {
 switch lbType {
 case LbRandom:
  return &RandomBalance{}
 case LbConsistentHash:
  return NewConsistentHashBalance(10, nil)
 case LbRoundRobin:
  return &RoundRobinBalance{}
 case LbWeightRoundRobin:
  return &WeightRoundRobinBalance{}
 default:
  return &RandomBalance{}
 }
}

到此这篇关于Golang实现四种负载均衡的算法(随机,轮询等)的文章就介绍到这了,更多相关Golang 负载均衡内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/igo9go_zq/article/details/112579920

延伸 · 阅读

精彩推荐
  • GolangGo语言range关键字循环时的坑

    Go语言range关键字循环时的坑

    今天小编就为大家分享一篇关于Go语言range关键字循环时的坑,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来...

    benben_20154202020-05-23
  • GolangGO语言字符串处理Strings包的函数使用示例讲解

    GO语言字符串处理Strings包的函数使用示例讲解

    这篇文章主要为大家介绍了GO语言字符串处理Strings包的函数使用示例讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加...

    Jeff的技术栈6882022-04-14
  • Golang深入浅析Go中三个点(...)用法

    深入浅析Go中三个点(...)用法

    这篇文章主要介绍了深入浅析Go中三个点(...)用法,需要的朋友可以参考下...

    踏雪无痕SS6472021-11-17
  • GolangGo语言实现自动填写古诗词实例代码

    Go语言实现自动填写古诗词实例代码

    这篇文章主要给大家介绍了关于Go语言实现自动填写古诗词的相关资料,这是最近在项目中遇到的一个需求,文中通过示例代码介绍的非常详细,需要的朋...

    FengY5862020-05-14
  • GolangGo语言基础单元测试与性能测试示例详解

    Go语言基础单元测试与性能测试示例详解

    这篇文章主要为大家介绍了Go语言基础单元测试与性能测试示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助祝大家多多进步...

    枫少文7812021-12-05
  • Golanggo语言获取系统盘符的方法

    go语言获取系统盘符的方法

    这篇文章主要介绍了go语言获取系统盘符的方法,涉及Go语言调用winapi获取系统硬件信息的技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    无尽海3862020-04-24
  • GolangGolang 语言极简类型转换库cast的使用详解

    Golang 语言极简类型转换库cast的使用详解

    本文我们通过 cast.ToString() 函数的使用,简单介绍了cast 的使用方法,除此之外,它还支持很多其他类型,在这没有多多介绍,对Golang 类型转换库 cast相关知...

    Golang语言开发栈6112021-12-02
  • GolangGolang实现四种负载均衡的算法(随机,轮询等)

    Golang实现四种负载均衡的算法(随机,轮询等)

    本文介绍了示例介绍了Golang 负载均衡的四种实现,主要包括了随机,轮询,加权轮询负载,一致性hash,感兴趣的小伙伴们可以参考一下...

    Gundy_8442021-08-09