聊聊dubbogo的ConsistentHashLoadBalance

编程

本文主要研究一下dubbo-go的ConsistentHashLoadBalance

ConsistentHashLoadBalance

dubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go

const (

// ConsistentHash ...

ConsistentHash = "consistenthash"

// HashNodes ...

HashNodes = "hash.nodes"

// HashArguments ...

HashArguments = "hash.arguments"

)

var (

selectors = make(map[string]*ConsistentHashSelector)

re = regexp.MustCompile(constant.COMMA_SPLIT_PATTERN)

)

func init() {

extension.SetLoadbalance(ConsistentHash, NewConsistentHashLoadBalance)

}

// ConsistentHashLoadBalance ...

type ConsistentHashLoadBalance struct {

}

// NewConsistentHashLoadBalance ...

func NewConsistentHashLoadBalance() cluster.LoadBalance {

return &ConsistentHashLoadBalance{}

}

  • ConsistentHashLoadBalance的init方法设置了名为consistenthash的ConsistentHashLoadBalance到extension中

Select

dubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go

// Select ...

func (lb *ConsistentHashLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker {

methodName := invocation.MethodName()

key := invokers[0].GetUrl().ServiceKey() + "." + methodName

// hash the invokers

bs := make([]byte, 0)

for _, invoker := range invokers {

b, err := json.Marshal(invoker)

if err != nil {

return nil

}

bs = append(bs, b...)

}

hashCode := crc32.ChecksumIEEE(bs)

selector, ok := selectors[key]

if !ok || selector.hashCode != hashCode {

selectors[key] = newConsistentHashSelector(invokers, methodName, hashCode)

selector = selectors[key]

}

return selector.Select(invocation)

}

  • Select方法遍历invokers挨个执行json.Marshal(invoker),将bytes[]添加到bs中,之后通过crc32.ChecksumIEEE(bs)计算hashCode,然后对比selectors[key]的hashCode与计算出来的hashCode是否一致,不一致则通过newConsistentHashSelector重新设置一个,最后执行selector.Select(invocation)

ConsistentHashSelector

dubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go

// ConsistentHashSelector ...

type ConsistentHashSelector struct {

hashCode uint32

replicaNum int

virtualInvokers map[uint32]protocol.Invoker

keys Uint32Slice

argumentIndex []int

}

  • ConsistentHashSelector定义了hashCode、replicaNum、virtualInvokers、keys、argumentIndex属性

newConsistentHashSelector

dubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go

func newConsistentHashSelector(invokers []protocol.Invoker, methodName string,

hashCode uint32) *ConsistentHashSelector {

selector := &ConsistentHashSelector{}

selector.virtualInvokers = make(map[uint32]protocol.Invoker)

selector.hashCode = hashCode

url := invokers[0].GetUrl()

selector.replicaNum = int(url.GetMethodParamInt(methodName, HashNodes, 160))

indices := re.Split(url.GetMethodParam(methodName, HashArguments, "0"), -1)

for _, index := range indices {

i, err := strconv.Atoi(index)

if err != nil {

return nil

}

selector.argumentIndex = append(selector.argumentIndex, i)

}

for _, invoker := range invokers {

u := invoker.GetUrl()

address := u.Ip + ":" + u.Port

for i := 0; i < selector.replicaNum/4; i++ {

digest := md5.Sum([]byte(address + strconv.Itoa(i)))

for j := 0; j < 4; j++ {

key := selector.hash(digest, j)

selector.keys = append(selector.keys, key)

selector.virtualInvokers[key] = invoker

}

}

}

sort.Sort(selector.keys)

return selector

}

  • newConsistentHashSelector方法实例化ConsistentHashSelector,并初始化virtualInvokers、hashCode、argumentIndex、keys、virtualInvokers属性

Select

dubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go

// Select ...

func (c *ConsistentHashSelector) Select(invocation protocol.Invocation) protocol.Invoker {

key := c.toKey(invocation.Arguments())

digest := md5.Sum([]byte(key))

return c.selectForKey(c.hash(digest, 0))

}

func (c *ConsistentHashSelector) toKey(args []interface{}) string {

var sb strings.Builder

for i := range c.argumentIndex {

if i >= 0 && i < len(args) {

fmt.Fprint(&sb, args[i].(string))

}

}

return sb.String()

}

func (c *ConsistentHashSelector) selectForKey(hash uint32) protocol.Invoker {

idx := sort.Search(len(c.keys), func(i int) bool {

return c.keys[i] >= hash

})

if idx == len(c.keys) {

idx = 0

}

return c.virtualInvokers[c.keys[idx]]

}

func (c *ConsistentHashSelector) hash(digest [16]byte, i int) uint32 {

return uint32((digest[3+i*4]&0xFF)<<24) | uint32((digest[2+i*4]&0xFF)<<16) |

uint32((digest[1+i*4]&0xFF)<<8) | uint32(digest[i*4]&0xFF)&0xFFFFFFF

}

  • Select方法通过c.toKey(invocation.Arguments())获取key,再通过md5.Sum([]byte(key))计算digest,最后通过c.selectForKey(c.hash(digest, 0))选取Invoker

小结

ConsistentHashLoadBalance的Select方法遍历invokers挨个执行json.Marshal(invoker),将bytes[]添加到bs中,之后通过crc32.ChecksumIEEE(bs)计算hashCode,然后对比selectors[key]的hashCode与计算出来的hashCode是否一致,不一致则通过newConsistentHashSelector重新设置一个,最后执行selector.Select(invocation)

doc

  • consistent_hash

以上是 聊聊dubbogo的ConsistentHashLoadBalance 的全部内容, 来源链接: utcz.com/z/519275.html

回到顶部