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

leastActiveLoadBalance

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

const (
    // LeastActive ...
    LeastActive = "leastactive"
)

func init() {
    extension.SetLoadbalance(LeastActive, NewLeastActiveLoadBalance)
}

type leastActiveLoadBalance struct {
}

// NewLeastActiveLoadBalance ...
func NewLeastActiveLoadBalance() cluster.LoadBalance {
    return &leastActiveLoadBalance{}
}
  • leastActiveLoadBalance的NewLeastActiveLoadBalance方法创建leastActiveLoadBalance

Select

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

func (lb *leastActiveLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker {
    count := len(invokers)
    if count == 0 {
        return nil
    }
    if count == 1 {
        return invokers[0]
    }

    var (
        leastActive  int32                = -1 // The least active value of all invokers
        totalWeight  int64                     // The number of invokers having the same least active value (LEAST_ACTIVE)
        firstWeight  int64                     // Initial value, used for comparison
        leastCount   int                       // The number of invokers having the same least active value (LEAST_ACTIVE)
        leastIndexes = make([]int, count)      // The index of invokers having the same least active value (LEAST_ACTIVE)
        sameWeight   = true                    // Every invoker has the same weight value?
    )

    for i := 0; i < count; i++ {
        invoker := invokers[i]
        // Active number
        active := protocol.GetMethodStatus(invoker.GetUrl(), invocation.MethodName()).GetActive()
        // current weight (maybe in warmUp)
        weight := GetWeight(invoker, invocation)
        // There are smaller active services
        if leastActive == -1 || active < leastActive {
            leastActive = active
            leastIndexes[0] = i
            leastCount = 1 // next available leastIndex offset
            totalWeight = weight
            firstWeight = weight
            sameWeight = true
        } else if active == leastActive {
            leastIndexes[leastCount] = i
            totalWeight += weight
            leastCount++

            if sameWeight && (i > 0) && weight != firstWeight {
                sameWeight = false
            }
        }
    }

    if leastCount == 1 {
        return invokers[0]
    }

    if !sameWeight && totalWeight > 0 {
        offsetWeight := rand.Int63n(totalWeight) + 1
        for i := 0; i < leastCount; i++ {
            leastIndex := leastIndexes[i]
            offsetWeight -= GetWeight(invokers[i], invocation)
            if offsetWeight <= 0 {
                return invokers[leastIndex]
            }
        }
    }

    index := leastIndexes[rand.Intn(leastCount)]
    return invokers[index]
}
  • Select方法遍历invokers,挨个通过protocol.GetMethodStatus(invoker.GetUrl(), invocation.MethodName()).GetActive()获取active信息,并通过GetWeight(invoker, invocation)获取weight,然后计算leastCount、totalWeight、sameWeight;对于leastCount为1的返回invokers[0],对于sameWeight为false且totalWeight大于0的,遍历leastIndexes,计算offsetWeight,若offsetWeight小于等于0,则返回invokers[leastIndex],否则通过leastIndexes[rand.Intn(leastCount)]计算index,返回invokers[index]

GetWeight

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

// GetWeight ...
func GetWeight(invoker protocol.Invoker, invocation protocol.Invocation) int64 {
    url := invoker.GetUrl()
    weight := url.GetMethodParamInt64(invocation.MethodName(), constant.WEIGHT_KEY, constant.DEFAULT_WEIGHT)

    if weight > 0 {
        //get service register time an do warm up time
        now := time.Now().Unix()
        timestamp := url.GetParamInt(constant.REMOTE_TIMESTAMP_KEY, now)
        if uptime := now - timestamp; uptime > 0 {
            warmup := url.GetParamInt(constant.WARMUP_KEY, constant.DEFAULT_WARMUP)
            if uptime < warmup {
                if ww := float64(uptime) / float64(warmup) / float64(weight); ww < 1 {
                    weight = 1
                } else if int64(ww) <= weight {
                    weight = int64(ww)
                }
            }
        }
    }
    return weight
}
  • GetWeight方法通过url.GetMethodParamInt64(invocation.MethodName(), constant.WEIGHT_KEY, constant.DEFAULT_WEIGHT)获取weight,若weight大于0,则计算warmup,重新计算weight值

小结

leastActiveLoadBalance的NewLeastActiveLoadBalance方法创建leastActiveLoadBalance;Select方法遍历invokers,挨个通过protocol.GetMethodStatus(invoker.GetUrl(), invocation.MethodName()).GetActive()获取active信息,并通过GetWeight(invoker, invocation)获取weight,然后计算leastCount、totalWeight、sameWeight,最后计算index

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...


引用和评论

0 条评论