mirror of
https://github.com/caddyserver/caddy.git
synced 2026-08-27 12:14:43 +00:00
The random_choose selection policy is meant to implement power-of-d-choices: sample d available upstreams uniformly, then pick the least-loaded of that sample. The sampling loop, however, was not a correct reservoir sample (Algorithm R): it never filled the first k reservoir slots unconditionally, instead writing every candidate to a random slot j = rand(i+1), which can evict an earlier candidate while leaving another slot nil. It also derived j from the upstream's index in the pool rather than from the number of available upstreams seen, skewing the sample whenever unavailable upstreams precede available ones. As a result the reservoir frequently held fewer than min(k, available) upstreams, so the least-load comparison often never happened. Most notably, with two upstreams and 'random_choose 2' (the canonical power-of-two-choices setup), half of all requests were routed to the more-loaded upstream even when it was saturated and the other idle -- identical behavior to plain 'random'. The nil slots this leaves behind were also the cause of the panic reported in #3810, which was patched by skipping nils in leastRequests rather than by fixing the sampling. Replace the loop with a standard Algorithm R reservoir sample over the available upstreams: fill the first k slots, then replace a random slot with probability k/n. Every available upstream is now sampled uniformly and the reservoir always holds min(k, available) candidates. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| fastcgi | ||
| forwardauth | ||
| addresses.go | ||
| addresses_test.go | ||
| admin.go | ||
| admin_test.go | ||
| ascii.go | ||
| ascii_test.go | ||
| buffering_test.go | ||
| caddyfile.go | ||
| client_disconnect_test.go | ||
| command.go | ||
| copyresponse.go | ||
| dynamic_upstreams_test.go | ||
| headers_test.go | ||
| healthchecks.go | ||
| hopheaders_test.go | ||
| hosts.go | ||
| httptransport.go | ||
| httptransport_test.go | ||
| metrics.go | ||
| passive_health_test.go | ||
| retries_test.go | ||
| reverseproxy.go | ||
| selectionpolicies.go | ||
| selectionpolicies_test.go | ||
| streaming.go | ||
| streaming_test.go | ||
| upstreams.go | ||
| upstreams_test.go | ||