一致性哈希算法主要使用在分布式数据存储系统中,按照必定的策略将数据尽量均匀分布到全部的存储节点上去,使得系统具备良好的负载均衡性能和扩展性。html
详细能够看这篇文章:git
实现:github
源码url:
https://github.com/golang/groupcache/blob/master/consistenthash/consistenthash.gogolang
type Map struct { hash Hash // hash 函数 replicas int keys []int // Sorted hashMap map[int]string }
Map 结构,定义核心数据结构,其中hash
是哈希函数,用于对key进行hash,keys
字段保存全部的节点(包括虚拟节点)是可排序的,hashmap
则是虚拟节点到真实节点的映射。算法
一致性哈希算法在服务节点太少时,容易由于节点分部不均匀而形成数据倾斜问题。一致性哈希算法引入了虚拟节点机制,即对每个服务节点计算多个哈希,每一个计算结果位置都放置一个此服务节点,称为虚拟节点。replicas
是指的是每一个节点和虚拟节点的个数。express
// 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) }
Map的Add方法,添加节点到圆环,参数是一个或者多个string,对每个key关键字进行哈希,这样每台机器就能肯定其在哈希环上的位置,在添加每一个关键字的时候,并添加对应的虚拟节点,每一个真实节点和虚拟节点个数有replicas
字段指定,保存虚拟节点到真实节点的对应关系到hashmap字段。apache
好比在测试用例中, hash.Add("6", "4", "2")
,则全部的节点是 2, 4, 6, 12, 14, 16, 22, 24, 26
, 当has.Get('11') 时,对应的节点是12,而12对应的真实节点是2服务器
hash.Add("6", "4", "2")
是数据值:数据结构
2014/02/20 15:45:16 replicas: 3 2014/02/20 15:45:16 keys: [2 4 6 12 14 16 22 24 26] 2014/02/20 15:45:16 hashmap map[16:6 26:6 4:4 24:4 2:2 6:6 14:4 12:2 22:2]
// 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))) // 顺时针“行走”,找到第一个大于哈希值的节点 for _, v := range m.keys { if v >= hash { return m.hashMap[v] // 返回真实节点 } } // hash值大于最大节点哈希值的状况 return m.hashMap[m.keys[0]] }
Get方法根据提供的key定位数据访问到相应服务器节点,算法是:将数据key使用相同的哈希函数H计算出哈希值h,通根据h肯定此数据在环上的位置,今后位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器。app
附groupcache consistent hash算法源码:
/* Copyright 2013 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // Package consistenthash provides an implementation of a ring hash. package consistenthash import ( "hash/crc32" "sort" "strconv" ) 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 } // Returns true if there are no items available. func (m *Map) IsEmpty() bool { return len(m.keys) == 0 } // 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) } // 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))) // Linear search for appropriate replica. for _, v := range m.keys { if v >= hash { return m.hashMap[v] } } // Means we have cycled back to the first replica. return m.hashMap[m.keys[0]] }