分享
  1. 首页
  2. 文章

Go语言实现一致性哈希(Consistent Hashing)算法

xcltapestry · · 9792 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

一致性哈希可用于解决服务器均衡问题。 用Golang简单实现了下,并加入了权重。可采用合适的权重配合算法使用。

package main
//一致性哈希(Consistent Hashing)
//author: Xiong Chuan Liang
//date: 2015年2月20日
import (
	"fmt"
	"hash/crc32"
	"sort"
	"strconv"
	"sync"
)
const DEFAULT_REPLICAS = 160
type HashRing []uint32
func (c HashRing) Len() int {
	return len(c)
}
func (c HashRing) Less(i, j int) bool {
	return c[i] < c[j]
}
func (c HashRing) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
type Node struct {
	Id int
	Ip string
	Port int
	HostName string
	Weight int
}
func NewNode(id int, ip string, port int, name string, weight int) *Node {
	return &Node{
		Id: id,
		Ip: ip,
		Port: port,
		HostName: name,
		Weight: weight,
	}
}
type Consistent struct {
	Nodes map[uint32]Node
	numReps int
	Resources map[int]bool
	ring HashRing
	sync.RWMutex
}
func NewConsistent() *Consistent {
	return &Consistent{
		Nodes: make(map[uint32]Node),
		numReps: DEFAULT_REPLICAS,
		Resources: make(map[int]bool),
		ring: HashRing{},
	}
}
func (c *Consistent) Add(node *Node) bool {
	c.Lock()
	defer c.Unlock()
	if _, ok := c.Resources[node.Id]; ok {
		return false
	}
	count := c.numReps * node.Weight
	for i := 0; i < count; i++ {
		str := c.joinStr(i, node)
		c.Nodes[c.hashStr(str)] = *(node)
	}
	c.Resources[node.Id] = true
	c.sortHashRing()
	return true
}
func (c *Consistent) sortHashRing() {
	c.ring = HashRing{}
	for k := range c.Nodes {
		c.ring = append(c.ring, k)
	}
	sort.Sort(c.ring)
}
func (c *Consistent) joinStr(i int, node *Node) string {
	return node.Ip + "*" + strconv.Itoa(node.Weight) +
		"-" + strconv.Itoa(i) +
		"-" + strconv.Itoa(node.Id)
}
// MurMurHash算法 :https://github.com/spaolacci/murmur3
func (c *Consistent) hashStr(key string) uint32 {
	return crc32.ChecksumIEEE([]byte(key))
}
func (c *Consistent) Get(key string) Node {
	c.RLock()
	defer c.RUnlock()
	hash := c.hashStr(key)
	i := c.search(hash)
	return c.Nodes[c.ring[i]]
}
func (c *Consistent) search(hash uint32) int {
	i := sort.Search(len(c.ring), func(i int) bool { return c.ring[i] >= hash })
	if i < len(c.ring) {
		if i == len(c.ring)-1 {
			return 0
		} else {
			return i
		}
	} else {
		return len(c.ring) - 1
	}
}
func (c *Consistent) Remove(node *Node) {
	c.Lock()
	defer c.Unlock()
	if _, ok := c.Resources[node.Id]; !ok {
		return
	}
	delete(c.Resources, node.Id)
	count := c.numReps * node.Weight
	for i := 0; i < count; i++ {
		str := c.joinStr(i, node)
		delete(c.Nodes, c.hashStr(str))
	}
	c.sortHashRing()
}
func main() {
	cHashRing := NewConsistent()
	for i := 0; i < 10; i++ {
		si := fmt.Sprintf("%d", i)
		cHashRing.Add(NewNode(i, "172.18.1."+si, 8080, "host_"+si, 1))
	}
	for k, v := range cHashRing.Nodes {
		fmt.Println("Hash:", k, " IP:", v.Ip)
	}
	ipMap := make(map[string]int, 0)
	for i := 0; i < 1000; i++ {
		si := fmt.Sprintf("key%d", i)
		k := cHashRing.Get(si)
		if _, ok := ipMap[k.Ip]; ok {
			ipMap[k.Ip] += 1
		} else {
			ipMap[k.Ip] = 1
		}
	}
	for k, v := range ipMap {
		fmt.Println("Node IP:", k, " count:", v)
	}
}
/*
分布:
Node IP: 172.18.1.2 count: 115
Node IP: 172.18.1.8 count: 111
Node IP: 172.18.1.3 count: 94
Node IP: 172.18.1.1 count: 84
Node IP: 172.18.1.7 count: 107
Node IP: 172.18.1.6 count: 117
Node IP: 172.18.1.4 count: 92
Node IP: 172.18.1.5 count: 112
Node IP: 172.18.1.0 count: 63
Node IP: 172.18.1.9 count: 105
*/
上面是简单测试后的结果。


MAIL: xcl_168@aliyun.com

BLOG: http://blog.csdn.net/xcl168






有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:xcltapestry

查看原文:Go语言实现一致性哈希(Consistent Hashing)算法

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
9792 次点击 ∙ 1 赞
1 回复 | 直到 2000年01月01日 00:00:00
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