feat(discovery): Phase 1 telemetry — measure non-uniform relay binding before changing logic - #235
feat(discovery): Phase 1 telemetry — measure non-uniform relay binding before changing logic#235metaphorics wants to merge 17 commits into
Conversation
… surface) Adds in-memory trace types consumed by upcoming SelectPriorityWithTrace / SelectMultiHopWithTrace siblings on MOLSRelayPolicy and RelaySet, and by the metrics emitter. ClientHash carried for debug-log correlation only; LocalAddress intentionally absent (PII-leak surface). No callers in this commit; pure type addition; existing public API unchanged. Phase 1 (telemetry-only) per the discovery rationalization plan.
…e siblings on MOLSRelayPolicy
…HopWithTrace; wire metrics emission and sampled debug log
The keyless_tls/ directory is a separate nested git repository (not part of the portal module). It was inadvertently staged as a submodule pointer in b5ce160 because that commit's tooling did a broad add. Removing the gitlink entry; the working-tree directory is unaffected. Untracked-state restored.
Prevents the keyless_tls/ directory (a separate nested git repository for an unrelated project) from being staged by broad git-add operations.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5c37195d84
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| %: | ||
| @: |
There was a problem hiding this comment.
Remove global catch-all rule that masks unknown make targets
The new %: fallback makes every unknown target succeed as a no-op, so typos in local/CI commands silently pass instead of failing fast (e.g., make definitely-not-a-target now exits 0). That can skip intended build/test/vet steps without any signal, which is a reliability regression beyond the load-test passthrough use case this rule was added for.
Useful? React with 👍 / 👎.
| if *relays <= 0 { | ||
| fmt.Fprintln(os.Stderr, "portal-loadtest: -relays must be > 0") | ||
| os.Exit(1) |
There was a problem hiding this comment.
Reject relay count below two for chi-square calculation
The CLI currently accepts -relays=1, but the chi-square test then uses df := relays - 1 (so df=0) and calls igamc(0, ...), which immediately returns 1.0 via the s <= 0 guard; this prints a valid-looking p-value for a statistically undefined case. This can mislead users running the probe with small K values, so input validation should require at least 2 relays (or explicitly special-case the output).
Useful? React with 👍 / 👎.
| "sync" | ||
|
|
||
| "github.com/prometheus/client_golang/prometheus" | ||
| "github.com/prometheus/client_golang/prometheus/promauto" |
There was a problem hiding this comment.
Prometheus metrics should not live in discovery; this introduces import-time global registration and makes discovery own telemetry transport details. Consider a separate metrics package.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 57040792a3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| discovery.ActiveTunnelsPerRelay.WithLabelValues(relayURL).Inc() | ||
| wrappedConn := &tunnelCounterConn{ | ||
| Conn: conn, | ||
| decr: func() { | ||
| discovery.ActiveTunnelsPerRelay.WithLabelValues(relayURL).Dec() |
There was a problem hiding this comment.
Bound active-tunnel relay labels before updating gauge
Using relayURL directly in ActiveTunnelsPerRelay.WithLabelValues(...) creates a new Prometheus time series for every unique relay ever seen, and those series persist even after the gauge returns to 0. With discovery enabled (or relay URL churn/malicious announce data), this can grow metric cardinality and process memory without bound; it also bypasses the 64-label cap implemented via boundedRelay in portal/discovery/metrics.go for other relay-labeled metrics.
Useful? React with 👍 / 👎.
Proposal: Priority Transposition Logic based on EWMA RTT AnalysisTo address the structural non-uniformity confirmed in Phase 1, I propose implementing a dynamic priority transposition mechanism as part of the Phase 2 weighted composite selector. 1. RationaleWhile the MOLS algorithm provides a deterministic baseline, mathematical uniformity does not account for real-world network degradation. By monitoring RTT "stretching," we can bridge the gap between theoretical priority and actual user experience. 2. Implementation Details
3. Expected Benefits
Recommendation: We should extend the Phase 1 telemetry to include RTT distribution logs. This data will be critical for tuning the EWMA weight ( |
|
LGTM Since MOLS is a mere algorithm, it does not help without additional layer. Let's dive into the "Phase 2"...and I guess that load-awareness should not rely on some constants by approximation. |
|
Also, please detach telemetry codes from discovery :) |
|
@metaphorics Hi, I've refactored your code, and there are some structure changes... Thanks a lot. |
Phase 1 of the discovery rationalization
Adds telemetry around the existing
MOLSRelayPolicyto measure non-uniform relay binding before changing selection logic. Phase 2 (load-aware weighted composite) is gated on the data this PR collects.What landed (13 atomic commits)
portal/discovery/trace.go(new) —SelectionTrace+TraceEntry.ClientHash(uint8) for sampled debug-log correlation only;LocalAddressNOT carried (PII surface).portal/discovery/metrics.go(new) — 8 Prometheus metrics +EmitFromTrace. Cardinality bounded: max 64 unique relay URLs, overflow →relay="other". NO per-client labels.portal/discovery/mols.go—SelectPriorityWithTrace/SelectMultiHopWithTracesiblings; existing methods delegate. Public API unchanged; newmols_test.gogolden byte-equality assertions.portal/discovery/relayset.go—PriorityRelaysWithTrace/PriorityMultiHopWithTrace; emits to metrics; sampled zerolog debug log per call.cmd/relay-server/admin.go—/admin/metricsendpoint behind existing auth middleware (path/admin/metricsbecauseserveAdminis registered undertypes.PathAdminPrefix).cmd/portal-tunnel/main.go— optional--metrics-addr <host:port>flag (no-op if unset).sdk/expose.go—active_tunnels_per_relaygauge instrumentation in accept loop withcloseOncedecrementer (exact-once viasync.Once).cmd/portal-loadtest/main.go(new) — N synthetic clients with uniqueLocalAddress; per-relay top-pick histogram; chi-square vs uniformN/K; p-value via regularized incomplete gamma (Numerical Recipes §6.2 series + continued-fraction).Makefile—load-test:target with%:catch-all formake load-test -- <args>passthrough.Verification (local)
go build ./...exit 0go vet ./...exit 0make lintexit 0 (0 issues)go test -count=1 ./...exit 0 (179 tests pass across 20 packages)Phase 1 finding — validates user-reported non-uniform binding
make load-test -- -clients 1000 -relays 5(deterministic; identical on every re-run):The MOLS deterministic GF(64) hash is structurally non-uniform on this 5-relay-URL set: relay-4 captures ~50% of synthetic clients' top picks because its hash wins ~32/64 GF(64) rows. This is the empirical baseline that Phase 2's weighted composite (additive load penalty
final = mols_position + lambda * load_factor) is designed to address.Public API
No public API changes.
SelectPriority/SelectMultiHop/PriorityRelays/PriorityMultiHopsignatures preserved byte-equal. The new*WithTracesiblings are additive; existing 70+ MOLS tests pass byte-identically (verified via parameterized golden byte-equality test inmols_test.go).New direct dep
github.com/prometheus/client_golang v1.23.2(only new direct dep, per Phase 1 plan acceptance criterion feat: add remote ID validation in RelayClient RequestConnection #8).Out of scope (deferred to later phases)
RelayState(Phase 2)./16diversity (Phase 3).Atomic-commit gate
git log --oneline origin/main..HEADshows 13 commits, each with a single concern, no behavior+cleanup mixing. The two trailingfix:andchore:commits address an inadvertent submodule-pointer add by thegit addpattern in one of the implementer agents (keyless_tls/is a separate nested workspace, now.gitignore'd).