ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

从groupcache看一致性哈希

2022-08-11 02:01:56  阅读:158  来源: 互联网

标签:hash key keys 哈希 groupcache 一致性 服务器 节点


一致性哈希(consistenthash)

什么是一致性哈希

在分布式缓存中,假设我们有3台缓存服务器,我们有三万张图片要缓存数据要分配到这三台服务器上,常见的做法就是哈希,用图片名对服务器的个数取模,根据取模结果分配,这样就可以分配的很均匀。但是,如果3台机器不够,要加机器呢?这时候,机器数变了,那么之前key和服务器之间的对应关系就变了,这就意味着你的缓存在一定时间里就失效了。
因此基于传统哈希算法的缺陷,就很危险。于是就有了一致性哈希算法。一致性哈希算法可以保证当机器增加或者减少的时候,节点之间的数据迁移仅限于两个节点之间。

一致性哈希的原理

一致性哈希怎么做呢,他不对机器个数取模,而是对2^32次方取模,它的流程是这样的:
● 一致性哈希算法将整个哈希值空间按照顺时针组成一个换,叫哈希环,(就是一个有2^32个坑的环)
● 对服务器的标识(名字或者地址)做哈希,确定每个服务器在哈希环上的位置。
● 对数据的key做哈希,确定数据在哈希环上的位置,然后顺时针走,第一台遇到的服务器就是它定位到的服务器。
在这个时候,增减机器的时候,只会涉及到一部分数据的重定位,而不是大多数的数据。
优点:
○ 简单对服务器数量取模,增减机器的时候很可能会造成缓存的雪崩。而一致性哈希算法在增减机器的时候,只需重定位环空间一小部分的数据,只有部分缓存失效,具有较好的容错性和可扩展性。

扩展:缓存雪崩
缓存雪崩是指一段时间内缓存中大批量数据过期了,然后一大堆请求打到了后端数据库上,然后数据库扛不住了。

哈希环的倾斜和虚拟节点

当节点较少的时候,很可能出现哈希环的倾斜现象,这个现象是这样的:节点在哈希环上的位置都比较近,那么顺时针来看,第一个节点要负责环上一大部分数据,缓存的对象大部分集中到了一台服务器上,这样还是有可能造成数据不均匀的现象,再严重就是服务器的崩溃。
盗个图:

解决方法:虚拟节点
虚拟节点的本质就是让哈希环上的节点尽可能地多,可以对服务器地标识多次哈希,最终每个机器在换上都有多个节点,这样可以解决倾斜问题。
(后面又看到又chord算法,分布式哈希什么的, 越来越多了,后面还是专门写一篇文章吧)

GroupCache的实现

GroupCache的一致性哈希实现非常地简单,代码总共60多行。
type Hash func(data []byte) uint32

type Map struct {
hash Hash
replicas int
keys []int // Sorted
hashMap map[int]string
}

func New(replicas int, fn Hash) *Map {
m := &Map{
replicas: replicas,
hash: fn,
hashMap: make(map[int]string),
}
if m.hash == nil {
m.hash = crc32.ChecksumIEEE
}
return m
}
首先,定义了Map结构体,里面的hash是哈希函数,默认是go标准库里的crc.32CheckSumIEEE,keys存放排序后的节点的哈希值,hashMap存储哈希值和节点的映射。replicas代表一个服务器在哈希环上有几个节点。
接下来看它的存取过程:
加入:
// Add adds some keys to the hash.
func (m *Map) Add(keys ...string) {
for _, key := range keys {
for i := 0; i < m.replicas; i++ {
hash := int(m.hash([]byte(strconv.Itoa(i) + key)))
m.keys = append(m.keys, hash)
m.hashMap[hash] = key
}
}
sort.Ints(m.keys) // 必须得排序
}
可以看到第二重循环循环了replicas次,将一个服务器哈希多次,然后存到keys这个数组里面进行排序,通过hashMap建立映射。
取出:
// Get gets the closest item in the hash to the provided key.
func (m *Map) Get(key string) string {
if m.IsEmpty() {
return ""
}

hash := int(m.hash([]byte(key)))

// Binary search for appropriate replica.
// 二分查找
idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash })

// Means we have cycled back to the first replica.
if idx == len(m.keys) {
	idx = 0
}

return m.hashMap[m.keys[idx]]

}
查找就是将数据的key做一个哈希,然后根据这个哈希做二分查找,然后找到合适的去hashMap中取节点信息。
我细看了一下sort.Search,这个函数根据传入的函数做判断,会返回第一个判断结果为true的index。所注意这个函数是寻找左边界的二分查找(区间定为左闭右开,然后mid匹配上的时候,将mid-1作为右边界,最后返回左边界)。如果Search查不到符合要求的值,就会返回切片长度。因此上面的会这样写。这也是一个常见的循环数组查找的写法吧。

标签:hash,key,keys,哈希,groupcache,一致性,服务器,节点
来源: https://www.cnblogs.com/yumingkuan/p/16574511.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有