• 企业400电话
  • 网络优化推广
  • AI电话机器人
  • 呼叫中心
  • 全 部 栏 目

    网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Golang实现四种负载均衡的算法(随机,轮询等)
    POST TIME:2021-10-18 17:02

    随机负载

    随机挑选目标服务器

    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
    }
    
    

    轮询负载

    服务器依次轮询

    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
    }

    加权轮询负载

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

    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

    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接口

    package load_balance
    
    type LoadBalance interface {
     Add(...string) error
     Get(string)(string, error)
    
    }
    
    

    工厂方法

    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 负载均衡内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    您可能感兴趣的文章:
    • golang grpc 负载均衡的方法
    • 使用Golang实现加权负载均衡算法的实现代码
    上一篇:Golang 实现简单随机负载均衡
    下一篇:详解玩转直播系列之消息模块演进
  • 相关文章
  • 

    关于我们 | 付款方式 | 荣誉资质 | 业务提交 | 代理合作


    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    X

    截屏,微信识别二维码

    微信号:veteran88

    (点击微信号复制,添加好友)

     打开微信