开源地址
github.com/lafikl/consistent
代码例子
var hosts = []string{
"host1",
"host2",
"host3",
}
var c = consistent.New()
func init() {
for _, host := range hosts {
c.Add(host)
}
}
func Test_Remove(t *testing.T) {
host1, _ := c.Get("1")
t.Log(host1)
host2, _ := c.Get("2")
t.Log(host2)
// delete host1
c.Remove(host1)
t.Log(host3)
// host2 不变
host4, _ := c.Get("2")
t.Log(host4)
}
基本方法实现
结构定义
type Consistent struct {
hosts map[uint64]string
sortedSet []uint64
loadMap map[string]*Host
totalLoad int64
sync.RWMutex
}
Add
func (c *Consistent) Add(host string) {
c.Lock()
defer c.Unlock()
if _, ok := c.loadMap[host]; ok { // 去重
return
}
c.loadMap[host] = &Host{Name: host, Load: 0}
for i := 0; i < replicationFactor; i++ { // 多副本?
h := c.hash(fmt.Sprintf("%s%d", host, i))
c.hosts[h] = host
c.sortedSet = append(c.sortedSet, h)
}
// sort hashes ascendingly
sort.Slice(c.sortedSet, func(i int, j int) bool {
if c.sortedSet[i] < c.sortedSet[j] { // 排序成环
return true
}
return false
})
}
Get
func (c *Consistent) Get(key string) (string, error) {
c.RLock()
defer c.RUnlock()
if len(c.hosts) == 0 {
return "", ErrNoHosts
}
h := c.hash(key) // 获得指定hash
idx := c.search(h) // 搜索最近的槽位
return c.hosts[c.sortedSet[idx]], nil
}
func (c *Consistent) search(key uint64) int {
idx := sort.Search(len(c.sortedSet), func(i int) bool { // 定位最近的槽位
return c.sortedSet[i] >= key
})
if idx >= len(c.sortedSet) {
idx = 0
}
return idx
}
Remove
// Deletes host from the ring
func (c *Consistent) Remove(host string) bool {
c.Lock()
defer c.Unlock()
for i := 0; i < replicationFactor; i++ {
h := c.hash(fmt.Sprintf("%s%d", host, i))
delete(c.hosts, h)
c.delSlice(h)
}
delete(c.loadMap, host)
return true
}
func (c *Consistent) delSlice(val uint64) {
idx := -1
l := 0
r := len(c.sortedSet) - 1
for l <= r { // 二分遍历指定idx
m := (l + r) / 2
if c.sortedSet[m] == val {
idx = m
break
} else if c.sortedSet[m] < val {
l = m + 1
} else if c.sortedSet[m] > val {
r = m - 1
}
}
if idx != -1 { // 从顺序数组中剔除
c.sortedSet = append(c.sortedSet[:idx], c.sortedSet[idx+1:]...)
}
}
版权声明:本文为qq_17612199原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。