Add interleaved weighted round-robin and alias-method loadbalancer (#2606)

diff --git a/cluster/loadbalance/aliasmethod/alias_method.go b/cluster/loadbalance/aliasmethod/alias_method.go
new file mode 100644
index 0000000..10c49cd
--- /dev/null
+++ b/cluster/loadbalance/aliasmethod/alias_method.go
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Package aliasmethod implements alias-method algorithm load balance strategy.
+package aliasmethod // weighted random with alias-method algorithm
+
+import (
+	"math/rand"
+
+	"dubbo.apache.org/dubbo-go/v3/cluster/loadbalance"
+	"dubbo.apache.org/dubbo-go/v3/protocol"
+)
+
+type aliasMethodPicker struct {
+	invokers []protocol.Invoker // Instance
+
+	weightSum int64
+	alias     []int
+	prob      []float64
+}
+
+func NewAliasMethodPicker(invokers []protocol.Invoker, invocation protocol.Invocation) *aliasMethodPicker {
+	am := &aliasMethodPicker{
+		invokers: invokers,
+	}
+	am.init(invocation)
+	return am
+}
+
+// Alias Method: https://en.wikipedia.org/wiki/Alias_method
+func (am *aliasMethodPicker) init(invocation protocol.Invocation) {
+	n := len(am.invokers)
+	weights := make([]int64, n)
+	am.alias = make([]int, n)
+	am.prob = make([]float64, n)
+
+	totalWeight := int64(0)
+
+	scaledProb := make([]float64, n)
+	small := make([]int, 0, n)
+	large := make([]int, 0, n)
+
+	for i, invoker := range am.invokers {
+		weight := loadbalance.GetWeight(invoker, invocation)
+		weights[i] = weight
+		totalWeight += weight
+	}
+	// when invoker weight all zero
+	if totalWeight <= 0 {
+		totalWeight = int64(1)
+	}
+	am.weightSum = totalWeight
+
+	for i, weight := range weights {
+		scaledProb[i] = float64(weight) * float64(n) / float64(totalWeight)
+		if scaledProb[i] < 1.0 {
+			small = append(small, i)
+		} else {
+			large = append(large, i)
+		}
+	}
+
+	for len(small) > 0 && len(large) > 0 {
+		l := small[len(small)-1]
+		small = small[:len(small)-1]
+		g := large[len(large)-1]
+		large = large[:len(large)-1]
+
+		am.prob[l] = scaledProb[l]
+		am.alias[l] = g
+
+		scaledProb[g] -= 1.0 - scaledProb[l]
+		if scaledProb[g] < 1.0 {
+			small = append(small, g)
+		} else {
+			large = append(large, g)
+		}
+	}
+
+	for len(large) > 0 {
+		g := large[len(large)-1]
+		large = large[:len(large)-1]
+		am.prob[g] = 1.0
+	}
+
+	for len(small) > 0 {
+		l := small[len(small)-1]
+		small = small[:len(small)-1]
+		am.prob[l] = 1.0
+	}
+}
+
+func (am *aliasMethodPicker) Pick() protocol.Invoker {
+	i := rand.Intn(len(am.invokers))
+	if rand.Float64() < am.prob[i] {
+		return am.invokers[i]
+	}
+	return am.invokers[am.alias[i]]
+}
diff --git a/cluster/loadbalance/aliasmethod/doc.go b/cluster/loadbalance/aliasmethod/doc.go
new file mode 100644
index 0000000..b3c7082
--- /dev/null
+++ b/cluster/loadbalance/aliasmethod/doc.go
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Package aliasmethod implements alias-method algorithm load balance strategy.
+// Alias Method: https://en.wikipedia.org/wiki/Alias_method
+// It needs O(n) time and O(n) memory to initialize and O(1) time to generate a random number.
+package aliasmethod // weighted random with alias-method algorithm
diff --git a/cluster/loadbalance/aliasmethod/loadbalance.go b/cluster/loadbalance/aliasmethod/loadbalance.go
new file mode 100644
index 0000000..ad172ce
--- /dev/null
+++ b/cluster/loadbalance/aliasmethod/loadbalance.go
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Package aliasmethod implements alias-method algorithm load balance strategy.
+package aliasmethod // weighted random with alias-method algorithm
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/cluster/loadbalance"
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/common/extension"
+	"dubbo.apache.org/dubbo-go/v3/protocol"
+)
+
+func init() {
+	extension.SetLoadbalance(constant.LoadBalanceKeyAliasMethod, newWeightedRandomWithAliasMethodBalance)
+}
+
+type weightedRandomWithAliasMethodBalance struct{}
+
+// newWeightedRandomWithAliasMethodBalance returns a loadbalancer using alias-method algorithm..
+func newWeightedRandomWithAliasMethodBalance() loadbalance.LoadBalance {
+	return &weightedRandomWithAliasMethodBalance{}
+}
+
+// Select gets invoker based on interleaved weighted round robine load balancing strategy
+func (lb *weightedRandomWithAliasMethodBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker {
+	count := len(invokers)
+	if count == 0 {
+		return nil
+	}
+	if count == 1 {
+		return invokers[0]
+	}
+
+	wramp := NewAliasMethodPicker(invokers, invocation)
+	return wramp.Pick()
+}
diff --git a/cluster/loadbalance/aliasmethod/loadbalance_test.go b/cluster/loadbalance/aliasmethod/loadbalance_test.go
new file mode 100644
index 0000000..dcfdf73
--- /dev/null
+++ b/cluster/loadbalance/aliasmethod/loadbalance_test.go
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package aliasmethod
+
+import (
+	"fmt"
+	"testing"
+
+	"dubbo.apache.org/dubbo-go/v3/common"
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/protocol"
+	"dubbo.apache.org/dubbo-go/v3/protocol/invocation"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestWRAMRoundRobinSelect(t *testing.T) {
+	loadBalance := newWeightedRandomWithAliasMethodBalance()
+
+	var invokers []protocol.Invoker
+
+	url, _ := common.NewURL(fmt.Sprintf("dubbo://%s:%d/org.apache.demo.HelloService",
+		constant.LocalHostValue, constant.DefaultPort))
+	invokers = append(invokers, protocol.NewBaseInvoker(url))
+	i := loadBalance.Select(invokers, &invocation.RPCInvocation{})
+	assert.True(t, i.GetURL().URLEqual(url))
+
+	for i := 1; i < 10; i++ {
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i))
+		invokers = append(invokers, protocol.NewBaseInvoker(url))
+	}
+	loadBalance.Select(invokers, &invocation.RPCInvocation{})
+}
+
+func TestWRAMRoundRobinByWeight(t *testing.T) {
+	loadBalance := newWeightedRandomWithAliasMethodBalance()
+
+	var invokers []protocol.Invoker
+	loop := 10
+	for i := 1; i <= loop; i++ {
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i))
+		invokers = append(invokers, protocol.NewBaseInvoker(url))
+	}
+
+	loop = (1 + loop) * loop / 2
+	selected := make(map[protocol.Invoker]int)
+
+	for i := 1; i <= loop; i++ {
+		invoker := loadBalance.Select(invokers, &invocation.RPCInvocation{})
+		selected[invoker]++
+	}
+
+	sum := 0
+	for _, value := range selected {
+		sum += value
+	}
+
+	assert.Equal(t, loop, sum)
+}
diff --git a/cluster/loadbalance/iwrr/doc.go b/cluster/loadbalance/iwrr/doc.go
new file mode 100644
index 0000000..0790fc2
--- /dev/null
+++ b/cluster/loadbalance/iwrr/doc.go
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Package iwrr implements Interleaved Weighted Round Robin load balance strategy.
+// Interleaved Weighted Round Robin: https://en.wikipedia.org/wiki/Weighted_round_robin#Interleaved_WRR
+// It needs O(n log maxWeight) time and O(n) memory to initialize and O(1) time to generate a random number.
+package iwrr
diff --git a/cluster/loadbalance/iwrr/iwrr.go b/cluster/loadbalance/iwrr/iwrr.go
new file mode 100644
index 0000000..e1d78a3
--- /dev/null
+++ b/cluster/loadbalance/iwrr/iwrr.go
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package iwrr
+
+import (
+	"math/rand"
+	"sync"
+
+	"dubbo.apache.org/dubbo-go/v3/cluster/loadbalance"
+	"dubbo.apache.org/dubbo-go/v3/protocol"
+)
+
+type iwrrEntry struct {
+	weight  int64
+	invoker protocol.Invoker
+
+	next *iwrrEntry
+}
+
+type iwrrQueue struct {
+	head *iwrrEntry
+	tail *iwrrEntry
+}
+
+func NewIwrrQueue() *iwrrQueue {
+	return &iwrrQueue{}
+}
+
+func (item *iwrrQueue) push(entry *iwrrEntry) {
+	entry.next = nil
+	tail := item.tail
+	item.tail = entry
+	if tail == nil {
+		item.head = entry
+	} else {
+		tail.next = entry
+	}
+}
+
+func (item *iwrrQueue) pop() *iwrrEntry {
+	head := item.head
+	next := head.next
+	head.next = nil
+	item.head = next
+	if next == nil {
+		item.tail = nil
+	}
+	return head
+}
+
+func (item *iwrrQueue) empty() bool {
+	return item.head == nil
+}
+
+// InterleavedweightedRoundRobin struct
+type interleavedweightedRoundRobin struct {
+	current *iwrrQueue
+	next    *iwrrQueue
+	step    int64
+	mu      sync.Mutex
+}
+
+func NewInterleavedweightedRoundRobin(invokers []protocol.Invoker, invocation protocol.Invocation) *interleavedweightedRoundRobin {
+	iwrrp := new(interleavedweightedRoundRobin)
+	iwrrp.current = NewIwrrQueue()
+	iwrrp.next = NewIwrrQueue()
+
+	size := uint64(len(invokers))
+	offset := rand.Uint64() % size
+	step := int64(0)
+	for idx := uint64(0); idx < size; idx++ {
+		invoker := invokers[(idx+offset)%size]
+		weight := loadbalance.GetWeight(invoker, invocation)
+		step = gcdInt(step, weight)
+		iwrrp.current.push(&iwrrEntry{
+			invoker: invoker,
+			weight:  weight,
+		})
+	}
+	iwrrp.step = step
+
+	return iwrrp
+}
+
+func (iwrr *interleavedweightedRoundRobin) Pick(invocation protocol.Invocation) protocol.Invoker {
+	iwrr.mu.Lock()
+	defer iwrr.mu.Unlock()
+
+	if iwrr.current.empty() {
+		iwrr.current, iwrr.next = iwrr.next, iwrr.current
+	}
+
+	entry := iwrr.current.pop()
+	entry.weight -= iwrr.step
+
+	if entry.weight > 0 {
+		iwrr.current.push(entry)
+	} else {
+		weight := loadbalance.GetWeight(entry.invoker, invocation)
+		if weight < 0 {
+			weight = 0
+		}
+		entry.weight = weight
+		iwrr.next.push(entry)
+	}
+
+	return entry.invoker
+}
+
+func gcdInt(a, b int64) int64 {
+	for b != 0 {
+		a, b = b, a%b
+	}
+	return a
+}
diff --git a/cluster/loadbalance/iwrr/loadbalance.go b/cluster/loadbalance/iwrr/loadbalance.go
new file mode 100644
index 0000000..20f9c3c
--- /dev/null
+++ b/cluster/loadbalance/iwrr/loadbalance.go
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package iwrr
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/cluster/loadbalance"
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/common/extension"
+	"dubbo.apache.org/dubbo-go/v3/protocol"
+)
+
+func init() {
+	extension.SetLoadbalance(constant.LoadBalanceKeyInterleavedWeightedRoundRobin, newInterleavedWeightedRoundRobinBalance)
+}
+
+type interleavedWeightedRoundRobinBalance struct{}
+
+// newInterleavedWeightedRoundRobinBalance returns a interleaved weighted round robin load balance.
+func newInterleavedWeightedRoundRobinBalance() loadbalance.LoadBalance {
+	return &interleavedWeightedRoundRobinBalance{}
+}
+
+// Select gets invoker based on interleaved weighted round robine load balancing strategy
+func (lb *interleavedWeightedRoundRobinBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker {
+	count := len(invokers)
+	if count == 0 {
+		return nil
+	}
+	if count == 1 {
+		return invokers[0]
+	}
+
+	iwrrp := NewInterleavedweightedRoundRobin(invokers, invocation)
+	return iwrrp.Pick(invocation)
+}
diff --git a/cluster/loadbalance/iwrr/loadbalance_test.go b/cluster/loadbalance/iwrr/loadbalance_test.go
new file mode 100644
index 0000000..9e926ad
--- /dev/null
+++ b/cluster/loadbalance/iwrr/loadbalance_test.go
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package iwrr
+
+import (
+	"fmt"
+	"testing"
+
+	"dubbo.apache.org/dubbo-go/v3/common"
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/protocol"
+	"dubbo.apache.org/dubbo-go/v3/protocol/invocation"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestIWrrRoundRobinSelect(t *testing.T) {
+	loadBalance := newInterleavedWeightedRoundRobinBalance()
+
+	var invokers []protocol.Invoker
+
+	url, _ := common.NewURL(fmt.Sprintf("dubbo://%s:%d/org.apache.demo.HelloService",
+		constant.LocalHostValue, constant.DefaultPort))
+	invokers = append(invokers, protocol.NewBaseInvoker(url))
+	i := loadBalance.Select(invokers, &invocation.RPCInvocation{})
+	assert.True(t, i.GetURL().URLEqual(url))
+
+	for i := 1; i < 10; i++ {
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i))
+		invokers = append(invokers, protocol.NewBaseInvoker(url))
+	}
+	loadBalance.Select(invokers, &invocation.RPCInvocation{})
+}
+
+func TestIWrrRoundRobinByWeight(t *testing.T) {
+	loadBalance := newInterleavedWeightedRoundRobinBalance()
+
+	var invokers []protocol.Invoker
+	loop := 10
+	for i := 1; i <= loop; i++ {
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i))
+		invokers = append(invokers, protocol.NewBaseInvoker(url))
+	}
+
+	loop = (1 + loop) * loop / 2
+	selected := make(map[protocol.Invoker]int)
+
+	for i := 1; i <= loop; i++ {
+		invoker := loadBalance.Select(invokers, &invocation.RPCInvocation{})
+		selected[invoker]++
+	}
+
+	sum := 0
+	for _, value := range selected {
+		sum += value
+	}
+
+	assert.Equal(t, loop, sum)
+}
diff --git a/cluster/loadbalance/loadbalance_benchmarks_test.go b/cluster/loadbalance/loadbalance_benchmarks_test.go
new file mode 100644
index 0000000..fa89ddd
--- /dev/null
+++ b/cluster/loadbalance/loadbalance_benchmarks_test.go
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package loadbalance_test
+
+import (
+	"fmt"
+	"testing"
+
+	"dubbo.apache.org/dubbo-go/v3/cluster/loadbalance"
+	_ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/aliasmethod"
+	_ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/consistenthashing"
+	_ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/iwrr"
+	_ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/leastactive"
+	_ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/p2c"
+	_ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/random"
+	_ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/ringhash"
+	_ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/roundrobin"
+	"dubbo.apache.org/dubbo-go/v3/common"
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/common/extension"
+	"dubbo.apache.org/dubbo-go/v3/protocol"
+	"dubbo.apache.org/dubbo-go/v3/protocol/invocation"
+)
+
+func Generate() []protocol.Invoker {
+	var invokers []protocol.Invoker
+	for i := 1; i < 256; i++ {
+		url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i))
+		invokers = append(invokers, protocol.NewBaseInvoker(url))
+	}
+	return invokers
+}
+
+func Benchloadbalance(b *testing.B, lb loadbalance.LoadBalance) {
+	b.Helper()
+	invokers := Generate()
+	b.ReportAllocs()
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		lb.Select(invokers, &invocation.RPCInvocation{})
+	}
+}
+
+func BenchmarkRoudrobinLoadbalance(b *testing.B) {
+	Benchloadbalance(b, extension.GetLoadbalance(constant.LoadBalanceKeyRoundRobin))
+}
+
+func BenchmarkLeastativeLoadbalance(b *testing.B) {
+	Benchloadbalance(b, extension.GetLoadbalance(constant.LoadBalanceKeyLeastActive))
+}
+
+func BenchmarkConsistenthashingLoadbalance(b *testing.B) {
+	Benchloadbalance(b, extension.GetLoadbalance(constant.LoadBalanceKeyConsistentHashing))
+}
+
+func BenchmarkP2CLoadbalance(b *testing.B) {
+	Benchloadbalance(b, extension.GetLoadbalance(constant.LoadBalanceKeyP2C))
+}
+
+func BenchmarkInterleavedWeightedRoundRobinLoadbalance(b *testing.B) {
+	Benchloadbalance(b, extension.GetLoadbalance(constant.LoadBalanceKeyInterleavedWeightedRoundRobin))
+}
+
+func BenchmarkRandomLoadbalance(b *testing.B) {
+	Benchloadbalance(b, extension.GetLoadbalance(constant.LoadBalanceKeyRandom))
+}
+
+func BenchmarkAliasMethodLoadbalance(b *testing.B) {
+	Benchloadbalance(b, extension.GetLoadbalance(constant.LoadBalanceKeyAliasMethod))
+}
diff --git a/common/constant/loadbalance.go b/common/constant/loadbalance.go
index dde8443..c30a706 100644
--- a/common/constant/loadbalance.go
+++ b/common/constant/loadbalance.go
@@ -18,10 +18,12 @@
 package constant
 
 const (
-	LoadBalanceKeyConsistentHashing = "consistenthashing"
-	LoadBalanceKeyLeastActive       = "leastactive"
-	LoadBalanceKeyRandom            = "random"
-	LoadBalanceKeyRoundRobin        = "roundrobin"
-	LoadBalanceKeyP2C               = "p2c"
-	LoadXDSRingHash                 = "xdsringhash"
+	LoadBalanceKeyConsistentHashing             = "consistenthashing"
+	LoadBalanceKeyLeastActive                   = "leastactive"
+	LoadBalanceKeyRandom                        = "random"
+	LoadBalanceKeyRoundRobin                    = "roundrobin"
+	LoadBalanceKeyP2C                           = "p2c"
+	LoadXDSRingHash                             = "xdsringhash"
+	LoadBalanceKeyInterleavedWeightedRoundRobin = "interleavedweightedroundrobin"
+	LoadBalanceKeyAliasMethod                   = "aliasmethod"
 )