Design a Distributed Task Scheduler
A full Staff-level walkthrough of a Borg/Kubernetes-style cluster scheduler that places millions of containers across 100K+ machines — trading scheduling latency against bin-packing optimality, with priority preemption, autoscaling, and multi-tenant quotas. Follow it top to bottom, or jump to any step.
Scope & ambiguity
Framing statement
“A distributed task scheduler at hyperscale manages millions of containers across hundreds of thousands of machines. The key challenge is scheduling latency vs optimality — finding the best machine for each task quickly enough to not bottleneck deployment velocity. I’ll focus on the scheduling algorithm, resource management, and multi-tenancy isolation.”
Phased delivery
Requirements
Functional requirements
- FR1 — Schedule containers/tasks onto a fleet of machines based on resource requirements
- FR2 — Support priority levels with preemption (high-priority evicts low-priority)
- FR3 — Placement constraints (zone, GPU, SSD requirements)
- FR4 — Automatic failure recovery (reschedule on machine failure)
- FR5 — Autoscaling (scale tasks based on CPU/memory/custom metrics)
- FR6 — Multi-tenancy with resource quotas per team
Non-functional requirements
Back-of-envelope estimation
Capacity estimates
API design
Service definition (gRPC)
Data model
Storage choices
etcd scaling concern: etcd has a practical limit of ~100K keys for good performance. For 10M tasks, we need sharding.
Solution: Shard etcd by namespace/team. Each shard manages ~100K tasks. Scheduler maintains an in-memory aggregated view.
High-level architecture
Architecture diagram
Deep dives
WHERE STAFF IS WONScheduling algorithm
Two-phase scheduling:
Alternatives considered:
My choice — shared-state with partitioning (Omega-style):
- Multiple scheduler instances, each responsible for a partition of namespaces
- Shared machine state (eventually consistent, ~1s lag)
- Optimistic concurrency: two schedulers may try to use the same resources → one fails and retries
- At 10K tasks/sec with 10 partitions = 1K tasks/sec per scheduler (manageable)
Priority preemption
Autoscaling
Multi-tenancy and resource quotas
Multi-team rollout
1. Core scheduler (Weeks 1–8): Single-scheduler, bin-packing, basic priority.
2. Scale (Weeks 9–16): Shared-state multi-scheduler, autoscaling, quotas.
3. Production (Weeks 17–24): Migration from the existing scheduler — parallel run, compare placement decisions, measure utilization improvement.
4. Optimization (Months 7+): ML-based scheduling, gang scheduling for distributed training.
Bottlenecks & evolution
Bottleneck analysis
2–3 year evolution
Year 1: Reliable scheduling for 100K machines, priority preemption, autoscaling, multi-tenancy.
Year 2: ML-based scheduling (predict resource usage, improve bin-packing by 10–15%), gang scheduling (for ML training jobs that need N GPUs simultaneously), spot/preemptible market (internal pricing for spare capacity).
Year 3: Multi-cluster federation (schedule across data centers), edge scheduling (IoT/edge devices), serverless integration (auto-scale to zero), FinOps integration (cost visibility per task/team).
Rubric — Senior vs Staff
Want more breakdowns like this?
Join free early access for upcoming RAG, LLM eval, agents, and AI infrastructure walkthroughs.