首页 > 编程知识 正文

哈希算法例题,哈希算法的基本原理

时间:2023-05-04 23:41:00 阅读:165377 作者:4678

一致且快速的go get-ugithub.com/junhai Deng/consistent是c :=consistent.new (IPS :=[ ] string (192.168.0.0 ) ) IP:=rangeIPS{c.add(IP ) }fmt.println(IP: (,c.get ) )/Hello.txt首先,我们来看一下引入集群时可能出现的问题。 例如,我现在有五台Redis服务器,并且正常运行了很长时间。 不凑巧的是有一天,A服务器崩溃了。 此时,还有4台服务器,系统正常运行。 A发送到服务器的请求一定要考虑重定向的方法吧。 如果我们使用一般的快速茶函数进行分配的话,肯定是hash(key ) ) n但是,因为num现在是num-1,所以很有可能所有的请求都被变更后发送到其他服务器,发送到b的请求会被重新处理

为了避免这样的大移动,可以使用一致且迅速的茶。

虽然在算法原理上也使用了一致性快的茶叶模型,但是与普通的快茶不同,我们进行的是2^32的模型,而不是服务器的数量。 也就是说,相当于对一个固定的数量进行合模。 可以认为所有快茶值空间都构成了一个圆环。 下图:

如果有多台服务器,则根据某个属性计算茶叶值,例如IP地址,并将其映射到圆环上的相应节点。 假设现在我有三个节点,映射的结果为以下:

当收到某个请求时,根据其中的某个属性计算迅速的闹剧值,例如HTTP请求的路径、标题信息等,假设映射到以下位置

根据映射目标,顺时针旋转第一个发现的服务器节点,作为此请求中选择的服务器节点,即Web服务器。

我们的某个服务器崩溃时,例如b崩溃的情况下,a请求根据快速一致的聊天原理被分配给服务器节点c,更一般地说,[a,B]范围内的请求被重新分配给服务器节点c。 这与前面提到的一般快速的聊天函数不同。

但是,上述算法在某些情况下并不奏效。 例如,服务节点的分布

如果c1节点占用的空间约为2/3,且请求分配非常不均匀,请按如下方式设置多个节点的副本:

这样处理的话,会比以前均匀很多。 理论上,副本数量越多,分配越均匀,但同时也会增加管理难度,所以不要太大。

算法的实现首先简单说一下想法吧。 根据上面的原理,我们需要:

hash函数:支持多拷贝服务器节点映射:快茶值-服务器节点映射取值范围:上述取值环type consistent struct {//拷贝数replicas int//全部与节点相对应的serverserversmap [ uint 32 ] string///保存所有索引,即hash圆环上的节点circleuints//typeuints [ ] uint 32///可直接决定节点分布情况的hashhsync.rwmutex}当一个服务器节点进行映射时,多个快速的茶值(

但是,我们不需要保存2^31-1的大序列。 你只需要维持有序的排列就可以了。 当一个请求到来时,我们只需要获得其快捷茶值对应于顺时针下一个节点快捷茶值的服务器节点即可

快速茶函数快速茶函数应该可以支持多个副本。 方式有很多种,这里也可以采用简单的方式进行定制

import(hash/fnv ) strconv )/Replicafunchash ) keystring,numint(uint32 ) h:=fnv.new32 ) h.write([]byte

每次添加servers 3360=make (map [ uint 32 ] string )映射值范围circle :=make ([ uint 32,0 ] )节点时,都必须更改顺序。

for i :=0; i replicas; I{key:=hash(node,I ) circle=append ) c.circle,key ) servers[key]=node ) /排序sort.sort ) c.circle

支持的方法主要不多,但基本的有:

添加typeconsistenthasherinterface//节点add (

lot string)// 删除节点Delete(slot string)// 数据对应的节点Get(key string) string}

添加服务器节点上面已经说了,删除节点的主要代码如下:

func (c *consistent) Delete(node string) {c.Lock()defer c.Unlock()// 删除节点delete(c.nodes, node)// 因为在数组中删除元素不方便,这里先记录一下需要删除的数据// 然后如果在这里面的数据就不再添加到新的记录中memo := make(map[uint32]struct{})// 删除hash圆环中的值for i := 0; i < c.replicas; i++ {key := c.hashKey(node, i)memo[key] = struct{}{}delete(c.servers, key)}// 创建一个新的保存newCircle := make(uints, 0, c.circle.Len()-c.replicas)for i := 0; i < c.circle.Len(); i++ {if _, ok := memo[c.circle[i]]; !ok {newCircle = append(newCircle, c.circle[i])}}c.circle = newCircle}

当我们需要获取一个请求对应的服务器节点的时候,我们只要搜索到顺序针第一个服务器节点即可,因为迅速的嚓茶值有序,这里可以采用二分查找的方式

// Get 获取到属于的server节点func (c *consistent) Get(name string) string {c.RLock()defer c.RUnlock()// 首先将hash找到key := c.hash(name)// 然后在Hash圆环上找到对应的节点i := sort.Search(len(c.circle), func(i int) bool { return c.circle[i] >= key }) // 顺时针计算应该就是第一个节点了 if i >= c.circle.Len() {i = 0}return c.servers[c.circle[i]]} 总结

一致性迅速的嚓茶在加入和删除节点的时候只会影响相邻的节点,对其他的节点无影响。当节点数量发生变化,我们不希望映射关系全部被打乱的时候,可以采用该算法。

具体的实现代码可从微信公众号推文中获取~

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。