Skip to content

Commit 40234bb

Browse files
authored
perf(operator): mimalloc allocator + label-scope the Job watch (#53)
2 parents 7361b94 + aec8a04 commit 40234bb

3 files changed

Lines changed: 45 additions & 6 deletions

File tree

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jiff = { version = "0.2.25", features = ["serde"] }
1616
k8s-openapi = { version = "0.27.1", features = ["latest", "schemars"] }
1717
kube = { version = "3.1.0", default-features = false, features = ["runtime", "derive", "client", "rustls-tls", "ws"] }
1818
kube_quantity = "0.9.0"
19+
mimalloc = { version = "0.1", default-features = false }
1920
prometheus = "0.14.0"
2021
rand = "0.10.1"
2122
reqwest = { version = "0.13.4", features = ["json"] }

src/bin/operator.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ use postgres_restore_operator::{
2525
types::{PostgresPhysicalReplica, PostgresPhysicalRestore},
2626
};
2727

28+
// Use mimalloc instead of the default glibc allocator. Long-running Rust
29+
// services on glibc commonly hold significantly more RSS than their actual
30+
// live heap due to fragmentation and retained chunks; mimalloc keeps RSS
31+
// closer to working-set size, which matters for an operator that runs
32+
// indefinitely and was previously OOMKilled at a tight limit.
33+
#[global_allocator]
34+
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
35+
2836
const DEFAULT_MAX_CONCURRENT_RESTORES: usize = 2;
2937
const DEFAULT_METRICS_ADDR: &str = "[::]:8080";
3038
const DEFAULT_METRICS_PORT: u16 = 8080;
@@ -324,12 +332,23 @@ async fn main() -> anyhow::Result<()> {
324332
namespace.map(|ns| ObjectRef::new(&replica_name).within(&ns))
325333
},
326334
)
327-
.watches(Api::<Job>::all(client.clone()), Config::default(), |job| {
328-
let labels = job.metadata.labels.as_ref()?;
329-
let replica_name = labels.get("pgro.bes.au/replica")?;
330-
let namespace = job.metadata.namespace.as_ref()?;
331-
Some(ObjectRef::new(replica_name).within(namespace))
332-
})
335+
// Scope the Job watch to pgro-owned Jobs. Without a label selector
336+
// kube-rs caches every Job in every namespace (CI runners, batch
337+
// jobs, cert-manager, etc.) in the in-memory store, which scales
338+
// with cluster activity rather than pgro's working set. Limiting
339+
// to Jobs that carry the pgro.bes.au/replica label cuts that to
340+
// only restore Jobs, snapshot-list Jobs, schema-migration Jobs,
341+
// and credential-reset Jobs — all of which the operator builds.
342+
.watches(
343+
Api::<Job>::all(client.clone()),
344+
Config::default().labels("pgro.bes.au/replica"),
345+
|job| {
346+
let labels = job.metadata.labels.as_ref()?;
347+
let replica_name = labels.get("pgro.bes.au/replica")?;
348+
let namespace = job.metadata.namespace.as_ref()?;
349+
Some(ObjectRef::new(replica_name).within(namespace))
350+
},
351+
)
333352
.run(
334353
controllers::replica::reconcile,
335354
controllers::replica::error_policy,

0 commit comments

Comments
 (0)