Performance Profiling of the Kubernetes Control Plane

Performance Profiling of the Kubernetes Control Plane

Every deployment, every scale-up, every self-healing restart passes through a handful of components that most teams never look at until something slows down. This guide teaches you, step by step, how to measure those components, find the real bottleneck, and fix it with confidence.

Picture the control tower at a busy airport. Pilots, who are your applications, do the actual flying. But nothing takes off, lands, or changes course without the tower granting permission and recording the decision. When the tower works smoothly, nobody notices it. When the tower becomes slow, planes queue on the runway, pilots grow frustrated, and a small delay in one corner ripples across the entire schedule. The tower rarely fails dramatically; it simply gets slower, and slowness is much harder to diagnose than a clean failure.

The Kubernetes control plane is that tower. It receives every request to create, change, or remove anything in the cluster, it remembers the desired state of everything, it decides where workloads should run, and it constantly nudges reality to match the plan. Your applications may keep running even when the control plane is struggling, which makes problems easy to miss, but the moment you try to deploy, scale, or recover, you feel every millisecond of delay. This tutorial shows you how to profile the control plane, which means measuring where its time and resources go, so that you can find slow spots before your users do.

1What Does “Profiling the Control Plane” Actually Mean?

Profiling is the practice of measuring where time and resources are spent, so you improve the real problem instead of a guess.

Profiling in everyday words

To profile something is to measure it carefully and break the result into parts. If your morning commute takes ninety minutes, you can complain about traffic, or you can time each stage: walking to the station, waiting for the train, riding, and walking to the office. Suddenly you learn that thirty of those minutes are spent waiting on a single platform. That breakdown is a profile. It tells you where to act, and just as importantly, where acting would be a waste of effort.

Profiling the control plane works the same way. Instead of saying “the cluster feels slow”, we measure how long the interface server takes to answer different kinds of requests, how long the database takes to save changes, how long the scheduler takes to place a pod, and how long the controllers take to react to a change. The result is a timeline that shows which stage consumes the time.

Why this matters more as clusters grow

A small cluster with a few dozen workloads rarely shows control plane stress. The components have plenty of room. As a cluster grows to hundreds of nodes, thousands of pods, and many automation tools constantly watching and updating objects, the work done by the control plane grows faster than the cluster itself. Each new controller, each new custom resource type, and each new dashboard that polls the interface adds load. Problems that were invisible at small scale suddenly appear: deployments that take minutes to start, pods stuck waiting to be scheduled, and commands that hang before returning.

Simple Analogy

Think of a small town post office. One clerk handles everything and nobody waits. Now imagine the town becomes a city of a million people, yet the post office still has one clerk, one filing cabinet, and one queue. The clerk is not lazy and the cabinet is not broken, but the design no longer fits the load. Profiling is how you discover exactly which part of the post office, the clerk, the cabinet, or the queue, has become the limit.

What profiling is not

Profiling is not the same as monitoring, though they are close relatives. Monitoring watches known numbers over time and warns you when they cross a line. Profiling goes deeper: it investigates why a number looks the way it does by drilling into the internals. Monitoring tells you the interface server is slow today. Profiling tells you that a particular kind of list request, issued by a particular tool, is responsible for most of the slowness. You need both, and good profiling usually starts because monitoring raised a question.

i
Good to Know

Many teams assume that adding more powerful machines to the control plane is the first and best remedy. Often the true cause is a single misbehaving client or an overly heavy request pattern, and bigger machines would only hide the issue while increasing cost. Profile first, spend second.

4 Stages
Receive, decide, store, react: the control plane loop
1 Database
etcd holds the single source of truth for the cluster
Many Clients
Controllers, tools, and people all share the same front door

2The Anatomy of the Control Plane

You cannot profile what you cannot name. Meet the parts, and what each one is responsible for.

The components and their jobs

The control plane is a small group of cooperating programs. Each has a narrow responsibility, and they communicate almost entirely through one shared hub, the interface server. Understanding this hub-and-spoke design is the key to profiling, because it means that almost every performance problem eventually shows up as extra work at the hub or at the database behind it.

Front Door

API Server

Receives every request, checks who is asking and whether they are allowed, validates the request, saves it, and tells interested listeners about changes.

Memory

etcd

The consistent key-value database that stores the entire desired and current state of the cluster. Everything durable lives here.

Placement

Scheduler

Watches for new pods without a home and chooses the best node for each, based on resources, rules, and preferences.

Reconciliation

Controller Manager

Runs many small loops that compare what you asked for with what exists, and take action to close the gap.

Cloud Link

Cloud Controller Manager

Connects the cluster to the cloud provider for things like load balancers, routes, and node lifecycle.

Extensions

Webhooks and Aggregated APIs

Optional add-ons that the interface server calls out to during requests, which can add delay if they are slow.

flowchart TD
  U["Users, tools, and automation"] --> A["API server"]
  K["Kubelets on nodes"] --> A
  A  E[("etcd database")]
  S["Scheduler"]  A
  C["Controller manager"]  A
  X["Cloud controller manager"]  A
  A --> W["Admission webhooks and aggregated APIs"]
        
FIG 1 — Everything talks to the API server, and the API server talks to etcd

Why the hub-and-spoke design shapes profiling

Notice that the scheduler never talks directly to the controller manager, and neither of them ever touches the database. They all go through the interface server. This keeps the system simple and consistent, but it also means the interface server is a shared resource. If one client sends heavy requests, every other client feels it. If the database is slow, the interface server becomes slow, and then everything attached to it slows down together. When you profile, you will often find that symptoms appear in one component while the cause lives in another.

Simple Analogy

Imagine a restaurant where every waiter, cook, and cashier must communicate through a single order window. The window is efficient because everyone sees the same orders. But if one customer places a gigantic order that takes ten minutes to read aloud, everyone else waits. The window is shared, so its time is shared.

!
Common Mistake

Beginners often profile the scheduler first because “scheduling” sounds like the slow part of starting a pod. In practice, the scheduler is frequently the fastest component, and delays more often hide in the interface server, the database, admission webhooks, or the nodes themselves. Let measurements, not intuition, choose where you look.

3Life of a Request: Where Time Can Hide

Follow one request from arrival to answer. Each stop is a place where time can be spent, and where you can measure it.

The journey through the API server

When you ask Kubernetes to create a pod, your request does not go straight to the database. It passes through a series of stages, like a visitor moving through airport security. Each stage has a purpose, and each stage costs some time. For a healthy cluster each stage is tiny. For a struggling cluster, one stage often grows to dominate the total.

flowchart LR
  R["Request arrives"] --> A1["Authentication: who are you"]
  A1 --> A2["Authorization: are you allowed"]
  A2 --> A3["Mutating admission: adjust the request"]
  A3 --> A4["Schema validation"]
  A4 --> A5["Validating admission: final checks"]
  A5 --> A6["Write to etcd"]
  A6 --> A7["Response returned"]
  A6 --> A8["Notify watchers of the change"]
        
FIG 2 — The stages of a write request, each one a place to measure
1

Authentication and authorization

The server identifies the caller and checks permissions. These checks are usually quick, but they can slow down if they depend on an external identity service that responds slowly.

2

Admission control

Built-in and custom checks may modify or reject the request. Custom webhooks are external programs the server must call and wait for, so they add their own network time and processing time to every matching request.

3

Validation and storage

The server confirms the object is well formed and writes it to the database. Writes must be agreed upon by a majority of database members, so storage speed and network speed between members matter greatly here.

4

Notification of watchers

After the change is stored, the server tells every client that has asked to hear about such changes. With many watchers, this fan-out becomes a real cost.

5

Reaction by controllers and the scheduler

These components hear about the new object, do their work, and write back changes of their own, each of which repeats the same journey. A single pod creation can cause many separate requests.

Reads are different from writes

A read request, such as listing all pods in a namespace, takes a different and often cheaper path. The server can answer many reads from a copy it keeps in its own memory, called the watch cache, without bothering the database. But a read that demands the very freshest data, or one that asks for an enormous result, can bypass this shortcut and cause real work. Understanding which requests use the shortcut and which do not is one of the most valuable pieces of control plane knowledge.

i
Practical Advice

Whenever someone reports “creating things is slow”, ask first whether the delay is before the object is stored, which points to the front door and admission, or after it is stored, which points to controllers, the scheduler, or the nodes. This single question cuts the search space in half.

4The Language of Performance: Latency, Throughput, and Saturation

A handful of ideas explain almost every performance conversation. Learn them once and the rest becomes much easier.

Latency: how long one thing takes

Latency is the time between asking and receiving. If you request a pod listing and the answer arrives in twenty milliseconds, the latency of that request was twenty milliseconds. Latency is what humans feel directly. A person running a command notices when it takes three seconds instead of three hundred milliseconds, even if they could not describe why.

Throughput: how many things per unit of time

Throughput is the number of requests handled each second. A control plane might serve two hundred requests per second comfortably and struggle at two thousand. Throughput describes capacity, while latency describes experience, and the two are linked: as throughput approaches the limit, latency rises sharply.

Saturation: how full the system is

Saturation measures how close a resource is to its limit, such as processor usage, memory, disk activity, or the number of requests waiting in a queue. A resource at ninety-five percent saturation has almost no room to absorb a spike, and a tiny burst of extra work will cause a pile-up. Saturation is the best early warning, because it rises before users complain.

