mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-26 18:30:54 +08:00
92 lines
1.9 KiB
Go
92 lines
1.9 KiB
Go
|
package proxy
|
||
|
|
||
|
import (
|
||
|
"math/rand"
|
||
|
"sync/atomic"
|
||
|
)
|
||
|
|
||
|
type HostPool []*UpstreamHost
|
||
|
|
||
|
// Policy decides how a host will be selected from a pool.
|
||
|
type Policy interface {
|
||
|
Select(pool HostPool) *UpstreamHost
|
||
|
}
|
||
|
|
||
|
// The random policy randomly selected an up host from the pool.
|
||
|
type Random struct{}
|
||
|
|
||
|
func (r *Random) Select(pool HostPool) *UpstreamHost {
|
||
|
// instead of just generating a random index
|
||
|
// this is done to prevent selecting a down host
|
||
|
var randHost *UpstreamHost
|
||
|
count := 0
|
||
|
for _, host := range pool {
|
||
|
if host.Down() {
|
||
|
continue
|
||
|
}
|
||
|
count++
|
||
|
if count == 1 {
|
||
|
randHost = host
|
||
|
} else {
|
||
|
r := rand.Int() % count
|
||
|
if r == (count - 1) {
|
||
|
randHost = host
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return randHost
|
||
|
}
|
||
|
|
||
|
// The least_conn policy selects a host with the least connections.
|
||
|
// If multiple hosts have the least amount of connections, one is randomly
|
||
|
// chosen.
|
||
|
type LeastConn struct{}
|
||
|
|
||
|
func (r *LeastConn) Select(pool HostPool) *UpstreamHost {
|
||
|
var bestHost *UpstreamHost
|
||
|
count := 0
|
||
|
leastConn := int64(1<<63 - 1)
|
||
|
for _, host := range pool {
|
||
|
if host.Down() {
|
||
|
continue
|
||
|
}
|
||
|
hostConns := host.Conns
|
||
|
if hostConns < leastConn {
|
||
|
bestHost = host
|
||
|
leastConn = hostConns
|
||
|
count = 1
|
||
|
} else if hostConns == leastConn {
|
||
|
// randomly select host among hosts with least connections
|
||
|
count++
|
||
|
if count == 1 {
|
||
|
bestHost = host
|
||
|
} else {
|
||
|
r := rand.Int() % count
|
||
|
if r == (count - 1) {
|
||
|
bestHost = host
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return bestHost
|
||
|
}
|
||
|
|
||
|
// The round_robin policy selects a host based on round robin ordering.
|
||
|
type RoundRobin struct {
|
||
|
Robin uint32
|
||
|
}
|
||
|
|
||
|
func (r *RoundRobin) Select(pool HostPool) *UpstreamHost {
|
||
|
poolLen := uint32(len(pool))
|
||
|
selection := atomic.AddUint32(&r.Robin, 1) % poolLen
|
||
|
host := pool[selection]
|
||
|
// if the currently selected host is down, just ffwd to up host
|
||
|
for i := uint32(1); host.Down() && i < poolLen; i++ {
|
||
|
host = pool[(selection+i)%poolLen]
|
||
|
}
|
||
|
if host.Down() {
|
||
|
return nil
|
||
|
}
|
||
|
return host
|
||
|
}
|