summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/reverseproxy/selectionpolicies.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/caddyhttp/reverseproxy/selectionpolicies.go')
-rw-r--r--modules/caddyhttp/reverseproxy/selectionpolicies.go29
1 files changed, 17 insertions, 12 deletions
diff --git a/modules/caddyhttp/reverseproxy/selectionpolicies.go b/modules/caddyhttp/reverseproxy/selectionpolicies.go
index 001f7f8..125a07f 100644
--- a/modules/caddyhttp/reverseproxy/selectionpolicies.go
+++ b/modules/caddyhttp/reverseproxy/selectionpolicies.go
@@ -514,21 +514,26 @@ func leastRequests(upstreams []*Upstream) *Upstream {
return best[weakrand.Intn(len(best))]
}
-// hostByHashing returns an available host
-// from pool based on a hashable string s.
+// hostByHashing returns an available host from pool based on a hashable string s.
func hostByHashing(pool []*Upstream, s string) *Upstream {
- poolLen := uint32(len(pool))
- if poolLen == 0 {
- return nil
- }
- index := hash(s) % poolLen
- for i := uint32(0); i < poolLen; i++ {
- upstream := pool[(index+i)%poolLen]
- if upstream.Available() {
- return upstream
+ // Highest Random Weight (HRW, or "Rendezvous") hashing,
+ // guarantees stability when the list of upstreams changes;
+ // see https://medium.com/i0exception/rendezvous-hashing-8c00e2fb58b0,
+ // https://randorithms.com/2020/12/26/rendezvous-hashing.html,
+ // and https://en.wikipedia.org/wiki/Rendezvous_hashing.
+ var highestHash uint32
+ var upstream *Upstream
+ for _, up := range pool {
+ if !up.Available() {
+ continue
+ }
+ h := hash(s + up.String()) // important to hash key and server together
+ if h > highestHash {
+ highestHash = h
+ upstream = up
}
}
- return nil
+ return upstream
}
// hash calculates a fast hash based on s.