Simple Analogy

Think of a highway. Latency is how long your trip takes. Throughput is how many cars pass a point each minute. Saturation is how packed the lanes are. A half-empty highway has fast trips. As lanes fill, trips slow down gradually, and at some point one small incident causes a total jam. The jam seems sudden, but the packing that caused it built up quietly.

Why averages lie and percentiles tell the truth

Suppose ninety-nine requests finish in ten milliseconds and one request takes ten seconds. The average is about one hundred and ten milliseconds, which sounds fine and hides the slow request completely. Percentiles fix this. The ninety-ninth percentile, often written p99, is the value below which ninety-nine percent of requests fall. It reveals the slow tail that real users hit regularly. Control plane health is almost always judged by percentiles, because the slow tail is where controllers time out, retries pile up, and people lose patience.

MeasureQuestion it answersTypical control plane exampleDanger sign
LatencyHow long does one request take?Time to create a pod objectHigh p99 even when the average looks fine
ThroughputHow many requests per second?Requests handled by the interface server each secondThroughput flat while demand keeps rising
SaturationHow close to the limit?Disk activity on the database machine, or requests waiting in queuesSustained high usage with queues growing
ErrorsHow many requests fail?Timeouts and throttling responsesRising error rate during busy periods

SLIs and SLOs: turning feelings into targets

A service level indicator, or SLI, is a measured number that reflects user experience, such as “the share of write requests finishing within one second”. A service level objective, or SLO, is the target you set for that number, such as “ninety-nine percent of write requests finish within one second over a month”. The Kubernetes community itself publishes scalability targets in this style, including expectations that common write and single-object read requests complete within about a second at the ninety-ninth percentile, with larger target times for broader list requests, and a short startup target for ordinary stateless pods. Setting your own objectives, informed by these published ones, turns vague complaints into measurable goals.

“You cannot improve what you have not measured, and you cannot measure well what you have not named.”
!
Common Mistake

Watching only average latency is the most common reason teams miss control plane trouble. Always chart high percentiles beside the average, and set alerts on the high percentiles.

5What to Measure: Metric Families and Where They Come From

The control plane tells you a great deal about itself. You only need to know where to listen.

Metrics exposed by every component

Each control plane component publishes a rich set of numbers describing its own behavior, available over a standard web endpoint in a format that popular monitoring systems understand. A monitoring system scrapes these endpoints every few seconds, stores the history, and lets you chart and alert on them. This is the foundation of all control plane profiling, and it costs almost nothing to turn on.

API Server

Request duration and count

How long requests take and how many arrive, broken down by action, resource type, and response code.

API Server

In-flight and queued requests

How many requests are being processed right now and how many are waiting, which shows saturation directly.

etcd

Disk sync and commit time

How long the database takes to make writes durable on disk, the most important health signal for the database.

etcd

Database size and leader changes

How big the stored data is and how often the group of database members changes its leader.

Scheduler

Scheduling attempt duration and pending pods

How long placement decisions take and how many pods are waiting for a home.

Controllers

Work queue depth and processing time

How many pieces of work are waiting for each controller and how long each takes to process.

Three levels of insight

LevelWhat it gives youCostBest used for
MetricsNumbers over time, cheap and always onVery lowDetecting that something is wrong and roughly where
Traces and audit recordsThe story of individual requests, including who sent them and how long each stage tookModerateFinding which client or request pattern causes the load
Code-level profilesWhere inside the program processor time, memory, and waiting are spentHigher, used brieflyExplaining why a component itself is slow once it is confirmed to be the culprit
i
Practical Advice

Work from cheap to expensive. Start with metrics to locate the problem area, move to traces and audit records to identify the responsible clients, and use code-level profiles only when you must understand the internals of a specific component. This order saves time and avoids adding load to an already struggling system.

!
Watch Out

On managed Kubernetes services, the provider runs the control plane and decides which metrics and logs you can see. Check what your provider exposes before planning your profiling approach, and learn whether you can view interface server metrics, database health, and audit records. Some providers expose many; some expose only a few.

6Profiling the API Server: The Busiest Component

The front door is where most control plane stories begin and where most of them can be understood.

Reading request duration the right way

The interface server records how long each request takes, grouped by the kind of action, such as get, list, create, update, patch, delete, and watch, and by the type of object involved. These durations are stored in buckets, which lets a monitoring system calculate percentiles. The first habit to build is to never look at all requests together. A flood of fast reads can hide a handful of painfully slow writes, and a single enormous list request can distort every chart. Always split by action and by resource type.

Long-running watch requests need special care. A watch is a request that stays open for minutes, so its duration is long by design and says nothing about health. Good dashboards exclude watches from latency charts and track them separately, as a count of open connections and as a rate of events delivered.

Signals that point to trouble

1

Rising high-percentile latency for writes

Writes depend on the database and on admission webhooks. If write latency climbs while read latency stays calm, suspect storage speed, slow webhooks, or a very busy database leader.

2

Rising latency for list requests

Lists scale with the size of the result. If list latency rises, look for clients asking for huge result sets, requests that bypass the cache, or growth in the number of objects.

3

Increasing throttled and timed-out responses

When the server rejects requests because it is overloaded, or when clients give up waiting, the system is already past comfortable capacity.

4

Growing memory use in the server

Memory growth often follows large list responses, many watchers, or very large objects. Because the server keeps a cache in memory, big objects and many objects directly raise memory needs.

5

Uneven load across multiple server instances

In a highly available setup, a single instance may carry most of the traffic because long-lived client connections stick to it. That instance becomes the weak link while others sit idle.

Request size and response size matter

Time is not the only cost. A request that returns forty megabytes costs processor time to assemble, memory to hold, and network time to send, even if it finishes quickly. Tracking response sizes by resource type reveals the heaviest consumers. It is common to discover that one resource type, perhaps a collection of configuration maps or events, accounts for the majority of bytes served.

Simple Analogy

A library clerk may answer a hundred quick questions in the time it takes to photocopy one thousand-page book for a customer. If you only count questions answered, the clerk looks productive. If you count effort, the book was the real cost. Request counts alone hide heavy requests in exactly this way.

i
Good to Know

Group metrics by the identity of the caller wherever your tooling allows it, through audit records or request attribution. Knowing that a specific controller or tool produces most of a heavy request pattern turns an abstract load problem into a concrete conversation with its owner.

7Fairness Under Pressure: API Priority and Fairness

When demand exceeds capacity, someone has to wait. This mechanism decides who, and keeps important traffic moving.

The problem it solves

Before modern fairness controls, the interface server protected itself with a simple limit on the total number of requests in flight at once. When the limit was reached, extra requests were rejected. This crude approach had a nasty flaw: one noisy client could consume the entire limit and starve everyone else, including critical components like the node agents and controllers that keep the cluster healthy. A runaway script could effectively take the cluster down.

How fairness works

The modern mechanism, called API Priority and Fairness, sorts incoming requests into categories using rules that look at who is asking and what they are asking for. Each category belongs to a priority level, and each priority level has its own share of the server’s capacity and its own set of waiting lines. Within a priority level, requests from different sources are placed into separate lines and served in a fair rotation, so that one chatty source cannot crowd out the rest. Requests that must wait are held in a line for a short time; if the line is too long or the wait too great, the request is rejected so the client can back off.

flowchart LR
  I["Incoming requests"] --> C["Classify by caller and request type"]
  C --> P1["High priority level: system and leader election"]
  C --> P2["Medium priority level: workload controllers"]
  C --> P3["Lower priority level: general clients"]
  P1 --> Q1["Fair queues"]
  P2 --> Q2["Fair queues"]
  P3 --> Q3["Fair queues"]
  Q1 --> E["Executed within capacity share"]
  Q2 --> E
  Q3 --> E
        
FIG 3 — Requests sorted into priority levels, then queued fairly within each level
Simple Analogy

Think of an airport security checkpoint with a fast lane for crew and emergency staff, a priority lane for frequent flyers, and a general lane for everyone else. Inside each lane, people are served in order, so no single large tour group can block the others. When everything gets too crowded, staff politely ask late arrivals to try again in a few minutes rather than letting the whole terminal seize up.

What to look for when profiling fairness

Signal

Requests waiting in queues

Shows how many requests are delayed, by priority level. Persistent queues in an important level are a clear warning.

Signal

Wait time before execution

Shows how long requests spend waiting before they begin running. Rising wait time means capacity is tight.

Signal

Rejected requests

Counts requests turned away because queues were full or waits too long. Any sustained rejection in a critical level needs attention.

Signal

Seat usage per level

Shows how much of each level’s share is used. A level always at its limit may need a larger share or fewer heavy clients.

i
Practical Advice

Create a dedicated, lower-priority category for noisy but non-critical tools, such as reporting jobs and experimental automation. This protects the cluster’s essential traffic automatically, and it gives you a clear place to watch when a tool misbehaves.

!
Common Mistake

Raising capacity shares to make rejections disappear can simply move the overload down to the database, which has no such protection. Fix the heavy client first; adjust shares only when the demand is genuine and the downstream components can support it.

8Expensive Requests: Lists, Watches, and Giant Objects

A few request patterns cause most control plane pain. Learn to recognize them on sight.

