cmd/derpprobe,prober: add ability to perform continuous queuing delay measurements against DERP servers

This new type of probe sends DERP packets sized similarly to CallMeMaybe packets
at a rate of 10 packets per second. It records the round-trip times in a Prometheus
histogram. It also keeps track of how many packets are dropped. Packets that fail to
arrive within 5 seconds are considered dropped.

Updates tailscale/corp#24522

Signed-off-by: Percy Wegmann <percy@tailscale.com>
This commit is contained in:
Percy Wegmann
2024-12-16 23:05:46 -06:00
committed by Percy Wegmann
parent 6ae0287a57
commit 00a4504cf1
8 changed files with 429 additions and 55 deletions

50
prober/histogram.go Normal file
View File

@@ -0,0 +1,50 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package prober
import (
"slices"
"sync"
)
// histogram serves as an adapter to the Prometheus histogram datatype.
// The prober framework passes labels at custom metric collection time that
// it expects to be coupled with the returned metrics. See ProbeClass.Metrics
// and its call sites. Native prometheus histograms cannot be collected while
// injecting more labels. Instead we use this type and pass observations +
// collection labels to prometheus.MustNewConstHistogram() at prometheus
// metric collection time.
type histogram struct {
count uint64
sum float64
buckets []float64
bucketedCounts map[float64]uint64
mx sync.Mutex
}
// newHistogram constructs a histogram that buckets data based on the given
// slice of upper bounds.
func newHistogram(buckets []float64) *histogram {
slices.Sort(buckets)
return &histogram{
buckets: buckets,
bucketedCounts: make(map[float64]uint64, len(buckets)),
}
}
func (h *histogram) add(v float64) {
h.mx.Lock()
defer h.mx.Unlock()
h.count++
h.sum += v
for _, b := range h.buckets {
if v > b {
continue
}
h.bucketedCounts[b] += 1
break
}
}