第五周作业

用户头像
秦宝齐
关注
发布于: 2020 年 07 月 04 日

一致性hash内存环,10台node,200台虚拟node,百万key,

测试了golang中自带3种hash函数,crc32、fnv、adler32、xxhash

map[1:99776 2:100093 3:100262 4:99971 5:100168 6:99899 7:99912 8:100246 9:99723 10:99950]

*crc32.digest 标准差:177.26364545501144

map[1:99848 2:99340 3:100800 4:99700 5:100040 6:99234 7:100506 8:100178 9:99852 10:100502]

*fnv.sum32 标准差:483.59983457399983

map[1:106845 2:95337 3:94924 4:106153 5:98051 6:100011 7:101243 8:103853 9:98930 10:94653]

*adler32.digest 标准差:4267.873803195216

map[1:99564 2:100353 3:99833 4:99766 5:99997 6:99927 7:100251 8:100206 9:100281 10:99822]

*main.xxhashAdapter 标准差:248.75087939543047



结果:crc32>xxhash>fnv>adler32



package main
import (
"errors"
"fmt"
"github.com/cespare/xxhash/v2"
"hash"
"hash/adler32"
"hash/crc32"
"hash/fnv"
"math"
"sort"
)
func main() {
nodeIds := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
test(newRing(nodeIds, func() hash.Hash32 {
return crc32.NewIEEE()
}))
test(newRing(nodeIds, func() hash.Hash32 {
return fnv.New32()
}))
test(newRing(nodeIds, func() hash.Hash32 {
return adler32.New()
}))
test(newRing(nodeIds, func() hash.Hash32 {
return new(xxhashAdapter)
}))
//扩容后
ring := newRing(nodeIds, func() hash.Hash32 {
return crc32.NewIEEE()
})
for i := 1; i < 11; i++ {
ring.addNode(10 + i)
}
test(ring)
}
type xxhashAdapter struct {
xxhash.Digest
}
func (a *xxhashAdapter) Sum32() uint32 {
return uint32(a.Sum64())
}
func test(ring *Ring) {
keyCount := 1000000
counter := make(map[int]int)
for i := 0; i < keyCount; i++ {
n, _ := ring.getNode(fmt.Sprintf("%s%d", "key", i))
if counter[n] == 0 {
counter[n] = 1
} else {
counter[n] = counter[n] + 1
}
}
fmt.Println(counter)
//计算标准差
average := keyCount / len(ring.actualNodes)
var sum float64
for _, v := range counter {
sum += math.Pow(float64(v)-float64(average), 2)
}
fmt.Printf(fmt.Sprintf("%T 标准差:%v\n", ring.hasher(), math.Sqrt(sum/(float64(len(ring.actualNodes))))))
}
type Ring struct {
size int
virtualCount int
virtualNodes []*Node
virtualNodesMap map[int][]*Node
actualNodes []*Node
step int
hasher func() hash.Hash32
}
type Node struct {
id int
index int
}
func newRing(nodeIds []int, hasher func() hash.Hash32) *Ring {
ring := &Ring{
virtualCount: 200,
virtualNodes: make([]*Node, 0),
actualNodes: make([]*Node, 0),
virtualNodesMap: map[int][]*Node{},
hasher: hasher,
size: 1000000,
}
for nodeId := range nodeIds {
ring.actualNodes = append(ring.actualNodes, &Node{id: nodeId})
}
ring.step = 1000000 / ring.virtualCount
index := 0
for i := 0; i < ring.virtualCount; {
for _, nodeId := range nodeIds {
index = i * ring.step
n := &Node{id: nodeId, index: index}
ring.virtualNodesMap[n.id] = append(ring.virtualNodesMap[n.id], n)
i++
}
}
ring.rebalanceVirtualNodes()
return ring
}
func (r *Ring) getNode(key string) (node int, error error) {
if len(r.virtualNodes) == 0 {
return 0, errors.New("no actual nodes")
}
hash := r.hasher()
hash.Reset()
hash.Write([]byte(key))
//fmt.Println(hash.Sum32())
index := int(hash.Sum32() % uint32(r.size))
//fmt.Println(index)
return r.virtualNodes[(index/r.step+1)%len(r.virtualNodes)].id, nil
}
func (r *Ring) addNode(newNodeId int) error {
if len(r.actualNodes) == 0 {
return errors.New("no actual nodes")
}
//rebalance的逻辑:新增节点讨'百家饭',从'大户'开始吃,一家一口,吃到新节点virtual node count达到virtual nodes quotient/actual nodes count均值为止
//不考虑并发
newNodes := make([]*Node, 0)
nodeSorter := r.getNodeSorter()
sort.Sort(sort.Reverse(nodeSorter))
//sort.Sort(nodeSorter)
quotient := len(r.virtualNodes) / (len(r.actualNodes) + 1) / len(r.actualNodes)
mod := len(r.virtualNodes) / (len(r.actualNodes) + 1) % len(r.actualNodes)
for i, nodes := range nodeSorter {
j := quotient
if i < mod {
j += 1
}
for n := 0; n < j; n++ {
n := &Node{newNodeId, nodes[n].index}
newNodes = append(newNodes, n)
}
r.virtualNodesMap[nodes[0].id] = r.virtualNodesMap[nodes[0].id][j:]
}
r.actualNodes = append(r.actualNodes, &Node{id: newNodeId})
r.virtualNodesMap[newNodeId] = newNodes
r.rebalanceVirtualNodes()
return nil
}
func (r *Ring) rebalanceVirtualNodes() {
nodes := make([]*Node, 0)
for _, v := range r.virtualNodesMap {
nodes = append(nodes, v...)
}
sort.Sort(SortByIndex(nodes))
r.virtualNodes = nodes
}
type SortByNodeCount [][]*Node
func (r *Ring) getNodeSorter() SortByNodeCount {
virtualNodes := make([][]*Node, 0)
for _, vn := range r.virtualNodesMap {
virtualNodes = append(virtualNodes, vn)
}
return virtualNodes
}
func (ns SortByNodeCount) Len() int {
return len(ns)
}
func (ns SortByNodeCount) Less(i, j int) bool {
if len(ns[i]) == len(ns[j]) && len(ns[i]) != 0 && len(ns[j]) != 0 {
return ns[i][0].index < ns[j][0].index
} else {
return len(ns[i]) < len(ns[j])
}
}
func (ns SortByNodeCount) Swap(i, j int) {
tmp := ns[i]
ns[i] = ns[j]
ns[j] = tmp
}
type SortByIndex []*Node
func (vns SortByIndex) Len() int {
return len(vns)
}
func (vns SortByIndex) Less(i, j int) bool {
return vns[i].index < vns[j].index
}
func (vns SortByIndex) Swap(i, j int) {
tmp := vns[i]
vns[i] = vns[j]
vns[j] = tmp
}



发布于: 2020 年 07 月 04 日 阅读数: 82
用户头像

秦宝齐

关注

还未添加个人签名 2020.03.26 加入

还未添加个人简介

评论

发布
暂无评论
第五周作业