The unbounded list

A list request asks for every object of some type, possibly across the entire cluster. In a cluster with fifty thousand pods, an unfiltered cluster-wide list produces an enormous response. Building that response uses memory proportional to its size, and sending it ties up network and processor time. If many clients do this at once, the interface server can run out of memory and restart, and the restart makes every client reconnect and list again, which causes the problem to repeat. This feedback loop is one of the classic ways clusters fall into a spiral.

How good clients avoid the trap

Well-written controllers do not repeatedly list. They list once, then open a watch, and from then on they receive only changes, keeping a local copy in memory. This pattern, implemented by shared helper libraries often called informers, reduces load dramatically. Poorly written tools, by contrast, poll the full list every few seconds, and a handful of them can dominate the server.

Good

List once, then watch

Receive changes as a stream and keep a local copy, instead of repeatedly asking for everything.

Good

Filter at the source

Ask only for objects with specific labels or fields, so the server returns a small result.

Good

Paginate large lists

Request results in chunks so memory use stays bounded and one request cannot monopolize resources.

Good

Allow cached reads when freshness is not critical

Reads that accept slightly older data can be served from the server’s memory instead of the database.

The watch cache and the cost of freshness

The interface server keeps a recent copy of objects in memory and can answer many reads from it. A client can usually choose between “give me the freshest possible data”, which forces a trip to the database to confirm the latest state, and “any reasonably recent data is fine”, which can be served from memory. The first choice is safer for correctness but costs much more. Many tools request the freshest data out of habit, even when they do not need it, and those habitual requests can make up a large share of database reads.

Watches at scale

Every watch is a long-lived connection that costs memory and requires the server to check each change against it. Ten thousand watchers across a large cluster mean that every single write must be considered for delivery to many listeners. The rate of change multiplied by the number of watchers is the true workload. Tools that open many separate watches, instead of sharing one, multiply this cost needlessly.

Large objects

Objects have a size limit, but even objects well below the limit can cause trouble when there are many of them or when they change often. A configuration object holding a megabyte of data that is updated every few seconds creates constant database traffic, constant cache updates, and constant watch notifications. Oversized objects are an especially common cause of unexplained database growth and slow writes.

ANTI-PATTERN-01 Avoid
Problem

A dashboard or script repeatedly lists all objects of a large type across the whole cluster every few seconds.

Why It’s Harmful

Each repetition forces the server to build and send a huge response. Several such tools together can exhaust memory, trigger restarts, and cause a reconnect storm that worsens the overload.

Correct Approach

Use the list-then-watch pattern through shared client helpers, filter requests narrowly, paginate when listing is unavoidable, and accept cached reads wherever slight staleness is acceptable.

i
Good to Know

Newer Kubernetes releases continue to improve how large lists are streamed to clients, reducing the memory spikes they cause. Check the release notes of the version you run to see which of these improvements are available and enabled by default.

9Extension Points That Add Delay: Webhooks, Custom Resources, and Aggregated APIs

Kubernetes is deliberately extensible. Every extension is also a place where performance can leak away.

Admission webhooks

An admission webhook is a separate program that the interface server calls during a request, to inspect or modify the object before it is saved. Security tools, policy engines, and sidecar injectors all use them. Because the server waits for the answer, a webhook’s speed becomes part of every matching request. If a webhook takes half a second, every pod creation takes at least half a second longer. If the webhook is unreachable, requests may fail or stall until a timeout expires, depending on how the webhook is configured.

Benefits of webhooks

  • Enforce security and compliance rules automatically
  • Inject standard settings so developers need not remember them
  • Keep policy logic outside the core, so it can evolve independently
  • Block risky configurations before they exist

Performance risks of webhooks

  • Every matching request waits for the webhook’s response
  • A slow or unavailable webhook can stall or fail many requests
  • Webhooks that match too broadly add delay to unrelated traffic
  • A webhook that depends on the cluster it guards can create circular failures

Profiling webhook cost

The interface server records how long admission steps take, broken down by the individual webhook. Reviewing these durations quickly reveals which webhooks consume the most time. Also review how many requests each webhook intercepts. A webhook limited to specific namespaces and object types costs far less than one that intercepts everything.

Narrow the match

Configure each webhook to apply only to the object types, actions, and namespaces it truly needs, so unrelated requests skip it entirely.

Set sensible timeouts

Use short timeouts so a failing webhook cannot hold requests for long, and decide deliberately whether a failure should block the request or let it through.

Keep webhooks healthy and close

Run several replicas, spread them across failure zones, and keep them on fast, reliable network paths close to the interface server.

Custom resources and controllers

Custom resource definitions let you add new object types to the cluster. Each one adds to the amount the interface server must track and cache, and each usually comes with its own controller that watches and updates objects. A cluster with hundreds of custom resource types and tens of thousands of instances carries a significantly heavier load than one with a few. Review which custom types are truly needed and how many instances exist.

Aggregated APIs

Some extensions register entire API groups served by separate programs. The interface server forwards matching requests to them. Their speed and availability become part of the cluster’s perceived speed, and a failing aggregated API can cause slow or failing discovery for every client, which affects tools that scan all API groups. Monitor the health and latency of every aggregated service just as you monitor the core.

!
Common Mistake

Installing extensions freely and never measuring their cost is how control planes gradually slow down over a year without any single obvious change. Review the list of webhooks, custom types, and aggregated APIs regularly, and remove anything unused.

10etcd: The Memory of the Cluster

If the interface server is the front door, etcd is the vault behind it. Its speed sets the ceiling for everything above.

What etcd is and why it is special

etcd is a distributed key-value database that stores every object in the cluster: every pod, every secret, every configuration, every lease. It is designed for correctness above all else. It promises that once a change is confirmed, it is durable and that all members agree on the order of changes. That promise is valuable, and it comes at a performance price that you must understand to profile it well.

How a write works inside etcd

etcd runs as a group of members, typically three or five. One member is the leader. All writes go to the leader, which records the change in a log on its own disk and sends it to the other members. Each member records it on its own disk too. Only when a majority of members have safely written the change to disk does the leader confirm it. This means that the speed of a write is limited by the slowest disk among the majority and by the network between the members.

sequenceDiagram
  participant A as API server
  participant L as etcd leader
  participant F1 as Follower one
  participant F2 as Follower two
  A->>L: Write request
  L->>L: Append to log on disk
  L->>F1: Send log entry
  L->>F2: Send log entry
  F1->>F1: Append to log on disk
  F2->>F2: Append to log on disk
  F1-->>L: Acknowledge
  F2-->>L: Acknowledge
  L->>L: Majority reached, commit
  L-->>A: Write confirmed
        
FIG 4 — A write is confirmed only after a majority writes it safely to disk
Simple Analogy

Imagine three notaries who must each stamp a contract before it becomes official, and the contract is valid once two of the three have stamped. The overall speed depends on how quickly the second-fastest notary stamps and how fast messengers travel between them. A single slow notary may not matter, but two slow notaries, or slow messengers, delay everything.

The three resources etcd cares about

Disk

Disk write latency

The most critical factor. Every committed change must be flushed to durable storage, so slow disks directly slow every write in the cluster.

Network

Network latency between members

Members exchange messages for every write and for regular heartbeats. High or unstable latency causes slow writes and unwanted leader changes.

Memory

Memory and database size

The database is designed to be read quickly from memory-mapped files. A very large database needs more memory and takes longer to maintain.

Processor

Processor for bursts

Usually modest, but heavy list traffic and large objects can create bursts that need headroom.

i
Practical Advice

Give etcd fast, dedicated storage, ideally local solid-state drives, and keep its members on a low-latency network, preferably within a single region. A modest control plane with excellent disks often outperforms a much larger one with slow shared disks.

11Profiling etcd: Reading Its Vital Signs

A handful of etcd numbers tell you almost everything about the health of the cluster’s memory.

The vital signs

Just as a doctor checks pulse, temperature, and blood pressure first, an engineer profiling etcd checks a short list of numbers before anything else. Each one maps to a specific kind of problem, so reading them together quickly narrows the diagnosis.

Vital signWhat it tells youHealthy patternWarning pattern
Write-ahead log sync durationHow long the disk takes to make log entries durableConsistently in single-digit milliseconds at the high percentileHigh percentile climbing into tens of milliseconds or more, which signals slow storage
Backend commit durationHow long the database takes to commit batched changes to its data fileLow and steadySpikes that match periods of heavy writes or maintenance
Database sizeHow much data is stored, including space that could be reclaimedStable or slowly growing, comfortably below the configured quotaRapid growth, or size approaching the quota
Leader changesHow often the group elects a new leaderRare, mostly during planned maintenanceFrequent changes, which pause writes while a new leader is chosen
Proposals pending and failedHow many writes are waiting for agreement or have failedNear zeroGrowing backlog or a steady stream of failures
Request duration seen by etcdHow long etcd itself takes to serve requests by typeLow and stableSlowness in etcd that matches slowness at the interface server

Why storage is the usual suspect

In a great many real incidents, slow control planes turn out to be caused by slow disks on the database machines. This happens most often when etcd shares a disk with other busy programs, when it runs on network-attached storage with variable latency, or when a cloud volume hits its input and output limits. The symptoms are subtle: everything works, but writes take longer, leader elections become more frequent because heartbeats miss their deadlines, and the whole cluster feels sluggish.

