18910140161

Golang一致性散列算法的实现

顺晟科技

2021-08-28 09:41:30

359

一致性散列算法在分布式应用中被广泛使用。主要作用是解决服务的热点问题。例如,在分布式数据存储(如Redis缓存集、状态活动等)中,可以解决请求的热点问题,并缓解服务更改时出现的负载不平衡。

本文简要介绍一致性散列算法,并分析golang的开放源代码实现包(github.com/stathat/consistent)

一致性哈希算法原理

解决的问题

分布式存储通常首先在代理层执行hash,以确保不同系统缓存的数据平衡和负载平衡。一般来说,我们会做模具工作,并将服务分配给其他机器。但是,在这种情况下,如果服务关闭或新系统加入,将直接影响所有系统的缓存。为了解决这个问题,出现了一致性哈希算法。

如何解决

一致性散列算法主要用于解决散列后将值映射到已设置系统的方法。下面是散列阶段。

1.将散列值组织成圆环。通常为[0,2 32-1] 2。均匀选择圆环上的Hash点作为系统的节点。3.访问机器时,Hash接触到圆环上的一点。顺时针访问的个节点是需要访问的机器

这样,当一台机器停机时,停机机器的下一台机器将委托停机机器的存储工作。将系统节点添加到Hash环路中的两个系统节点后,原始节点存储操作将被分为新添加的节点上的部分存储操作。

升华

一般来说,使用上述一致性哈希算法,发生停机时,一台机器做两台机器工作显然是不科学的。因此,虚拟节点的概念也是必需的。将虚拟节点放置在循环中,然后实际服务节点维护多个虚拟节点。此外,一个服务节点的多个虚拟节点必须单独分布。这样,当一个服务节点停机时,多个单独的虚拟节点将从散列循环中消失,这样,正常的系统就可以在保留现有数据的同时,承载停机时间对应的单独节点的负载。

一致哈希算法的golang实现

Github.com/stathat/consistent是golang实施的一致散列算法。

数据结构

在实现中,在分布式缓存中添加了更有用的副本概念。结构如下:

Type Consistent struct {

circle map[uint 32]字串//储存环

Members map[string]bool //成员标记

sorted hashes uints/[]int 32类型显示环的虚拟节点,排序的slice

NumberOfReplicas int //副本数

Count int64 //节点数

划痕[64]字节//未使用

UseFnv bool //标记使用FNV-1a hash

Sync .RWMutex //读写锁定标记

}

设置节点

初始化节点时,必须提供每个节点的名称和副本数。初始化将执行以下任务:

将Hash和node名称之间的映射保存在circle中

将Members显示为true

将散列值放入已排序的sorted hash中

func(c * consistent)set(elts[]string){

C.Lock()

Defer c.Unlock()

For k :=range c.members {//首先删除elts集合中没有的数据

Found :=false

For _,v :=range elts {

If k==v {

Found=true

布雷克

}

}

If!Found {

C.remove(k)

}

}

For _,v :=范围elts {//后面依次添加

_,exists 3360=c . members[v]

If exists {

Continue

}

C.add(v)

}

}

Func (c *一致性)add (ELT string) {

FOR I :=0;I c . NumberOfReplicasI {

c . circle[c . hash key(c . ELT key(ELT,I)]=ELT

}

C.members[elt]=true

更新c . updatesortedhashes()//sorted hashes字段以确认顺序

C.count

}

访问

通过Name映射node时,首先计算hash值,然后通过二进制查找方法从sortedHashes slice中获取该node的hash值,再通过circle映射该node name。

Func (c *一致性)get(名称字符串) (字符串,错误){

C.RLock()

Defer c.RUnlock()

If len(c.circle)==0 {

Return ' ',ErrEmptyCircle

}

密钥3360=C .散列密钥(name)

I:=c.search(键)

return c . circle[c . sorted hashes[I],nil

}

删除

一个系统停机后,可以删除该节点节点,快速调整服务请求。

Func (c *一致性)remove (ELT string) {

//代码有锁

FOR I :=0;I c . NumberOfReplicasI {

删除(C. circle,C. hash key (C. ELT key (ELT,I)))

}

删除(C. members,ELT)

C.updateSortedHashes()

C.count -

}

摘要

在代码实现中,我们可以看到:

要在环形中找到下一个节点,只需将所有节点的哈希值存储在有序切片中,然后进行平分查询即可。为了保持每个节点数据的平衡,通常会添加更多的虚拟节点,为了保证访问请求的速度,不能添加太多的虚拟节点。例如,在Codis上,虚拟节点默认设置为1024个(当然,还可以配置更多插槽)。

调整一致性散列服务时,可能会过度平滑

分布式缓存服务Redis-Cluster、Codis比较常见的应用程序或服务代理twemproxy等。

相关文章
我们已经准备好了,你呢?
2024我们与您携手共赢,为您的企业形象保驾护航