您的位置 首页 golang

Golang 实现一致性哈希负载均衡

Golang 实现一致性哈希负载均衡

个人理解:一致性哈希算法

  1. 根据每一台服务器不同的 ip:port 根据自己的 key生成算法 ,生成一个唯一的 key 值
  2. key => ip:port 把机器唯一的 key 映射机器访问地址 ip:port 设置到一个 有序的循环圆
  3. 请求过来的时候,根据请求内容生成按 自己的 key生成算法 也生成一个 请求的 key
  4. 请求的 key 有序的循环圆 上 机器的 key 循环对比, 第一个 机器的 key 大于 请求的 key 就是最优解,由它来处理该请求
  5. 如果 请求的 key 有序的循环圆 上 机器的 key 都大,那么由 圆上第一条机器 处理
  6. 有序的循环圆 上机器,根据访问情况。近实时增删机器映射

一致性哈希负载均衡 具体编码实现

 package load_balance

import (
"errors"
"fmt"
"hash/crc32"
"sort"
"strconv"
"strings"
"sync"
)

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 HashBanlance struct {
mux      sync.RWMutex
hash     Hash
replicas int               //复制因子
keys     UInt32Slice       //已排序的节点hash切片
hashMap  map[uint32]string //节点哈希和Key的map,键是hash值,值是节点key

//观察主体
conf LoadBalanceConf
}

func NewHashBanlance(replicas int, fn Hash) *HashBanlance {
m := &HashBanlance{
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 *HashBanlance) IsEmpty() bool {
return len(c.keys) == 0
}

// Add 方法用来添加缓存节点,参数为节点key,比如使用IP
func (c *HashBanlance) 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 *HashBanlance) 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
}

func (c *HashBanlance) SetConf(conf LoadBalanceConf) {
c.conf = conf
}  

负载轮询测试代码

测试结果

文章来源:智云一二三科技

文章标题:Golang 实现一致性哈希负载均衡

文章地址:https://www.zhihuclub.com/91262.shtml

关于作者: 智云科技

热门文章

网站地图