Why the database grows and what to do about it

etcd keeps a history of changes so that watchers can resume from where they left off. Over time, old versions pile up. A process called compaction discards history older than a chosen point, which marks space as reusable. A second process called defragmentation actually returns that space so the file shrinks. Without regular compaction, the database grows. If it reaches its size quota, etcd stops accepting writes and the whole cluster becomes read-only, which is one of the most disruptive failures a control plane can suffer. Kubernetes normally triggers compaction automatically, but you must still watch size and plan defragmentation during quiet periods, since defragmenting a member briefly blocks it.

flowchart TD
  A["Many updates create many versions"] --> B["Database file grows"]
  B --> C["Compaction discards old history"]
  C --> D["Free space inside the file"]
  D --> E["Defragmentation returns space to the disk"]
  B -->|"Quota reached"| F["Writes refused: cluster becomes read-only"]
        
FIG 5 — Why database size must be watched and maintained
!
Watch Out

Hitting the database size quota is an emergency, not a gradual slowdown. Alert well before the limit, for example when usage passes a comfortable fraction of the quota, so you have time to find out what is growing and to reclaim space calmly.

Finding what fills the database

When the database grows unexpectedly, the question is always which object types and which objects take the most space. Usually a small number of types account for most of it, commonly events, large configuration objects, custom resources written by operators, or leftover objects from jobs that are never cleaned up. Counting objects by type and measuring their combined size points straight to the culprit. A common remedy is to move high-churn, low-value data such as events to a separate database so it cannot crowd the main one.

i
Good to Know

Time-based cleanup of finished jobs, expired events, and abandoned custom objects is among the cheapest and most effective performance improvements available. Smaller databases are faster to read, faster to back up, and faster to restore.

12Profiling the Scheduler: How Fast Do Pods Find a Home?

The scheduler solves a matching puzzle thousands of times a day. Profiling shows whether it keeps up.

What the scheduler actually does

When a new pod appears without a node, the scheduler picks one. It does this in two broad phases. First it filters, removing every node that cannot run the pod, for reasons such as insufficient resources, mismatched labels, or rules forbidding the placement. Then it scores the remaining nodes, ranking them by how well they fit, and picks the best. Finally it records the decision by telling the interface server which node was chosen, and the node’s agent takes over from there.

flowchart LR
  A["Pod waiting in queue"] --> B["Filter: remove nodes that cannot run it"]
  B --> C["Score: rank remaining nodes"]
  C --> D["Choose best node"]
  D --> E["Reserve resources in scheduler memory"]
  E --> F["Bind: tell API server the choice"]
        
FIG 6 — The stages of a scheduling decision

What to measure

Speed

Scheduling attempt duration

How long each decision takes, split by outcome. Rising times suggest heavy rules or very large clusters.

Backlog

Pending pods by queue

How many pods are waiting, and in which queue. Pods that cannot be placed sit in a separate waiting area and are retried later.

End to end

Time from creation to placement

The delay a user actually feels, including time spent waiting in queues before the scheduler even looked.

Reliability

Binding errors and retries

Failures when recording decisions, which usually point back to interface server or database trouble.

Common reasons scheduling feels slow

The pod simply cannot fit anywhere

The scheduler is not slow; the cluster has no suitable node. The pod stays pending, and its status explains why. Profiling must separate “slow to decide” from “no valid answer exists”.

Complex placement rules

Rules that relate pods to each other, such as spreading across zones or avoiding certain neighbors, require comparing each candidate against many existing pods. These are powerful but expensive in large clusters.

Slow dependencies

Decisions that rely on volume checks or external plugins can stall if the underlying systems respond slowly.

Bursty arrivals

Launching thousands of pods at once, such as at the start of a large batch job, creates a queue. The scheduler handles them one decision at a time per scheduling cycle, so large bursts take real time.

i
Practical Advice

For very large clusters, the scheduler can be configured to examine only a portion of eligible nodes before choosing, trading a small loss in placement quality for a large gain in speed. Measure the effect on your own workloads before and after adjusting such settings.

!
Common Mistake

Blaming the scheduler for pods stuck in a pending state without reading the reason attached to the pod. Most pending pods are waiting for a legitimate reason, such as insufficient capacity or an unsatisfied storage request, which no amount of scheduler tuning will fix.

13Profiling Controllers: Queues, Retries, and Client-Side Limits

Controllers are the muscle of Kubernetes. When they fall behind, the cluster reacts late to everything.

How a controller works

A controller follows a simple loop. It watches objects of some kind, and whenever one changes, it places a small note in a work queue. A set of workers takes notes from the queue, compares desired state with actual state, and takes action to close any gap. For example, the controller for replicated sets notices that fewer pods exist than requested and creates the missing ones. The loop repeats forever. Because everything flows through queues, queue behavior is the best window into controller health.

flowchart LR
  W["Watch events from API server"] --> Q["Work queue"]
  Q --> K["Worker takes an item"]
  K --> R["Compare desired and actual state"]
  R --> A["Act: create, update, or delete objects"]
  A -->|"Failure"| Y["Retry later with backoff"]
  Y --> Q
        
FIG 7 — The controller loop and its work queue

The queue metrics that matter

Queue metricMeaningIf it looks bad
DepthHow many items wait right nowA depth that keeps growing means workers cannot keep up with arrivals
Time in queueHow long items wait before being picked upLong waits mean the cluster reacts to changes slowly, even if each item is quick to process
Processing timeHow long a worker spends per itemSlow processing points to expensive reconciliation logic or slow calls to the interface server
RetriesHow often items must be tried againHigh retries signal repeated failures, conflicts, or a dependency that keeps erroring
Longest running workerThe age of the oldest unfinished itemA stuck worker blocks progress for the items that depend on it

Client-side rate limiting: the hidden brake

Every controller talks to the interface server through a client library that limits how fast it may send requests, to protect the server. This limit has two settings: a steady rate of requests per second, and a burst allowance for short spikes. If a controller needs to send more requests than its limit allows, the library makes it wait, silently. The controller appears slow, its queue grows, yet the interface server shows no stress at all, because the delay happens inside the client. This confuses many investigations.

Simple Analogy

Imagine a delivery driver who has been told never to make more than a few stops per hour, no matter how many parcels are on the truck. The warehouse is idle and the roads are empty, yet parcels pile up. The bottleneck is a rule inside the driver’s own company, invisible to anyone looking at the roads or the warehouse.

Reading client-side throttling

Look for metrics and log messages showing time spent waiting on the client’s own rate limiter. Compare this with server-side latency: if the server answers quickly but the controller is slow, client-side limits are the likely explanation. Raising a client’s limits can fix this, but only after confirming that the server and database have spare capacity, because a higher limit simply moves the pressure forward.

!
Common Mistake

Increasing client limits across all controllers at once is a risky way to “make things faster”. If every client then sends much more traffic, the interface server and database can be overwhelmed. Raise limits for a specific, proven bottleneck, measure, and proceed step by step.

Custom controllers and operators

The controllers you write or install yourself deserve the same scrutiny as built-in ones. Operators for databases, message brokers, and certificates often become the heaviest clients of the interface server, because they reconcile large numbers of objects frequently. Check that they use shared informer caches, that they avoid updating objects when nothing has changed, and that they do not trigger endless reconciliation loops by reacting to their own writes.

14Nodes Also Talk to the Control Plane

Thousands of node agents send constant status reports. At scale, their chatter is a major part of the load.

Heartbeats and node status

Each node runs an agent called the kubelet, which regularly tells the control plane that the node is alive and reports its condition. Early versions sent a full status update frequently, and each update was a write to the database. In a cluster with thousands of nodes, this created enormous write traffic. Modern versions use lightweight lease objects for the frequent heartbeat and send the full status much less often, which greatly reduces the load. Still, the number of nodes multiplied by their reporting rate remains an important contributor to control plane work.

Pods and their status updates

Every pod also generates status updates as it starts, becomes ready, changes, or stops. A cluster that frequently creates and destroys short-lived pods, for instance one running many small batch tasks, produces a constant stream of writes. Likewise, readiness and liveness checks that flip frequently cause repeated updates. Profiling often reveals that a few noisy workloads generate a large share of status traffic.

Source

Node heartbeats

Frequent but small. Scale with the number of nodes.

Source

Pod lifecycle changes

Scale with how often pods are created, restarted, and removed.

Source

Flapping health checks

A check that keeps switching between passing and failing creates constant updates and notifications.

Source

Events

Every notable action emits an event object. Crash loops and scheduling failures can produce floods of events.

i
Good to Know

A single crash-looping workload with many replicas can produce a surprising volume of events and status updates. Fixing one broken deployment sometimes lowers control plane load more than any tuning effort.

Reduce churn at the source

Prefer longer-lived workloads where possible, batch very small tasks into fewer pods, and fix pods that restart repeatedly.

Tune health checks sensibly

Choose check intervals and thresholds that reflect real needs, so brief hiccups do not cause constant flips between ready and not ready.

15Going Deeper: Code-Level Profiling with pprof and Flame Graphs

When you know which component is slow, code-level profiling shows exactly which part of its program is responsible.

What a code-level profile shows

