mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 09:18:34 +00:00
Least load balancer (#2999)
* v5: Health Check & LeastLoad Strategy (rebased from 2c5a71490368500a982018a74a6d519c7e121816) Some changes will be necessary to integrate it into V2Ray * Update proto * parse duration conf with time.Parse() * moving health ping to observatory as a standalone component * moving health ping to observatory as a standalone component: auto generated file * add initialization for health ping * incorporate changes in router implementation * support principle target output * add v4 json support for BurstObservatory & fix balancer reference * update API command * remove cancelled API * return zero length value when observer is not found * remove duplicated targeted dispatch * adjust test with updated structure * bug fix for observer * fix strategy selector * fix strategy least load * Fix ticker usage ticker.Close does not close ticker.C * feat: Replace default Health Ping URL to HTTPS (#1991) * fix selectLeastLoad() returns wrong number of nodes (#2083) * Test: fix leastload strategy unit test * fix(router): panic caused by concurrent map read and write (#2678) * Clean up code --------- Co-authored-by: Jebbs <qjebbs@gmail.com> Co-authored-by: Shelikhoo <xiaokangwang@outlook.com> Co-authored-by: 世界 <i@sekai.icu> Co-authored-by: Bernd Eichelberger <46166740+4-FLOSS-Free-Libre-Open-Source-Software@users.noreply.github.com> Co-authored-by: 秋のかえで <autmaple@protonmail.com> Co-authored-by: Rinka <kujourinka@gmail.com>
This commit is contained in:
parent
bf02392969
commit
fa5d7a255b
105 changed files with 3523 additions and 429 deletions
179
app/router/strategy_leastload_test.go
Normal file
179
app/router/strategy_leastload_test.go
Normal file
|
@ -0,0 +1,179 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
/*
|
||||
Split into multiple package, need to be tested separately
|
||||
|
||||
func TestSelectLeastLoad(t *testing.T) {
|
||||
settings := &StrategyLeastLoadConfig{
|
||||
HealthCheck: &HealthPingConfig{
|
||||
SamplingCount: 10,
|
||||
},
|
||||
Expected: 1,
|
||||
MaxRTT: int64(time.Millisecond * time.Duration(800)),
|
||||
}
|
||||
strategy := NewLeastLoadStrategy(settings)
|
||||
// std 40
|
||||
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
||||
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
||||
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
||||
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
||||
// std 60
|
||||
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
||||
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
||||
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
||||
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
||||
// std 0, but >MaxRTT
|
||||
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
||||
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
||||
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
||||
strategy.PutResult("c", time.Millisecond*time.Duration(1000))
|
||||
expected := "a"
|
||||
actual := strategy.SelectAndPick([]string{"a", "b", "c", "untested"})
|
||||
if actual != expected {
|
||||
t.Errorf("expected: %v, actual: %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectLeastLoadWithCost(t *testing.T) {
|
||||
settings := &StrategyLeastLoadConfig{
|
||||
HealthCheck: &HealthPingConfig{
|
||||
SamplingCount: 10,
|
||||
},
|
||||
Costs: []*StrategyWeight{
|
||||
{Match: "a", Value: 9},
|
||||
},
|
||||
Expected: 1,
|
||||
}
|
||||
strategy := NewLeastLoadStrategy(settings, nil)
|
||||
// std 40, std+c 120
|
||||
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
||||
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
||||
strategy.PutResult("a", time.Millisecond*time.Duration(60))
|
||||
strategy.PutResult("a", time.Millisecond*time.Duration(140))
|
||||
// std 60
|
||||
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
||||
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
||||
strategy.PutResult("b", time.Millisecond*time.Duration(40))
|
||||
strategy.PutResult("b", time.Millisecond*time.Duration(160))
|
||||
expected := "b"
|
||||
actual := strategy.SelectAndPick([]string{"a", "b", "untested"})
|
||||
if actual != expected {
|
||||
t.Errorf("expected: %v, actual: %v", expected, actual)
|
||||
}
|
||||
}
|
||||
*/
|
||||
func TestSelectLeastExpected(t *testing.T) {
|
||||
strategy := &LeastLoadStrategy{
|
||||
settings: &StrategyLeastLoadConfig{
|
||||
Baselines: nil,
|
||||
Expected: 3,
|
||||
},
|
||||
}
|
||||
nodes := []*node{
|
||||
{Tag: "a", RTTDeviationCost: 100},
|
||||
{Tag: "b", RTTDeviationCost: 200},
|
||||
{Tag: "c", RTTDeviationCost: 300},
|
||||
{Tag: "d", RTTDeviationCost: 350},
|
||||
}
|
||||
expected := 3
|
||||
ns := strategy.selectLeastLoad(nodes)
|
||||
if len(ns) != expected {
|
||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||
}
|
||||
}
|
||||
func TestSelectLeastExpected2(t *testing.T) {
|
||||
strategy := &LeastLoadStrategy{
|
||||
settings: &StrategyLeastLoadConfig{
|
||||
Baselines: nil,
|
||||
Expected: 3,
|
||||
},
|
||||
}
|
||||
nodes := []*node{
|
||||
{Tag: "a", RTTDeviationCost: 100},
|
||||
{Tag: "b", RTTDeviationCost: 200},
|
||||
}
|
||||
expected := 2
|
||||
ns := strategy.selectLeastLoad(nodes)
|
||||
if len(ns) != expected {
|
||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||
}
|
||||
}
|
||||
func TestSelectLeastExpectedAndBaselines(t *testing.T) {
|
||||
strategy := &LeastLoadStrategy{
|
||||
settings: &StrategyLeastLoadConfig{
|
||||
Baselines: []int64{200, 300, 400},
|
||||
Expected: 3,
|
||||
},
|
||||
}
|
||||
nodes := []*node{
|
||||
{Tag: "a", RTTDeviationCost: 100},
|
||||
{Tag: "b", RTTDeviationCost: 200},
|
||||
{Tag: "c", RTTDeviationCost: 250},
|
||||
{Tag: "d", RTTDeviationCost: 300},
|
||||
{Tag: "e", RTTDeviationCost: 310},
|
||||
}
|
||||
expected := 3
|
||||
ns := strategy.selectLeastLoad(nodes)
|
||||
if len(ns) != expected {
|
||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||
}
|
||||
}
|
||||
func TestSelectLeastExpectedAndBaselines2(t *testing.T) {
|
||||
strategy := &LeastLoadStrategy{
|
||||
settings: &StrategyLeastLoadConfig{
|
||||
Baselines: []int64{200, 300, 400},
|
||||
Expected: 3,
|
||||
},
|
||||
}
|
||||
nodes := []*node{
|
||||
{Tag: "a", RTTDeviationCost: 500},
|
||||
{Tag: "b", RTTDeviationCost: 600},
|
||||
{Tag: "c", RTTDeviationCost: 700},
|
||||
{Tag: "d", RTTDeviationCost: 800},
|
||||
{Tag: "e", RTTDeviationCost: 900},
|
||||
}
|
||||
expected := 3
|
||||
ns := strategy.selectLeastLoad(nodes)
|
||||
if len(ns) != expected {
|
||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||
}
|
||||
}
|
||||
func TestSelectLeastLoadBaselines(t *testing.T) {
|
||||
strategy := &LeastLoadStrategy{
|
||||
settings: &StrategyLeastLoadConfig{
|
||||
Baselines: []int64{200, 400, 600},
|
||||
Expected: 0,
|
||||
},
|
||||
}
|
||||
nodes := []*node{
|
||||
{Tag: "a", RTTDeviationCost: 100},
|
||||
{Tag: "b", RTTDeviationCost: 200},
|
||||
{Tag: "c", RTTDeviationCost: 300},
|
||||
}
|
||||
expected := 1
|
||||
ns := strategy.selectLeastLoad(nodes)
|
||||
if len(ns) != expected {
|
||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||
}
|
||||
}
|
||||
func TestSelectLeastLoadBaselinesNoQualified(t *testing.T) {
|
||||
strategy := &LeastLoadStrategy{
|
||||
settings: &StrategyLeastLoadConfig{
|
||||
Baselines: []int64{200, 400, 600},
|
||||
Expected: 0,
|
||||
},
|
||||
}
|
||||
nodes := []*node{
|
||||
{Tag: "a", RTTDeviationCost: 800},
|
||||
{Tag: "b", RTTDeviationCost: 1000},
|
||||
}
|
||||
expected := 0
|
||||
ns := strategy.selectLeastLoad(nodes)
|
||||
if len(ns) != expected {
|
||||
t.Errorf("expected: %v, actual: %v", expected, len(ns))
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue