proxy: add mirror-selection benchmarks #123
Reference in New Issue
Block a user
Delete Branch "benvin/proxy-selection-benchmarks"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
We added a mirror load-balancing strategy (round_robin / least_conn) in #122 and need hard numbers on whether mirror selection adds meaningful request latency. This PR adds microbenchmarks that isolate the selection cost (no network/DB/redis) and commits the results as a permanent regression guard.
How
internal/proxy/selection_bench_test.gobuilds a zero-valueEngine(same setup asleastconn_test.go/multibaseurl_test.go) and calls the selection functions directly:BenchmarkBaseURLAttemptOrder_SingleURL— thelen<=1early-return no-op pathBenchmarkBaseURLAttemptOrder_RoundRobin— pools of 3 and 8BenchmarkBaseURLAttemptOrder_LeastConn— pools of 3 and 8, with in-flight skew preloaded on the gaugesBenchmarkBeginEndAttempt— the gauge inc/dec pair_Parallel(RunParallel) variants of RR / least_conn / begin-end to surface sync.Map + atomic contentionRun:
go test -run=^$ -bench='BaseURLAttemptOrder|BeginEndAttempt' -benchmem -benchtime=1s -count=6 -cpu=8 ./internal/proxy/internal/proxy/BENCHMARKS.mdhas the median-of-6 table (Ryzen 7 4700U, go1.26.5) plus the raw runs.Headline numbers (median of 6, ns/op — sequential | parallel@8)
Key caveat:
baseURLAttemptOrderis only called fromheadUpstream/fetchFromUpstream/checkUpstream— the cache-miss/upstream path. A cache hit returnsSource: "cache"before any selection runs, so the cache-hit hot path pays zero selection cost regardless of strategy.Verdict: even the worst case (least_conn across 8 mirrors, ~15 µs) is <1% of the multi-millisecond upstream round-trip it accompanies; round_robin (~0.5 µs) is negligible. The strategy adds no meaningful latency. least_conn's cost scales super-linearly because the
sort.SliceStablecomparator re-derives each mirror's gauge viainflightCounter(string-concat key + speculativenew(atomic.Int64)) O(n·log n) times — a possible future micro-opt (snapshot loads before sorting), out of scope here.