The control plane components are written in the Go programming language, which has excellent built-in profiling support. A profile is a sampled record of what the program was doing. At regular tiny intervals, the profiler notes which functions were running, and over thousands of samples, a clear picture emerges of where time and memory go. The components expose profiling endpoints that authorized users can request, and the results can be viewed with standard tools.

Profile type

Processor profile

Shows which functions use the most processor time. Best for finding computation-heavy work.

Profile type

Heap profile

Shows which parts of the program hold the most memory. Best for explaining memory growth and restarts.

Profile type

Goroutine profile

Shows what each concurrent task is doing. Best for finding leaks and tasks stuck waiting.

Profile type

Mutex and blocking profiles

Show where tasks wait for locks or other tasks. Best for explaining slowness when processors are idle.

Reading a flame graph

A flame graph turns sampled data into a picture. Each horizontal bar represents a function. The bar’s width shows how much of the total time that function and everything it called consumed. Bars are stacked, with callers below and callees above. The wide bars are your suspects. A wide bar near the top, with nothing above it, means that function itself uses a lot of time. A wide bar lower down with many narrower bars above it means time is spread across the things it calls.

Simple Analogy

Imagine a time-lapse photograph of a busy kitchen taken every few seconds all evening. Afterward, you count in how many photos the chef was chopping, stirring, plating, or waiting for ingredients. The counts reveal where the chef’s evening really went. A flame graph is that photo count drawn as a picture, so the biggest time sinks stand out immediately.

1

Capture during the problem

A profile taken while the system is healthy teaches little. Capture during the slowdown, for long enough to collect a representative sample, typically tens of seconds.

2

Capture a baseline too

Take another profile during normal operation. Comparing the two highlights what changed, which is often more informative than either profile alone.

3

Look for the widest bars

Focus on functions that dominate the picture, and read their names to understand what the program was doing, for example serializing objects, filtering, or waiting for storage.

4

Connect findings back to requests

Link what the profile shows to the request patterns you found earlier. If time goes to serializing huge list responses, return to the offending client rather than modifying the server.

Continuous profiling

Because slowdowns are often brief and unpredictable, some teams run continuous profiling, which samples programs at a very low rate all the time and stores the results. When an incident occurs, the profile from that exact moment is already available. The cost is small, and the benefit is that you stop missing the evidence of problems that vanish before anyone can investigate.

!
Security and Safety

Profiling endpoints expose internal details of a critical component, and heavy profiling adds load. Restrict access to authorized administrators, never expose these endpoints publicly, and avoid capturing many large profiles at once on a component that is already under stress.

16Tracing and Audit Records: Finding Who Causes the Load

Metrics show that load exists. Traces and audit records show who creates it and why.

Audit records

The interface server can record each request: who sent it, what they asked for, when, and what the response was. At a modest detail level, this creates a searchable history of activity. Analyzing it answers questions metrics cannot, such as which service account made the most list requests last night, which tool updated the same object ten thousand times, or which user deleted a particular resource.

Top callers by request volume

Group requests by user or service account to find the heaviest clients, then check whether their volume makes sense.

Top callers by expensive actions

Focus on large list requests and unfiltered cluster-wide queries, which cost far more than their count suggests.

Repeated updates without change

Spot tools that write the same data over and over, wasting database capacity and triggering unnecessary watch notifications.

Distributed tracing

Tracing follows a single request across components and records how much time was spent in each stage. The interface server and the database can both emit traces, which lets you see, for one slow request, whether the time went to authentication, admission webhooks, or the database write. Because tracing is more expensive than metrics, it is usually sampled: only a small fraction of requests are traced, which is enough to reveal patterns without adding much load.

flowchart LR
  M["Metrics: something is slow"] --> A["Audit records: who is sending the heavy requests"]
  A --> T["Traces: which stage of those requests is slow"]
  T --> P["Profiles: which code is responsible"]
  P --> F["Fix at the source"]
        
FIG 8 — A funnel from broad signals to precise causes
i
Practical Advice

Audit logging at high detail can itself become heavy, producing large volumes of data and adding work to every request. Choose detail levels deliberately: record metadata for most requests and full bodies only for the sensitive operations that truly require them.

17Load Testing: Learning Limits Before Production Teaches Them

Waiting for a real traffic spike to discover your limits is an expensive way to learn. Controlled tests are cheaper.

Why test the control plane on purpose

Metrics from a healthy production cluster tell you how the control plane behaves under ordinary load, but they cannot tell you where the cliff is. Load testing pushes the system deliberately, in a safe environment, to reveal the point where latency begins to climb and the component that gives way first. Knowing your cliff in advance lets you set alerts at sensible distances from it and plan capacity before demand arrives.

What a good test looks like

A useful test imitates real behavior instead of simply hammering one endpoint. It creates many objects of realistic shapes and sizes, runs many watchers, mixes reads and writes in realistic ratios, and exercises the scheduler and controllers by creating real workloads. The Kubernetes community maintains dedicated testing tools for this purpose, and other open-source projects specialize in creating large numbers of objects and measuring how the control plane responds. The best of them measure the same service level indicators you use in production, so results are directly comparable.

Step 1

Define the questions

Decide what you want to learn, for example how many nodes the current control plane supports, or how a new operator affects latency.

Step 2

Build a realistic environment

Use the same versions, settings, and storage types as production, since results from a different setup may not transfer.

Step 3

Ramp up gradually

Increase load in steps and hold each step long enough to observe steady behavior, instead of jumping straight to the maximum.

Step 4

Record everything

Capture metrics, profiles, and logs throughout, so you can explain results later rather than only observing them.

Simulated nodes and their limits

Creating thousands of real machines for a test is costly, so some tools simulate nodes: lightweight programs that pretend to be node agents and report status to the control plane. They are excellent for measuring control plane load from node traffic. They cannot reproduce everything real nodes do, such as actually running workloads, so use them to test the control plane and not the nodes.

Test typeWhat it revealsWhen to run it
Steady-state loadNormal capacity and baseline latencyBefore and after major upgrades
Ramp testThe load at which latency starts risingWhen planning growth
Spike testBehavior under sudden bursts, such as many pods starting at onceBefore launching large batch or event-driven workloads
Soak testSlow problems like memory growth and database bloatBefore trusting a new component in production
Failure testBehavior while a member is lost or restartedRegularly, as a reliability exercise
!
Common Mistake

Running load tests against a production cluster to “see what happens” can cause the very outage you hoped to prevent. Test in an isolated environment that mirrors production, and only ever run gentle, well-announced tests in live environments.

18A Repeatable Method for Hunting Bottlenecks

Good engineers do not guess. They follow a method that narrows the search with every step.

Seven steps from symptom to fix

1

State the symptom precisely

“Deployments are slow” is vague. “Creating pods takes eight seconds at the ninety-ninth percentile since Tuesday” is something you can investigate.

2

Find when it started

Look at charts over several days. A sudden step usually matches a change, such as an upgrade, a new tool, or a configuration edit. A slow ramp suggests growth.

3

Locate the slow stage

Compare latencies across the front door, admission, the database, the scheduler, and controllers to find where time is added.

4

Check saturation of that component

Determine whether processor, memory, disk, network, or a queue is at its limit. A saturated resource is almost always the proximate cause.

5

Identify the source of the load

Use audit records and request attribution to find which clients and request types are responsible for the extra work.

6

Form a hypothesis and test it

State what you believe is the cause and what change should confirm it. Apply one change at a time, ideally to a test environment first.

7

Verify and prevent recurrence

Confirm the symptom is gone, then add an alert or a guardrail so the same problem is caught earlier next time.

flowchart TD
  S["Symptom reported"] --> A{"Did it start with a change?"}
  A -->|"Yes"| B["Review recent changes and consider rollback"]
  A -->|"No, gradual"| C["Check growth in objects, nodes, and clients"]
  B --> D["Locate slow stage"]
  C --> D
  D --> E{"Which stage?"}
  E -->|"Front door or admission"| F["Check request mix, webhooks, fairness queues"]
  E -->|"Database"| G["Check disk latency, size, leader changes"]
  E -->|"Scheduler or controllers"| H["Check queues, client limits, placement rules"]
  F --> I["Fix source, then verify"]
  G --> I
  H --> I
        
FIG 9 — A decision path from reported symptom to verified fix

Two helpful lenses

Two simple frameworks organize this thinking. The first examines each resource by its utilization, its saturation, and its errors. The second examines each service by its request rate, its error rate, and its duration. Used together, they ensure you look at both the machines and the work they serve, and they prevent the common trap of staring at only one kind of chart.

i
Good to Know

Write down every hypothesis and what you did to test it, even the ones that turned out wrong. A written trail prevents repeating dead ends, and it becomes a valuable runbook for the next person who sees a similar symptom.

19From Symptom to Likely Cause: A Field Guide

Patterns repeat across clusters. This table maps common symptoms to the places you should look first.

