You run a large-scale, latency-sensitive request-serving fleet — think ads retrieval, search ranking, or similar — where each incoming request fans out to many threads that must complete within a tight deadline. The fleet runs standard Linux with a general-purpose CPU scheduler that has no knowledge of your workload structure.
A kernel upgrade introduces a scheduling regression: p99 latency climbs, timeout errors rise, and business metrics worsen. Rolling back the kernel is an option but creates long-term technical debt. How do you design a workload-aware scheduling policy for this fleet, and how do you build the surrounding infrastructure so that scheduling improvements can be iterated on continuously rather than being one-off fixes tied to kernel release cycles?
Practice against the follow-up probes
- Before you write a single line of scheduler code, how do you diagnose where the scheduling regression is actually coming from — what instrumentation do you reach for?
- You decide to soft-partition CPUs into a latency-critical pool and a background pool. How do you determine the right pool sizes, and what happens when the split is wrong under a traffic spike?
- Cache locality is a key win in your design. How do you measure whether a scheduling change actually improved L3 hit rates, and how do you distinguish that effect from other concurrent changes on the fleet?
- Your policy ships as a user-space binary that can be reloaded without a kernel upgrade. What does your experiment framework look like — how do you safely A/B test two scheduling policies on a live production fleet without corrupting in-flight requests?
- A future team wants to let the application itself signal thread priority to the scheduler — for example, flagging a thread as working on a high-value request. What are the risks of exposing that interface, and how do you prevent it from being abused or destabilizing the scheduler?
Show answer guide
What the interviewer is probing
This question probes architecture thinking across the kernel-userspace boundary: does the candidate understand why a general-purpose scheduler is a poor fit for latency-sensitive fan-out workloads, and can they design a partitioning policy with explicit trade-offs around pool sizing, cache affinity, and failure modes? The deployment model — policy as a reloadable user-space artifact rather than a kernel patch — tests whether the candidate sees iteration speed as an architectural constraint worth designing around. The follow-up on application-scheduler interfaces probes systems thinking around trust boundaries and interface design: who gets to signal priority, and what prevents that interface from becoming a source of instability.
Strong answer outline
- Diagnose first, design second. Before designing a custom policy, characterize the regression: use scheduler tracing (e.g.,
perf sched,BPF tracepointson context switches, runqueue wait times) to identify whether the regression is excess preemption, poor cache affinity, priority inversion, or NUMA thrashing. The fix is different for each. - Model the workload structure. A request-serving fan-out has a clear thread taxonomy: request-handling threads on the critical path (latency-sensitive, short-burst), background threads (compaction, logging, async I/O — throughput-oriented). A general-purpose scheduler cannot distinguish these; a custom policy can encode this knowledge directly.
- CPU pool partitioning. Soft-partition CPUs into a latency pool and a background pool. 'Soft' is important — hard partitioning wastes capacity during imbalance; soft partitioning allows the pools to borrow from each other under load, with a priority bias rather than a hard boundary. Pool sizing starts from observed utilization ratios and is adjusted dynamically via load-based heuristics.
- Cache locality as a first-class design goal. Scheduling related threads to the same physical cores over time improves L3 hit rates and reduces DRAM accesses — critical when the fan-out brings together many threads working on shared data structures. NUMA-aware placement (keep threads and their memory on the same socket) is a follow-on optimization.
- Deployment model determines iteration speed. Encoding the policy as a reloadable user-space program (BPF program loaded by a user-space daemon) decouples the scheduling improvement cycle from the kernel release cycle. Rolling out a change is a daemon restart, not a kernel patch with months of validation. This is an architectural choice, not an implementation detail — it is what makes continuous optimization tractable.
- Experiment framework for live scheduling changes. A/B testing two scheduling policies on a live fleet requires: (a) host-level assignment (not request-level, to avoid mixing policies on the same host), (b) a grace period on policy switchover to let in-flight requests drain, (c) a rollback trigger based on p99 latency and timeout error rate guardrails, (d) metrics stratified by traffic mix to catch load-dependent effects.
- Common wrong turns: designing for average latency rather than tail latency (the business impact lives at p99+); using hard CPU partitioning and starving one pool; building the policy into the kernel binary rather than user space (kills iteration speed); skipping the diagnosis step and tuning a policy against the wrong bottleneck.
- Application-scheduler interface (the hardest part). Allowing the application to signal thread importance (e.g., 'this thread is serving a high-value request') is powerful but risky. Trust model must be explicit: the scheduler must treat these signals as hints, not hard constraints, with a cap on the boost any thread can claim. Abuse vectors — all threads claiming high priority — must be rate-limited or quota-bounded. The interface should be instrumented so gaming is detectable.
The underlying concept
General-purpose CPU schedulers like CFS and EEVDF optimize for fairness and throughput across arbitrary workloads — they are deliberately ignorant of application semantics. For most workloads this is fine, but for latency-sensitive request-serving systems the cost of that ignorance is measurable: threads on the critical path compete on equal footing with background work, cache affinity is not preserved across scheduling decisions, and small changes in the scheduler's virtual-time accounting can shift tail latency by tens of milliseconds. The key insight behind workload-aware scheduling is that the application already has the information the scheduler lacks — which threads are on the critical path, which are background, which requests are high-value — and a custom scheduler can use that information to make better decisions than any general-purpose heuristic. The deeper architectural point is that where the policy lives determines how fast you can improve it: a policy encoded in a kernel module requires a full kernel release cycle to ship; a policy encoded in a reloadable BPF program ships in days. At the scale where a single percentage point of latency improvement translates to megawatts of power savings and measurable revenue lift, that iteration speed difference is itself a strategic asset.
Source
Derived from Modernizing the Meta Ads Service With an Open-Source Kernel Scheduler