Merge branch 'lbstrategy-interface'

* lbstrategy-interface:
  Support power-of-<arbitrary number>
  Use an interface for load-balancing strategies
This commit is contained in:
Frank Denis 2020-03-20 17:55:41 +01:00
commit d9a68abae9
2 changed files with 49 additions and 28 deletions

View File

@ -358,23 +358,30 @@ func ConfigLoad(proxy *Proxy, flags *ConfigFlags) error {
if len(config.ListenAddresses) == 0 && len(config.LocalDoH.ListenAddresses) == 0 { if len(config.ListenAddresses) == 0 && len(config.LocalDoH.ListenAddresses) == 0 {
dlog.Debug("No local IP/port configured") dlog.Debug("No local IP/port configured")
} }
lbStrategy := LBStrategy(DefaultLBStrategy)
lbStrategy := DefaultLBStrategy switch lbStrategyStr := strings.ToLower(config.LBStrategy); lbStrategyStr {
switch strings.ToLower(config.LBStrategy) {
case "": case "":
// default // default
case "p2": case "p2":
lbStrategy = LBStrategyP2 lbStrategy = LBStrategyP2{}
case "ph": case "ph":
lbStrategy = LBStrategyPH lbStrategy = LBStrategyPH{}
case "fastest": case "fastest":
case "first": case "first":
lbStrategy = LBStrategyFirst lbStrategy = LBStrategyFirst{}
case "random": case "random":
lbStrategy = LBStrategyRandom lbStrategy = LBStrategyRandom{}
default: default:
if strings.HasPrefix(lbStrategyStr, "p") {
n, err := strconv.ParseInt(strings.TrimPrefix(lbStrategyStr, "p"), 10, 32)
if err != nil || n <= 0 {
dlog.Fatalf("Invalid load balancing strategy: [%s]", config.LBStrategy)
}
lbStrategy = LBStrategyPN{n: int(n)}
} else {
dlog.Warnf("Unknown load balancing strategy: [%s]", config.LBStrategy) dlog.Warnf("Unknown load balancing strategy: [%s]", config.LBStrategy)
} }
}
proxy.serversInfo.lbStrategy = lbStrategy proxy.serversInfo.lbStrategy = lbStrategy
proxy.serversInfo.lbEstimator = config.LBEstimator proxy.serversInfo.lbEstimator = config.LBEstimator

View File

@ -62,17 +62,41 @@ type ServerInfo struct {
DOHClientCreds DOHClientCreds DOHClientCreds DOHClientCreds
} }
type LBStrategy int type LBStrategy interface {
getCandidate(serversCount int) int
}
const ( type LBStrategyP2 struct{}
LBStrategyNone = LBStrategy(iota)
LBStrategyP2
LBStrategyPH
LBStrategyFirst
LBStrategyRandom
)
const DefaultLBStrategy = LBStrategyP2 func (LBStrategyP2) getCandidate(serversCount int) int {
return rand.Intn(Min(serversCount, 2))
}
type LBStrategyPN struct{ n int }
func (s LBStrategyPN) getCandidate(serversCount int) int {
return rand.Intn(Min(serversCount, s.n))
}
type LBStrategyPH struct{}
func (LBStrategyPH) getCandidate(serversCount int) int {
return rand.Intn(Max(Min(serversCount, 2), serversCount/2))
}
type LBStrategyFirst struct{}
func (LBStrategyFirst) getCandidate(int) int {
return 0
}
type LBStrategyRandom struct{}
func (LBStrategyRandom) getCandidate(serversCount int) int {
return rand.Intn(serversCount)
}
var DefaultLBStrategy = LBStrategyP2{}
type ServersInfo struct { type ServersInfo struct {
sync.RWMutex sync.RWMutex
@ -209,17 +233,7 @@ func (serversInfo *ServersInfo) getOne() *ServerInfo {
if serversInfo.lbEstimator { if serversInfo.lbEstimator {
serversInfo.estimatorUpdate() serversInfo.estimatorUpdate()
} }
var candidate int candidate := serversInfo.lbStrategy.getCandidate(serversCount)
switch serversInfo.lbStrategy {
case LBStrategyFirst:
candidate = 0
case LBStrategyPH:
candidate = rand.Intn(Max(Min(serversCount, 2), serversCount/2))
case LBStrategyRandom:
candidate = rand.Intn(serversCount)
default:
candidate = rand.Intn(Min(serversCount, 2))
}
serverInfo := serversInfo.inner[candidate] serverInfo := serversInfo.inner[candidate]
dlog.Debugf("Using candidate [%s] RTT: %d", (*serverInfo).Name, int((*serverInfo).rtt.Value())) dlog.Debugf("Using candidate [%s] RTT: %d", (*serverInfo).Name, int((*serverInfo).rtt.Value()))
serversInfo.Unlock() serversInfo.Unlock()