SymptomLikely causesFirst things to check
Commands hang or take many secondsOverloaded interface server, slow admission webhook, slow authentication providerRequest latency by action, admission step durations, identity provider health
Interface server restarts repeatedlyMemory exhaustion from large lists or many watchesMemory trend, heavy list callers, number of open watches
Writes slow, reads fineSlow disks on the database, slow webhooks, large objectsDatabase disk sync times, webhook durations, object sizes
Frequent leader elections in the databaseSlow disks, network jitter between members, overloaded machinesDisk latency, network round trip times, processor use on database machines
Cluster suddenly read-onlyDatabase size quota reachedDatabase size against quota, largest object types, compaction status
Pods stay pending longNo capacity, unsatisfied volume, complex placement rules, scheduler backlogThe reason shown on the pod, scheduler queue sizes and attempt durations
Rollouts progress very slowlyController queues backed up, client-side throttling, slow readiness checksQueue depth and wait time, client rate limiter waits, readiness probe settings
Many rejected or throttled requestsOne noisy client, undersized capacity share, runaway automationFairness metrics by priority level, top callers from audit records
Nodes flap between ready and not readyHeartbeats delayed by overloaded interface server or network problemsLease update latency, interface server saturation, node network health
Slow discovery by toolsA failing or slow aggregated API, or very many custom resource typesHealth of aggregated services, count of registered API groups
Everything slows after an upgradeChanged defaults, new features creating extra load, incompatible extensionsRelease notes, metrics before and after, extension versions
!
Keep Perspective

A table of likely causes is a starting point, not a verdict. Real incidents often involve two or three contributing factors that interact. Use the table to choose where to look first, then confirm with data before making changes.

20Scale Limits and Sizing the Control Plane

Kubernetes publishes tested limits. Knowing them tells you how far you can push, and when to plan ahead.

Published scalability thresholds

The Kubernetes community tests and documents the largest clusters it considers supported, expressed as upper bounds on things like the number of nodes, the number of pods in total, the number of pods per node, and the number of services. These limits describe configurations the project continuously tests against its published service level objectives. Exceeding them does not mean failure, but it means you are in territory that is less thoroughly tested and where you must rely more on your own measurements. Check the current documentation for the exact numbers of the version you run, because they are revisited as the software improves.

Dimensions of scale

Dimension

Number of nodes

Drives heartbeat traffic, watch counts, and scheduler work.

Dimension

Number of pods and objects

Drives memory in the interface server cache and size of the database.

Dimension

Rate of change

Drives write load, watch fan-out, and controller work. A quiet large cluster is easier than a busy medium one.

Dimension

Number of clients

Drives request volume and the number of long-lived watches.

Dimension

Kinds of objects

Each additional custom type adds caching, watching, and controller overhead.

Dimension

Object sizes

Large objects amplify every operation: storage, transfer, caching, and notification.

Sizing the machines

Control plane machine sizes are usually chosen by how many nodes the cluster has and how busy it is. The interface server mostly needs processor and memory in proportion to the number of objects and clients. The database needs fast storage first, then adequate memory for its data file. Rather than picking a size from a generic chart, observe the actual utilization of existing machines during peak periods and keep comfortable headroom, since control plane problems tend to appear as sudden cliffs rather than gentle slopes.

1

Measure peak, not average

Look at the busiest hour of the busiest day, including events like large deployments and nightly jobs, because that is when the control plane is tested.

2

Leave headroom for failure

In a group of three interface server instances, losing one pushes its traffic onto the other two. Size so that the remaining instances can carry the load without saturation.

3

Prefer fixing load over adding size

Remove wasteful clients and unneeded objects before buying larger machines. Savings from efficiency compound; savings from hardware do not.

4

Revisit sizing at each growth step

Reassess when node counts, object counts, or the number of operators grows significantly, and retest with load tests where possible.

i
Practical Advice

Very large organizations often split one huge cluster into several moderately sized ones. Several clusters of manageable size can be simpler to operate and safer, since a control plane problem then affects only a portion of the workloads. Weigh that benefit against the extra effort of managing multiple clusters.

21High Availability, Leader Election, and Failover Performance

Running several copies of each component keeps the cluster alive during failures. It also changes how performance behaves.

Different components, different redundancy

The interface server is stateless, so you can run several copies and spread requests across them with a load balancer. All copies are active at the same time. The scheduler and controller manager are different: only one copy of each does the work at any moment, because two schedulers choosing placements independently would conflict. The copies use a leader election process, where each competes to hold a lease stored in the cluster, and only the holder acts. If the leader fails or loses its lease, another takes over.

flowchart TD
  LB["Load balancer"] --> A1["API server one"]
  LB --> A2["API server two"]
  LB --> A3["API server three"]
  A1 --> E[("etcd group: three or five members")]
  A2 --> E
  A3 --> E
  S1["Scheduler one: leader"] --> A1
  S2["Scheduler two: standby"] -.-> A2
  C1["Controller manager one: leader"] --> A1
  C2["Controller manager two: standby"] -.-> A3
        
FIG 10 — Active interface servers and leader-elected scheduler and controller managers

Performance consequences of leader election

Failover gaps

When a leader fails, the standby must wait for the old lease to expire before taking over. During that gap, no scheduling or reconciliation happens. Lease timing settings trade failover speed against the risk of needless leader changes.

Lease renewal traffic

Leaders renew their lease frequently, and each renewal is a write. If the interface server or database is slow, renewals can fail, causing a leader to give up even though it was healthy. This produces confusing flapping.

Cold caches after takeover

A new leader may need to rebuild its view of the world, which causes a burst of requests right when the cluster is already stressed by a failure.

Uneven traffic across interface server copies

Because clients keep long-lived connections, traffic can become lopsided. After a rolling restart, the first instance restarted may end up with few connections while the last ones carry many. Watch per-instance request rates and memory, and consider settings that gently recycle connections so load spreads out again.

!
Watch Out

A rolling upgrade of the control plane is a stress test. Restarted components reconnect all their clients at once, rebuild caches, and trigger bursts of list requests. Upgrade one instance at a time, wait for latency to settle between steps, and watch the charts during the process.

22Managed Control Planes: What You Can and Cannot Do

Many teams use a cloud provider’s managed Kubernetes. Profiling still matters, but the levers are different.

What changes with a managed service

In a managed service, the provider runs and scales the control plane. You usually cannot log into its machines, change its low-level settings, capture code-level profiles, or choose its disk types. The provider handles patching, failover, and often automatic scaling of capacity. That removes a great deal of work, but it also removes some of your visibility, and it does not remove your responsibility for how your own workloads and tools use the control plane.

What you gain

  • No need to operate the database or interface servers yourself
  • Provider expertise and automatic scaling in many cases
  • Built-in high availability across failure zones
  • Published service commitments and support channels

What you give up

  • Limited access to internal metrics and profiles
  • Fewer tuning options for the components themselves
  • Provider-imposed limits on request rates and object counts
  • Dependence on provider support for deep investigations

What you can still profile

Client side

Your own clients

Measure request rates, latency, and errors from your controllers, tools, and pipelines. You fully control these.

Provider data

Exposed metrics and logs

Many providers expose interface server metrics, audit logs, and fairness data. Enable and collect whatever is offered.

Workload

Object counts and sizes

Track how many objects of each type you create, and how large they are. You control the demand placed on the service.

Extensions

Your webhooks and operators

Their speed and request patterns are yours to measure and fix, even when everything else is the provider’s.

i
Practical Advice

When you open a support case with a provider, bring evidence: the time window, the affected operations, latency measurements from your clients, and any error messages. Precise, data-backed reports lead to faster, more useful answers than a general complaint that the cluster is slow.

23Dashboards and Alerts That Actually Help

Charts nobody understands and alerts nobody trusts are worse than none. Design them for the person using them at three in the morning.

A dashboard that tells a story

The best control plane dashboard reads from top to bottom like a short story. The top row shows overall health against your objectives: is the front door meeting its latency targets, and are errors low? The next rows break the story down by component: interface server, fairness queues, database, scheduler, and controllers. Lower rows show resource usage, and a final row lists the heaviest clients. A person arriving during an incident can start at the top, see whether the objective is violated, and work downward to find the guilty component, without needing to remember dozens of metric names.

1

Row one: objectives

Show the share of requests meeting latency targets and the error rate. This answers “are users hurting right now?”

2

Row two: the interface server

Latency percentiles by action, request rates, in-flight requests, fairness queue waits, and rejections.

3

Row three: the database

Disk sync and commit times, database size against quota, leader changes, and pending proposals.

4

Row four: scheduler and controllers

Pending pods, scheduling durations, queue depths, queue wait times, and retries.

5

Row five: resources and callers

Processor, memory, disk, and network of each component, plus the heaviest clients by request volume and cost.

Alerting on symptoms and on early warnings

Alerts fall into two useful groups. Symptom alerts fire when users are affected, such as when write latency violates its objective for a sustained period. These should wake someone up. Early-warning alerts fire when something is trending toward trouble, such as database size passing a comfortable fraction of its quota or disk sync times creeping upward. These should usually create a ticket for working hours, because they give you time to act calmly.

Burn rate: alerting on how fast you spend your allowance

If your objective allows a small share of slow requests each month, that share is an error budget, like a monthly allowance. Burn rate measures how fast you are spending it. A fast burn, which would exhaust the whole budget in a day or two, deserves immediate attention. A slow burn, which would exhaust it in weeks, deserves a ticket. Alerting this way reduces false alarms from brief blips while still catching real, sustained problems quickly.

Simple Analogy

Think of a monthly phone data allowance. If you used half of it in the first two days, you would worry immediately even though you have not yet run out. If you are slightly above the daily average, you might just keep an eye on it. Burn rate alerts apply the same common sense to reliability.

