m11p7 — secure the cluster, all opt-in (pre-m11p7 byte-for-byte):
- gRPC replication mTLS by default via a custom tokio-rustls acceptor +
DynamicCertResolver; zero-drop content-hash cert rotation (k8s ..data swap,
no pod restart, no inotify)
- inter-node HTTP TLS sharing the same resolver (one rotation, both planes) +
per-node keyed-BLAKE3 signed x-tidal-node-token; marker-without-token -> 403
- admin audit log (operator-leg only) + per-principal rate limit (engine
RateLimiter; sibling nodes exempt)
- k8s cert-manager manifest (certs.yaml) + scripts/gen-cluster-certs.sh fallback;
secret.example.yaml gains TIDAL_CLUSTER_KEY (file-mounted, hot-rotatable)
- exit gate verified real: mtls.rs (gRPC foreign-pod), cluster_security.rs
(HTTP foreign + zero-drop rotation under load), 7 security unit tests
perf — instrument floor (sweep Wave 1):
- new tidal/benches/wal.rs + tidal-server/benches/scatter.rs
- p99->mean honesty relabel; sweep manifest at docs/reviews/perf-sweep-2026-06-13.md
- add @tidal-performance agent (Martin Thompson)
new: cluster/{audit,http_tls,security}.rs, tests/cluster_security.rs,
docs/planning/milestone-11/phase-7.md
156 lines
5.4 KiB
Rust
156 lines
5.4 KiB
Rust
#![allow(clippy::unwrap_used, clippy::cast_precision_loss)]
|
|
|
|
//! Criterion benchmark for scatter-gather RETRIEVE fan-out.
|
|
//!
|
|
//! Today `scatter_gather_retrieve` spawns one OS thread *per shard, per query*
|
|
//! behind a single global `Mutex<usize>` + `Condvar` permit semaphore (perf
|
|
//! sweep 2026-06-13, finding rank 2). Before this bench existed there was no
|
|
//! before/after for that threading model. It measures:
|
|
//!
|
|
//! - **`scatter_fanout/regions{4,16}`** — single-query fan-out latency. The gap
|
|
//! between 4 and 16 regions is the per-shard thread create/teardown +
|
|
//! 2 MiB-stack-reservation cost, since the underlying per-shard reads over the
|
|
//! tiny replicated dataset are near-instant.
|
|
//!
|
|
//! - **`scatter_fanout_concurrent/regions{4,16}_q8`** — 8 concurrent queries
|
|
//! issued at once, so `8 * regions` workers all contend the one global
|
|
//! semaphore. This is the lock-bounce / queue-depth signal that a reused
|
|
//! worker pool (wave 5) must improve without regressing single-query latency.
|
|
//!
|
|
//! Run:
|
|
//! ```bash
|
|
//! cargo bench -p tidal-server --bench scatter
|
|
//! ```
|
|
|
|
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
use std::time::{Duration, Instant};
|
|
|
|
use criterion::{Criterion, criterion_group, criterion_main};
|
|
use tidal_server::scatter_gather::scatter_gather_retrieve;
|
|
use tidaldb::query::retrieve::Retrieve;
|
|
use tidaldb::replication::shard::RegionId;
|
|
use tidaldb::schema::{DecaySpec, EntityId, EntityKind, Schema, SchemaBuilder, Window};
|
|
use tidaldb::testing::SimulatedCluster;
|
|
use tidaldb::testing::cluster::ClusterConfig;
|
|
|
|
fn bench_schema() -> Schema {
|
|
let mut builder = SchemaBuilder::new();
|
|
let _ = builder
|
|
.signal(
|
|
"view",
|
|
EntityKind::Item,
|
|
DecaySpec::Exponential {
|
|
half_life: Duration::from_secs(7 * 24 * 3600),
|
|
},
|
|
)
|
|
.windows(&[Window::OneHour])
|
|
.velocity(false)
|
|
.add();
|
|
builder.build().unwrap()
|
|
}
|
|
|
|
/// Build an `n`-region replicated cluster pre-seeded with 64 viewed items.
|
|
/// Returns the cluster plus the shard list and region-name map that
|
|
/// `scatter_gather_retrieve` consumes.
|
|
fn build_cluster(
|
|
n: u16,
|
|
) -> (
|
|
Arc<SimulatedCluster>,
|
|
Vec<RegionId>,
|
|
HashMap<RegionId, String>,
|
|
) {
|
|
let regions: Vec<RegionId> = (0..n).map(RegionId).collect();
|
|
let config = ClusterConfig {
|
|
regions: regions.clone(),
|
|
leader_region: RegionId(0),
|
|
schema: bench_schema(),
|
|
profiles: Vec::new(),
|
|
transports: None,
|
|
};
|
|
let cluster = Arc::new(SimulatedCluster::build(config));
|
|
|
|
// Replicated topology: write to the leader, all regions see all data.
|
|
for i in 1..=64u64 {
|
|
let eid = EntityId::new(i);
|
|
cluster
|
|
.write_item_with_metadata(eid, &HashMap::new())
|
|
.unwrap();
|
|
cluster.write_signal("view", eid, i as f64).unwrap();
|
|
}
|
|
|
|
let names: HashMap<RegionId, String> = regions
|
|
.iter()
|
|
.map(|&r| (r, format!("region-{}", r.0)))
|
|
.collect();
|
|
(cluster, regions, names)
|
|
}
|
|
|
|
fn trending_query() -> Retrieve {
|
|
Retrieve::builder()
|
|
.profile("trending")
|
|
.limit(20)
|
|
.build()
|
|
.unwrap()
|
|
}
|
|
|
|
fn fanout_latency(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("scatter_fanout");
|
|
group.sample_size(30);
|
|
for n in [4u16, 16] {
|
|
let (cluster, shards, names) = build_cluster(n);
|
|
let query = trending_query();
|
|
group.bench_function(format!("regions{n}"), |b| {
|
|
b.iter(|| {
|
|
let (result, _meta) =
|
|
scatter_gather_retrieve(&cluster, &query, &shards, &names, None).unwrap();
|
|
assert!(!result.items.is_empty());
|
|
});
|
|
});
|
|
}
|
|
group.finish();
|
|
}
|
|
|
|
fn fanout_concurrent(c: &mut Criterion) {
|
|
const CONCURRENCY: usize = 8;
|
|
let mut group = c.benchmark_group("scatter_fanout_concurrent");
|
|
group.sample_size(20);
|
|
group.measurement_time(Duration::from_secs(12));
|
|
for n in [4u16, 16] {
|
|
let (cluster, shards, names) = build_cluster(n);
|
|
let query = trending_query();
|
|
group.bench_function(format!("regions{n}_q{CONCURRENCY}"), |b| {
|
|
b.iter_custom(|iters| {
|
|
let mut elapsed = Duration::ZERO;
|
|
for _ in 0..iters {
|
|
let start = Instant::now();
|
|
let threads: Vec<_> = (0..CONCURRENCY)
|
|
.map(|_| {
|
|
let cluster = Arc::clone(&cluster);
|
|
let query = query.clone();
|
|
let shards = shards.clone();
|
|
let names = names.clone();
|
|
std::thread::spawn(move || {
|
|
let (result, _meta) = scatter_gather_retrieve(
|
|
&cluster, &query, &shards, &names, None,
|
|
)
|
|
.unwrap();
|
|
assert!(!result.items.is_empty());
|
|
})
|
|
})
|
|
.collect();
|
|
for t in threads {
|
|
t.join().unwrap();
|
|
}
|
|
elapsed += start.elapsed();
|
|
}
|
|
elapsed
|
|
});
|
|
});
|
|
}
|
|
group.finish();
|
|
}
|
|
|
|
criterion_group!(benches, fanout_latency, fanout_concurrent);
|
|
criterion_main!(benches);
|