dubbo.apache.org/dubbo-go/v3@v3.1.1/cluster/loadbalance/leastactive/loadbalance.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package leastactive 19 20 import ( 21 "math/rand" 22 ) 23 24 import ( 25 "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance" 26 "dubbo.apache.org/dubbo-go/v3/common/constant" 27 "dubbo.apache.org/dubbo-go/v3/common/extension" 28 "dubbo.apache.org/dubbo-go/v3/protocol" 29 ) 30 31 const ( 32 // Key is used to set the load balance extension 33 Key = "leastactive" 34 ) 35 36 func init() { 37 extension.SetLoadbalance(constant.LoadBalanceKeyLeastActive, newLeastActiveLoadBalance) 38 } 39 40 type leastActiveLoadBalance struct{} 41 42 // newLeastActiveLoadBalance returns a least active load balance. 43 // 44 // A random mechanism based on actives, actives means the number of a consumer's requests have been sent to provider but not yet got response. 45 func newLeastActiveLoadBalance() loadbalance.LoadBalance { 46 return &leastActiveLoadBalance{} 47 } 48 49 // Select gets invoker based on least active load balancing strategy 50 func (lb *leastActiveLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker { 51 count := len(invokers) 52 if count == 0 { 53 return nil 54 } 55 if count == 1 { 56 return invokers[0] 57 } 58 59 var ( 60 leastActive int32 = -1 // The least active value of all invokers 61 totalWeight int64 // The number of invokers having the same least active value (LEAST_ACTIVE) 62 firstWeight int64 // Initial value, used for comparison 63 leastCount int // The number of invokers having the same least active value (LEAST_ACTIVE) 64 leastIndexes = make([]int, count) // The index of invokers having the same least active value (LEAST_ACTIVE) 65 sameWeight = true // Every invoker has the same weight value? 66 weights = make([]int64, count) // The weight of every invokers 67 ) 68 69 for i := 0; i < count; i++ { 70 invoker := invokers[i] 71 // Active number 72 active := protocol.GetMethodStatus(invoker.GetURL(), invocation.MethodName()).GetActive() 73 // current weight (maybe in warmUp) 74 afterWarmup := loadbalance.GetWeight(invoker, invocation) 75 // save for later use 76 weights[i] = afterWarmup 77 // There are smaller active services 78 if leastActive == -1 || active < leastActive { 79 leastActive = active 80 leastIndexes[0] = i 81 leastCount = 1 // next available leastIndex offset 82 totalWeight = afterWarmup 83 firstWeight = afterWarmup 84 sameWeight = true 85 } else if active == leastActive { 86 leastIndexes[leastCount] = i 87 totalWeight += afterWarmup 88 leastCount++ 89 90 if sameWeight && afterWarmup != firstWeight { 91 sameWeight = false 92 } 93 } 94 } 95 96 if leastCount == 1 { 97 return invokers[leastIndexes[0]] 98 } 99 100 if !sameWeight && totalWeight > 0 { 101 offsetWeight := rand.Int63n(totalWeight) + 1 102 for i := 0; i < leastCount; i++ { 103 leastIndex := leastIndexes[i] 104 offsetWeight -= weights[leastIndex] 105 if offsetWeight < 0 { 106 return invokers[leastIndex] 107 } 108 } 109 } 110 111 index := leastIndexes[rand.Intn(leastCount)] 112 return invokers[index] 113 }