!
Common Mistake

Creating alerts on every available metric produces constant noise, and people learn to ignore the pager. Alert on a small number of things that mean users are suffering or soon will be, and leave the rest as charts for investigation.

24Tuning Levers and Their Trade-offs

Every improvement costs something somewhere else. Wise tuning means understanding both sides before changing anything.

LeverPotential benefitTrade-off or risk
Faster, dedicated storage for the databaseLower write latency, fewer leader changesHigher cost; requires planned migration
Separate database for eventsKeeps high-churn data from crowding the main databaseExtra component to run and monitor
Regular compaction and defragmentationSmaller, faster databaseDefragmentation briefly blocks a member, so it needs scheduling
Adjusting fairness shares and categoriesProtects critical traffic, contains noisy clientsMisconfiguration can starve legitimate clients
Raising interface server resourcesMore headroom for bursts and larger cachesCost, and may only mask inefficient clients
Adding interface server replicasMore request capacity and resilienceMore connections to the database and uneven load if not balanced well
Narrowing webhook scope and timeoutsLower request latency, fewer cascading failuresPossible policy gaps if scope is too narrow
Raising client rate limits for a specific controllerFaster reconciliationMore load on the server and database
Limiting scheduler node searchFaster placement in very large clustersSlightly less optimal placement
Shortening event retention and cleaning old objectsSmaller database, fewer objects to cacheLess history available for debugging
Splitting into multiple clustersSmaller blast radius, easier scaling per clusterMore operational overhead and cross-cluster complexity

A rule of thumb for choosing levers

Prefer changes that reduce load over changes that increase capacity, and prefer reversible changes over irreversible ones. Removing a wasteful client, narrowing a webhook, or cleaning up old objects reduces demand permanently and usually costs nothing. Adding capacity helps only until demand catches up, and it costs money every month. When you must add capacity, do it after you have removed the waste, so you are not paying to serve work nobody needed.

i
Practical Advice

Change one thing at a time and record the date, the change, and the observed result. When improvements stack up from many small changes made together, nobody can tell which ones helped and which ones quietly caused new problems.

25Anti-patterns: Habits That Slowly Strangle a Control Plane

Most control plane crises are not sudden surprises. They are the final result of habits that were allowed to continue.

ANTI-PATTERN-02 Avoid
Problem

Operating the control plane without objectives, relying on the feeling that things seem fine.

Why It’s Harmful

Gradual degradation goes unnoticed until it becomes an outage, and there is no shared definition of acceptable performance when people disagree.

Correct Approach

Define a few measurable objectives, track them continuously, and review them regularly with the teams who depend on the cluster.

ANTI-PATTERN-03 Avoid
Problem

Letting the database share a disk and machine with other busy programs, or placing it on slow shared storage.

Why It’s Harmful

Disk latency is the strongest influence on write speed. Contention produces unpredictable stalls, missed heartbeats, and unnecessary leader changes.

Correct Approach

Give the database fast, dedicated storage and a stable, low-latency network between members, and monitor its disk metrics closely.

ANTI-PATTERN-04 Avoid
Problem

Installing webhooks, operators, and custom resource types without measuring their cost or reviewing them later.

Why It’s Harmful

Each adds latency, memory, and watch traffic. Together they can turn a fast control plane into a slow one with no single culprit.

Correct Approach

Evaluate the cost of each extension before adopting it, scope it narrowly, and review the list periodically, removing what is no longer needed.

ANTI-PATTERN-05 Avoid
Problem

Treating the control plane as a free, unlimited service for scripts, dashboards, and pipelines.

Why It’s Harmful

Uncontrolled clients poll aggressively and request huge results, competing with critical components for the same shared capacity.

Correct Approach

Use fairness categories to isolate non-critical clients, give teams guidance on efficient client behavior, and review the heaviest callers regularly.

ANTI-PATTERN-06 Avoid
Problem

Fixing slowness only by upgrading machine sizes, never investigating the cause.

Why It’s Harmful

The underlying problem remains and returns as soon as demand grows to fill the new capacity, while costs keep rising.

Correct Approach

Profile first, remove waste, and add capacity only for demand that is genuine and verified.

ANTI-PATTERN-07 Avoid
Problem

Never testing the effect of upgrades, new features, or new tools on control plane performance before production.

Why It’s Harmful

Defaults change between versions and new components alter load patterns. Surprises appear in production at the worst possible time.

Correct Approach

Run a representative load test in a staging environment for significant changes, and compare results with a recorded baseline.

26Real-World Scenarios

These illustrative stories show how the ideas above combine in practice. Each one follows the same path: symptom, investigation, cause, and fix.

Scenario one: the deployment pipeline that slowed everything

A company noticed that deployments took minutes at certain hours. Charts showed rising latency for list requests at the interface server and memory growth followed by restarts. Audit records revealed that a monitoring dashboard was listing all pods in the cluster every few seconds, on behalf of many open browser tabs. Switching the dashboard to a watch-based approach with filtering and lowering its fairness priority removed the spikes without any hardware change.

Scenario two: the cluster that turned read-only

A team found that every create and update failed one morning. The database had reached its size quota. Investigation showed that a batch system had created millions of finished job objects and never cleaned them up. After clearing old objects, compacting, and defragmenting, writes resumed. Afterward the team added automatic cleanup and an early-warning alert at a conservative fraction of the quota.

Scenario three: slow writes with a calm interface server

Write latency crept up over weeks while reads stayed fast. Database disk sync times showed occasional spikes, and leader changes were more frequent than before. The database volumes turned out to share input and output capacity with a logging agent. Moving the database to dedicated local drives stabilized sync times and ended the leader flapping.

Scenario four: the operator that argued with itself

An operator for a data service updated its own objects on every reconciliation, which triggered another reconciliation, in an endless loop. The interface server saw thousands of updates per second for objects that had not meaningfully changed. Fixing the operator to skip no-op updates cut write traffic dramatically and lowered database growth.

Scenario five: the webhook that stalled every pod

Pod creation began taking several seconds. Admission step durations showed one policy webhook responsible for nearly all of the delay, because its backing service had been scaled down and requests waited for a timeout. Restoring replicas, shortening the timeout, and narrowing the webhook’s scope fixed the symptom and prevented a repeat.

Scenario six: slow rollouts that were nobody’s server problem

A large rollout crawled while all server charts looked calm. Controller queue wait times were high, and a log message revealed waiting on the controller’s own client-side rate limiter. After confirming the server had spare capacity, the team raised that one controller’s limits carefully, and rollouts accelerated.

i
Good to Know

In every story above, the cause was found by following data from a broad symptom to a specific source, and the best fix removed or reduced demand instead of adding raw capacity. That pattern repeats across almost every real control plane investigation.

27A Maturity Path for Control Plane Performance Work

You do not need advanced tooling on day one. Progress in stages, and gain value at each step.

StageFocusTypical activitiesSuccess looks like
Stage one: ObserveBasic visibilityCollect metrics from every component, build a single overview dashboard, learn what normal looks likeAnyone on call can say whether the control plane is healthy within a minute
Stage two: ObjectivesMeaningful targetsDefine latency and availability objectives, add symptom alerts and early warnings, set up audit analysisAlerts are rare, trusted, and tied to real user impact
Stage three: InvestigateFast diagnosisEnable sampled tracing, practice capturing profiles, build a field guide and runbooksTypical incidents are diagnosed in minutes instead of hours
Stage four: PreventStaying aheadRegular load tests, performance checks for upgrades, guardrails for noisy clients, capacity forecastsCapacity is added before demand arrives, and upgrades cause no surprises

Numbers worth reviewing every month

Experience

Objective compliance

The share of time the control plane met its latency and availability targets.

Growth

Object and node counts

How quickly the cluster is growing, which predicts when limits will be reached.

Storage

Database size trend

Growth rate against quota, and the largest object types by size.

Load

Heaviest callers

The clients responsible for the most requests and the most expensive requests.

Hygiene

Extension inventory

Counts of webhooks, custom types, and aggregated services, with owners and measured cost.

Response

Time to diagnose

How long incidents take to understand, which shows whether your tooling and runbooks are improving.

i
Practical Advice

Hold a short monthly review with platform engineers and a few application owners. The platform team knows what the control plane can bear; the application teams know what they plan to launch. Sharing both views lets you prepare for upcoming load instead of reacting to it.

28Upgrades, Change Management, and Performance Regressions

The most common moment for performance to change is the moment you change something.

Why changes cause regressions

Every new Kubernetes release brings improvements, but it can also change defaults, add features that generate extra requests, or alter caching behavior. Third-party components that work well on one version can behave differently on the next. Even small configuration edits, such as changing a webhook’s scope or a controller’s number of workers, shift load patterns. A disciplined approach treats performance as a property that can regress, like any other quality of the system.

1

Record a baseline

Before the change, capture the key latency percentiles, request rates, queue depths, and resource usage for a representative period.

2

Read the release notes with performance in mind

Look for changed defaults, new feature gates, deprecations, and notes on caching, fairness, and storage behavior.

3

Test in a mirror environment

Apply the change to a staging cluster with realistic load, and compare against the baseline. Investigate any difference larger than your normal variation.

4

