一致性哈希的实现

在网关系统的实现中,需要提供对session一致性的支持,而网关系统通过hash一致性来支持session一致性。
一致性哈希实现的难点在于一是需要让key尽量分别均匀,二是需要考虑到目标节点动态变化的情况。

一 哈希环实现

参考rpc框架中kitc 客户端哈希一致性的实现:
负责哈希一致性的负载类实现

type KeyFunc func(ctx context.Context, req interface{}) (string, error)
type ConsistBalancer struct {
	GetKey KeyFunc
	backup LoadBalancer
	// 	为了使key尽量均匀分布于节点上,引入虚拟节点
	replicas int

	instanceInfo map[string][]*discovery.Instance
	sortedHash []uint64 
	hash2Ins map[uint64]*discovery.Instance
	lock lock.RWMutex
}

Picker 选择器实现:

func (cb *ConsistBalancer) NewPicker(ctx context.Context, req interface{}, key string, instances []*discovery.Instance) Picker {
	...
	hashKey, err := cb.GetKey(ctx, req)
	if err != nil {...}
	intList := cb.search(hash(hashKey))
	if len(intList) == 0 {...}
	return &consistBalancePicker{intList}
}
func (cb *ConsistBalancer) search(hashCode uint64) []*discovery.Instance {
	results := make([]*discovery.Instance, 0, 3)
	dup := make(map[string]struct{}, 0, 3)
	cb.Lock.RLock()
	defer cb.Lock.RULock()
	index := sort.Search(len(cb.sortedHash), func(x int) bool {
		return cb.soredHash[x] > hashCode
	})
	if index == len(cb.sortedHash) { index = 0 }
	for i = 0; i<len(sortedHash); i++ {
		ins := cb.hash2Ins[cb.sortedHash[index]]
		// instanceKey 根据ins信息生成string
		key = instanceKey(ins)
		if _, ok := dup[key]; ok {
			index = (index + 1) % len(cb.sortedHash)
			continue
		}
		dup[key] = struct{}{}
		results = append(results, ins)
		index = (index + 1) % len(cb.sortedHash)
		if len(results) == 3 {
			break
		}
	}
	return results
}
type consistBalancePicker struct {
	insList []*discovery.Instance
}
func (cbp *ConsistBalancePicker) Pick() (*discovery.Instance, bool){
	if len(cbp.insList) == 0 { ... }
	ret := cbp.insList[0]
	cbp.insList = cbp.insList[1:]
	return ret, true
}

节点信息更新实现:

func (cb *consistBalancer) Rebalance(key string, insList []*discovery.Instance) {
	var oldInsList []*discovery.Instance
	if  !cb.isExitKey(key) {
		goto DoRebalance
	}
	cb.Lock.RLock()
	oldInsList = cb.instanceInfo[key]
	cb.Lock.RUnlock()
	if len(insList) == len(oldInsList) {
		newMap, oldMap := make(map[string]struct{}, len(insList), make(map[string]struct{}, len(insList)
		for _, ins := range insList {
			newMap[instanceKey(ins)] = struct{}{}
		}
		for _, ins := range oldList {
			oldMap[instanceKey(ins)] = struct{}{}
		}
		if len(newMap) == len(oldMap) {
			for k := range newMap {
				if _, ok := oldMap[key]; !ok {
					goto DoRebalance
				}
			}
			return
		}
	}

DoRebalane :
	cb.Rebalance(key, insList)
}

func (cb *ConsistBalancer) Rebalance(key string, insList []*discovery.Instance) {
	cb.Lock.Lock()
	cb.instanceInfo[key] = insList
	totalLen = 0
	for _, instances := range cb.instanceInfo {
		totalLen += len(instances)
	}
	sortedHash := make([]uint64, 0, totalLen*cb.replicas)
	hash2Ins := make(map[uint64]*discovery.Instance,totalLen*cb.replicas)
	for _, insList := range cb.instanceInfo {
		for _, ins := range insList {
			for i:= 0;i<=cb.replicas;i++ {
				key := fmt.Sprintf("%v:%v",instanceKey(ins), i)
				hashcode := hash(key)
				sortedHash = append(sortedHash, hashcode)
				hash2Ins[hashcode] = ins
			}
		}
	}
	sort.Slice(sortedHash, func(i, j int) bool {
		return sortedHash[i] < sortedHash[j]
	} 
	cb.hash2Ins = hash2Ins
	cb.sortedHash = sortedHash
	cb.Lock.UnLock()
}
func instanceKey(ins *discovery.Instance) string {
	return ins.Host + ":" + ins.Port
}
func hash(key string) uint64 {
	return xxhash.Sum64String(key)
}
二 谷歌哈希一致性算法

具体可以参考:
谷歌哈希一致性算法
实现方式:

var DefaultHasher hash.Hash64 = crc64.New(crc64.MakeTable(crc64.ECMA))
func Hash(key uint64, buckets int32) int32 {
	var b, j int64
	if bucket <= 1 {
		buckets = 1
	}
	for j< int64(buckets) {
		b = j
		key = key * 2862933555777941757 + 1
		j = int64(float(b+1)*float64(int64(1)<<31) / float64((key>>33)+1)))
	}
	return int32(b)
}
// key为string时调用的方法
func HashString (key string, buckets int32) int32 {
	return hashStringWithHasher(key, buckets, DefaultHasher)
}
func HashStringWithHasher(key string, buckets int32, hasher hash.Hash64) int32 {
	hasher.Reset()
	hasher.Write([]byte(key))
	return Hash(hasher.Sum64(), buckets)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值