Roll out gradually and watch

Change one control plane member at a time, wait for latency to settle, and keep a clear rollback plan ready.

5

Compare and document

After the change, compare against the baseline again and record what you learned, so the next change starts from better knowledge.

!
Common Mistake

Making several unrelated changes in one maintenance window, such as a version upgrade, a storage migration, and a new webhook. If performance changes afterward, nobody can tell which change caused it. Separate changes in time so each can be judged on its own.

29A Worked Investigation from Start to Finish

Follow one realistic investigation to see the method in action. The details are illustrative, but the reasoning is typical.

The report

On a Monday morning, several teams complain that their deployments take far longer than usual. Some report that command-line tools pause for many seconds before showing results. Nothing is down, applications are running, and the on-call engineer sees no alarms. The engineer begins by stating the symptom precisely: write requests and list requests at the interface server are slow, starting sometime over the weekend.

Locating the slow stage

The engineer opens the control plane dashboard. The top row shows the write latency objective violated since Saturday evening. In the second row, write latency at the interface server is high, but the database’s own request durations look normal, and its disk sync times are healthy. That rules out storage. Admission step durations show one webhook taking much longer than before, but not enough to explain everything. In-flight requests are high and the fairness queue for general clients shows long waits and a growing count of rejected requests.

Finding the source

Audit records for the weekend reveal that a new reporting job, started Saturday, makes frequent cluster-wide list requests for pods and configuration objects, with no filters. Its request count is not extreme, but its response sizes are enormous. Memory use of the interface server instances has climbed in step. The job belongs to a data analytics team that did not realize its tool lists everything every thirty seconds.

sequenceDiagram
  participant J as Reporting job
  participant A as API server
  participant E as etcd
  participant O as Other clients
  J->>A: List all pods and configuration objects, no filters
  A->>E: Fetch large result set
  E-->>A: Very large response
  A-->>J: Build and send huge reply
  O->>A: Normal requests
  Note over A: Memory and processor busy with huge replies
  A-->>O: Slow responses and rejections
        
FIG 11 — How one heavy client slows everyone else

Confirming and fixing

The engineer asks the analytics team to pause the job, and within minutes list latency falls, memory stabilizes, and rejections stop. That confirms the hypothesis. The permanent fix has three parts. The analytics team changes the tool to watch for changes and filter by label, instead of listing everything. The platform team assigns that tool’s service account to a lower-priority fairness category, so future misbehavior is contained. And the team adds an alert on unusually large response sizes and a short guide for teams on efficient use of the cluster interface.

1

What went well

The dashboard’s top-down layout led quickly from objective violation to the interface server, and audit records identified the caller without guesswork.

2

What was missing

No alert existed for large response sizes, and no fairness category protected critical traffic from a new, unvetted client.

3

What changed afterward

A new alert, a containment category, a client guideline, and a short onboarding check for any new tool that talks to the cluster.

30A Plain-English Glossary

Keep these short definitions nearby while reading dashboards, audit records, and incident reports.

Term

Control plane

The group of components that stores the cluster’s desired state, makes decisions, and drives reality toward the plan.

Term

API server

The central front door through which every component and user reads and changes cluster state.

Term

etcd

The consistent, distributed database that durably stores all cluster objects.

Term

Latency

The time one request takes from being sent to being answered.

Term

Percentile

A value below which a given share of measurements fall. The ninety-ninth percentile shows the slow tail that averages hide.

Term

Saturation

How close a resource is to its limit, such as a nearly full queue or a very busy disk.

Term

SLI and SLO

A measured indicator of experience, and the target value you promise to meet for it.

Term

Watch

A long-lived request that streams changes to a client as they happen.

Term

Watch cache

The recent copy of objects the API server keeps in memory to answer many reads without touching the database.

Term

Informer

A client helper that lists once, watches for changes, and keeps a local copy to avoid repeated heavy requests.

Term

Admission webhook

An external program the API server calls during a request to inspect, modify, or reject an object.

Term

Priority and fairness

The mechanism that sorts requests into priority levels and queues them fairly so no single client can starve others.

Term

Compaction

Discarding old versions of data in etcd so space can be reused.

Term

Defragmentation

Returning reclaimed space to the disk so the etcd data file actually shrinks.

Term

Work queue

The list of items a controller still needs to process, whose depth and wait time reveal its health.

Term

Flame graph

A picture of profiling samples where wider bars represent functions that consumed more time or memory.

i
Practical Advice

Share this glossary with application teams who use your cluster. When everyone means the same thing by latency, saturation, and objectives, incident conversations become shorter and decisions become faster.

31Frequently Asked Questions

Quick answers to the questions beginners ask most often.

Q1How do I know whether my control plane is slow or my application is slow?

Compare request latency at the interface server with the symptoms. If creating, listing, or updating objects is slow, suspect the control plane. If objects are created quickly but your application responds slowly to users, the control plane is probably not involved, because running applications do not depend on it for each request.

Q2Do applications stop working if the control plane is slow or down?

Existing workloads generally keep running, since node agents and networking continue to function with the last known state. What stops is the ability to change things: deploy, scale, replace failed pods, or update configuration. This is why control plane trouble can go unnoticed until you try to make a change.

Q3Which metric should I watch first?

Start with the ninety-ninth percentile latency of requests at the interface server, split by action. It reflects what clients feel and points you toward either the front door or the database for deeper investigation.

Q4Why does the average latency look fine while users complain?

Averages hide the slow tail. A small share of very slow requests barely moves the average but causes timeouts and retries that users notice. Always look at high percentiles.

Q5Is it safe to run profiling on a production control plane?

Gentle, short profiling by authorized administrators is commonly done in production, but each capture adds some load. Avoid taking many large profiles at once from a component already under stress, restrict access to the endpoints, and prefer sampled or continuous low-rate profiling where possible.

Q6What is the most common cause of slow writes?

Slow storage under the database is the most frequent cause, followed by slow admission webhooks and oversized or constantly updated objects. Checking disk sync times and webhook durations quickly separates these possibilities.

Q7What causes the database to grow so large?

Typically a few object types: high-volume events, large configuration objects, leftover finished jobs, or custom resources written by operators. Counting objects and total size by type finds the main contributors, and cleanup plus compaction and defragmentation reclaim the space.

Q8Should I just buy bigger control plane machines?

Only after you understand the load. Larger machines can help genuine growth, but if a wasteful client or slow webhook is the cause, extra capacity just delays the problem while raising cost. Profile first, remove waste, then add capacity for demand that remains.

Q9What is the difference between monitoring and profiling?

Monitoring watches known numbers over time and alerts when they cross thresholds. Profiling digs into why a number behaves as it does, using audit records, traces, and code-level samples. Monitoring raises the question; profiling answers it.

Q10Can I profile a managed control plane?

Partly. You can usually collect the metrics and audit logs the provider exposes and fully profile your own clients, webhooks, and workloads, but you typically cannot capture code-level profiles of the provider’s components. Bring measured evidence to the provider when deeper investigation is needed.

Q11How often should I run load tests?

Before significant changes such as upgrades or new platform components, before major launches that will change load, and periodically as the cluster grows. Treat the results as a recorded baseline for later comparison.

Q12Why do some controllers seem slow even when the server is idle?

They may be waiting on their own client-side rate limits, or their work queues may be backed up by expensive processing. Compare client-side wait times and queue metrics with server latency to tell these cases apart.

Q13How many clusters should I run?

There is no single answer. Fewer, larger clusters share resources efficiently but have larger blast radius and scaling limits; several moderate clusters limit the blast radius at the cost of more management effort. Choose based on your scale, isolation needs, and operational capacity.

32Summary and Key Takeaways

The Kubernetes control plane is a small group of cooperating components organized around one hub, the interface server, backed by one durable store, etcd. Because everything flows through those two places, almost every performance problem eventually appears there, even when the true cause lives in a heavy client, a slow webhook, a slow disk, or a controller waiting on its own limits. Profiling means measuring where time and resources go, moving from cheap broad signals to expensive precise ones, and following the evidence to the source instead of guessing. Used together with clear objectives, fair queuing, careful extensions, regular testing, and disciplined change management, profiling turns the control plane from an invisible risk into a well-understood, predictable part of your platform.

Key Takeaways

  • Profile before you spend — measure where time goes first; most control plane slowness comes from a specific client, extension, or disk, not from a lack of raw capacity.
  • Think in percentiles and objectives — judge health by the high-percentile latency against defined targets, because averages hide the slow tail that users actually feel.
  • The API server and etcd are the center — nearly every symptom shows up at these two places, so learn their vital signs: request duration by action, fairness queues, disk sync time, database size, and leader changes.
  • Heavy requests cost far more than they count — unfiltered lists, constant polling, oversized objects, and bypassed caches are the classic causes of overload; use list-then-watch, filtering, and pagination.
  • Extensions are never free — webhooks, custom resources, operators, and aggregated APIs each add latency and load, so scope them narrowly, set sensible timeouts, and review them regularly.
  • Work from cheap signals to expensive ones — metrics locate the problem, audit records and traces identify the caller and stage, and code-level profiles explain the internals only when truly needed.
  • Prevent surprises — load test before big changes, record baselines, change one thing at a time, alert on objectives and early warnings, and keep a field guide and runbooks for the next incident.