etcd Performance Tuning in Kubernetes
Every object in your cluster lives in one small database, and the speed of that database sets the speed of everything else. A complete, step-by-step guide to understanding, measuring, and tuning etcd so your control plane stays fast and calm under pressure.
Imagine a huge library where every book, every borrowing record, and every reservation is written in a single master notebook. Before anyone can borrow a book, a librarian must write the entry in the notebook and make sure three other librarians have written the same entry in their own copies. If the pen is slow, or the desk is wobbly, or one librarian is far away in another building, the whole library slows down. No matter how many clever assistants you hire, the master notebook decides the speed of the building.
Kubernetes has exactly such a notebook. It is called etcd, and it stores every Pod, every Deployment, every Secret, every node, and every setting in your cluster. When etcd is healthy, nobody thinks about it. When it is slow, everything feels broken at once: commands time out, Pods are not created, controllers fall behind, and nodes appear to go missing even though they are fine. Tuning etcd is therefore one of the highest-value skills for anyone who runs Kubernetes seriously.
In this guide you will learn what etcd is, how a write travels through it, why the disk matters more than anything else, which settings are worth changing, how to keep the database small, how to measure health, how to reduce the load that Kubernetes itself puts on etcd, and how to recover when things go wrong. Every new term is explained the first time it appears, so you can read from top to bottom with no earlier knowledge.
1The Big Idea: What Is etcd and Why Does Tuning It Matter?
etcd is a small, strongly consistent database that remembers the truth about your cluster.
etcd is a distributed key-value store. A key-value store is the simplest kind of database: you save a value under a name, called a key, and later you ask for it by that name. Think of a coat check where you hand over a coat and receive a ticket number. The word “distributed” means that etcd runs as a group of several programs on several machines, and all of them keep identical copies of the data. If one machine dies, the others still have everything.
The most important word to remember is consistent. When etcd says a write succeeded, every healthy member will agree on that fact, and no later read will show older data. Kubernetes depends on this promise because many controllers make decisions from the data they read. If two controllers saw different versions of the truth, they could create duplicates or delete the wrong things.
Think of a group of friends planning a trip who each keep a copy of the plan. Before anyone writes a change in their copy, a majority of the friends must say “yes, I agree to write that.” This takes a few moments, but it guarantees that the copies never disagree. etcd works the same way, and the price of that guarantee is that every write must wait for a majority of friends to be ready.
Why tuning is not optional at scale
A small test cluster with a handful of nodes will run happily on almost any etcd setup. The trouble appears as the cluster grows. More nodes mean more heartbeats. More Pods mean more status updates. More controllers mean more watches. Each of these becomes a write or a read in etcd. When the number of requests rises faster than etcd can answer them, delays pile up and the control plane starts to wobble.
etcd is not fast because it is clever. It is fast when its disk is fast, its network is steady, its data is small, and its clients behave politely. Almost all tuning is about protecting those four things.
2Why etcd Is the Heart of the Kubernetes Control Plane
One database, one gatekeeper, and a lot of people who depend on both.
In a Kubernetes cluster, only one component is allowed to talk to etcd: the kube-apiserver. Every other part of the system, including the scheduler, the controller manager, the kubelets on each node, and your own kubectl commands, talks to the API server instead. The API server checks who you are, validates the request, and then reads from or writes to etcd on your behalf.
This design has an important effect. The speed of every operation in Kubernetes is at most the speed of the API server, and the speed of the API server is at most the speed of etcd for anything that has to be stored. When you create a Deployment, the API server writes one object to etcd. The Deployment controller notices and writes a ReplicaSet. The ReplicaSet controller writes Pods. The scheduler writes a binding for each Pod. The kubelet writes Pod status. A single “scale up” command can therefore cause dozens or hundreds of etcd writes within seconds.
A busy restaurant has many cooks, waiters, and cashiers, but only one till drawer where every payment is recorded. If the drawer sticks, the cooks can still cook, but nobody can finish an order. etcd is the till drawer of the cluster.
What happens when etcd is slow
Slow etcd does not usually look like an etcd problem. It looks like many other problems. Kubectl commands hang. Deployments roll out slowly. Pods stay in Pending even though nodes are free. Nodes flip between Ready and NotReady because their heartbeats cannot be saved in time. Controllers log errors about timeouts. People then waste hours investigating nodes and networks, when the real cause was a slow disk under one etcd member.
When many unrelated symptoms appear at the same time across the whole cluster, suspect the shared parts first: etcd and the API server. A problem that affects only one node or one application is rarely etcd.
The etcd project began at CoreOS and is now a graduated project of the Cloud Native Computing Foundation. It was chosen for Kubernetes because it offers strong consistency and a simple watch feature, which lets clients subscribe to changes instead of repeatedly asking. Managed services such as Amazon EKS, Google GKE, and Azure AKS run and tune etcd for you, so their customers feel its effects mainly through the limits and behavior of the API.
3Core Vocabulary for etcd Tuning
Twelve short words that you will meet in every etcd conversation.
Member
One etcd server in the cluster. A typical Kubernetes setup has three or five members.
Leader
The one member that receives writes first and tells the others to copy them. The others are followers.
Quorum
A majority of members. With three members, quorum is two. Writes need quorum to succeed.
Raft
The agreement method etcd uses so that all members hold the same ordered list of changes.
WAL
Write-ahead log. A file where each change is written and forced to disk before anything else happens.
fsync
The operating system call that forces data from memory onto the physical disk. Its speed is the heart of etcd performance.
Revision
A counter that goes up with every change. Each change creates a new version, and old versions stay until compaction.
Compaction
Throwing away old versions that nobody needs, so the history does not grow forever.
Defragmentation
Packing the database file tightly and giving freed space back to the disk after compaction.
Quota
The maximum database size. When it is reached, etcd refuses writes until you make space.
Heartbeat and election timeout
How often the leader says “I am alive,” and how long followers wait before choosing a new leader.
Snapshot
A complete copy of the database at one moment, used for backups and recovery.
Latency versus throughput
Two measurements appear again and again. Latency is how long one request takes from start to finish. Throughput is how many requests are handled per second. They are related but different. A road can have a high speed limit (low latency) and still be narrow (low throughput). etcd cares mostly about latency, because each write must wait for disks on several machines. Raising latency even a little can drop throughput a lot.
A toll booth takes ten seconds per car. The latency for one car is ten seconds. If there is only one booth, throughput is six cars a minute. To improve throughput you either make each booth faster or you add booths. For etcd, you cannot easily add booths, since every write must go through the single leader, so making each step faster is the main road to improvement.
4Architecture: Where etcd Sits and How It Is Deployed
A small group of members behind a group of API servers.
flowchart TB
KC["kubectl and controllers"] --> LB["Load balancer"]
LB --> A1["kube-apiserver 1"]
LB --> A2["kube-apiserver 2"]
LB --> A3["kube-apiserver 3"]
A1 --> E1[("etcd member 1 - leader")]
A2 --> E2[("etcd member 2")]
A3 --> E3[("etcd member 3")]
E1 |"Raft peer traffic"| E2
E2 |"Raft peer traffic"| E3
E1 |"Raft peer traffic"| E3
A1 -.->|"events only"| EV[("separate etcd for events")]
Look at Figure 1 from the top. People and controllers send requests to a load balancer, which hands them to one of several API servers. Each API server speaks to etcd. The etcd members continuously talk to each other to agree on every change. The dotted line at the bottom shows an optional trick that you will study later: sending the very noisy Event objects to their own etcd cluster.
Two ways to deploy etcd
| Topology | What it means | Good for | Watch out for |
|---|---|---|---|
| Stacked | etcd runs on the same machines as the API server and other control plane parts | Simple setups and small to medium clusters | Control plane programs compete with etcd for disk and CPU |
| External | etcd runs on its own dedicated machines | Large clusters and strict performance needs | More machines to run, secure, and back up |
A stacked setup is like keeping the master notebook on the same busy front desk as the telephone, the visitors, and the mail. It is convenient, but noise on the desk can disturb the writing. An external setup puts the notebook in its own quiet room.
2379
The client port. Only API servers should reach it.
2380
The peer port. Members use it to talk to each other, and nothing else should reach it.
Tools such as kubeadm support both topologies. Many teams start stacked and move etcd to dedicated machines once the cluster grows large or the API gets slow, because separating etcd is one of the easiest ways to stop other programs from stealing its disk time.
5Inside a Write: Raft, Leaders, and Quorum
Follow one write from the API server to success, and you will see exactly where time is spent.
sequenceDiagram
participant C as kube-apiserver
participant L as Leader member
participant F1 as Follower 1
participant F2 as Follower 2
C->>L: Write request
L->>L: Append to WAL and fsync
L->>F1: Replicate log entry
L->>F2: Replicate log entry
F1->>F1: Append to WAL and fsync
F1-->>L: Acknowledge
Note over L: Majority reached so the entry is committed
L->>L: Apply to database
L-->>C: Success
The request arrives at the leader
If the API server contacted a follower, the follower forwards the request to the leader. Only the leader orders changes.
The leader writes to its own WAL
The change is appended to the write-ahead log and forced to the physical disk with an fsync. This step cannot be skipped, because it is what protects the data if the machine loses power.
The entry travels to the followers
The leader sends the entry across the network. The time this takes is the peer round trip time, and it depends on the distance and quality of the network.
Followers also write to their WAL
Each follower does its own fsync before saying yes. A slow disk on any follower slows the answers that arrive.
A majority has confirmed
With three members, the leader plus one follower is enough. The entry is now committed, which means it can never be lost or reordered.
The change is applied and acknowledged
The leader applies the change to its database and tells the API server it succeeded. The followers apply it shortly after.
Imagine a head teacher who announces a new rule only after the rule is written in her own diary and at least half of the other teachers have written it down too. The waiting time is the diary writing speed plus the time for messages to travel between staff rooms. If one teacher has a slow pen, the head teacher may need to wait for a different teacher instead, as long as a majority is reached.
Why quorum shapes your cluster size
A cluster of three members needs two for quorum, so it survives one failure. A cluster of five needs three, so it survives two. A cluster of four also needs three, so it survives only one failure, the same as three members but with more cost. This is why even numbers are wasteful. It is also why adding many members does not make writes faster. More members mean more copies to update and more messages to send, so very large groups are slower, not faster.
Running etcd members in too many places or too many copies for safety usually lowers performance. Three members spread over three failure zones is the common choice, and five is used when the extra failure tolerance is worth the extra write cost.
6The Storage Engine: WAL, bbolt, Revisions, and Why Databases Grow
Understanding how data is stored on disk explains almost every size and space problem you will ever see.
flowchart LR
W["Write arrives"] --> WAL["WAL file with fsync"]
WAL --> RAFT["Raft commit by majority"]
RAFT --> MV["MVCC adds a new revision to the in-memory index"]
MV --> BB["bbolt database file with batched commits"]
BB --> CP["Compaction drops old revisions"]
CP --> DF["Defrag returns free space to the disk"]
Two places on disk
Each member keeps two main things on disk. The first is the write-ahead log, which records changes in order and is read again only if the member restarts. The second is the database file, which holds the current and past versions of every key. The database is built on a small embedded storage engine called bbolt, which stores data in fixed-size pages and is organized as a tree. Periodic snapshots let etcd trim old log files, so the log does not grow forever.
Every change creates a new version
etcd uses a design called MVCC, short for multi-version concurrency control. In plain words: when you change a value, etcd does not overwrite the old one. It adds a new version with a higher revision number and keeps the old version for a while. This is how watches work. A client can say “tell me everything that changed since revision 5000,” and etcd can replay the history. It is also why reads do not block writes.
Think of a shared document that saves every edit as a new version. You can always see what it looked like last Tuesday. That is helpful, but if people edit every second, the version history becomes enormous. Compaction is the librarian who says, “we only need to keep the last few minutes of history.”
Compaction and defragmentation are different jobs
Compaction removes old revisions logically. After compaction, the old data is gone from etcd’s view, but the database file does not shrink. The pages that held the old data are simply marked as free inside the file. Defragmentation is what actually rewrites the file tightly and hands the unused space back to the operating system. Without compaction, the data keeps growing. Without defragmentation, the file stays large even though much of it is empty.
| Operation | What it does | Does the file shrink? | Cost while running |
|---|---|---|---|
| Write | Adds a new revision | No, it grows | Normal |
| Compaction | Forgets old revisions | No, space is only marked free | Light |
| Defragmentation | Rewrites the file compactly | Yes | Heavy: that member pauses reads and writes |
| Snapshot | Copies the database for backup | No | Moderate disk and network use |
The space quota: a safety fuse
etcd has a limit on the database file size, called the backend quota. By default it is two gibibytes, and the documentation advises not to go far beyond eight. When the file reaches the limit, etcd raises an alarm called NOSPACE and refuses further writes. Reads still work, so the cluster looks alive but frozen: nothing new can be created or changed. This is a classic outage, and it is entirely preventable by watching size and keeping compaction and defragmentation healthy.
The kube-apiserver asks etcd to compact on a regular schedule, every five minutes by default. That is why a typical Kubernetes cluster does not need a separate compaction setting. What most clusters lack is a safe, regular defragmentation routine.
7The Disk: The Single Most Important Tuning Lever
If you only fix one thing, fix the disk.
As you saw in Chapter 5, every write needs an fsync on the leader and on at least one follower. If the fsync takes fifty milliseconds, no amount of CPU or clever settings can make a write complete faster than that. The etcd documentation gives a clear target: the 99th percentile of the WAL fsync time should stay below ten milliseconds, and the 99th percentile of the backend commit time should stay below twenty-five milliseconds. A 99th percentile means “ninety-nine out of a hundred operations were faster than this,” so it shows the slow tail, which is what hurts users.
If a bank clerk must stamp every cheque with a stamp that dries for ten seconds before the next cheque, the line moves at one cheque per ten seconds, no matter how fast the clerk can write. The stamp drying is the fsync. A faster stamp helps more than a faster clerk.
Use local SSD or NVMe
Solid state drives, especially NVMe, give small and steady fsync times. Spinning disks and many network disks are too slow and too unpredictable for busy clusters.
Give etcd its own disk
Put the data directory on a dedicated device. Do not share it with container images, logs, or other databases that can burst and block it.
Pick steady performance
Choose disk types with guaranteed input and output rates. Burstable disks that run out of credits can suddenly become slow.
Network file systems
Shared file servers add network delay to every fsync and are a common cause of mysterious leader changes.
Give etcd I/O priority
On shared machines, raise etcd’s disk priority so that other processes cannot starve its fsync calls.
Use a simple file system
A well-supported local file system such as ext4 or XFS, mounted normally, is the standard choice.
Test the disk before you trust it
Do not guess. A common practice is to run a short test with a disk benchmarking tool such as fio, configured to mimic etcd by writing small blocks and calling fdatasync after each one. The result you want to see is a 99th percentile sync time under ten milliseconds. etcd also ships with a built-in performance check command that sends a standard load and reports pass or fail. Run the test on every new machine type before you put a cluster on it, and again after any storage change.
Cloud disks often advertise high throughput but have much higher latency per operation than local disks, because every write crosses a network. Many teams are surprised to find that a small local NVMe drive beats a huge network volume for etcd. Always check the latency of small synced writes, not the headline megabytes per second.
What a bad disk looks like in the logs
When a disk is too slow, etcd tells you. The logs fill with warnings such as “apply request took too long,” which appears when applying a request takes more than about a hundred milliseconds, and warnings that the leader failed to send out a heartbeat on time. Metrics show the WAL fsync histogram shifting to the right. If you see these, check the disk first before touching any setting.
Production example: scaling to thousands of nodes
OpenAI has publicly described in an engineering write-up how, while scaling a Kubernetes cluster to thousands of nodes, they saw etcd latency problems tied to disk performance, and fixed them by moving etcd to local fast storage and by separating the very busy Event data into its own etcd cluster. The lesson matches this chapter: fast local disks, and less noise inside the main store.
8Network and Raft Timing: Heartbeat and Election Timeout
The members must hear each other quickly and reliably, or they start electing new leaders for no reason.
The leader sends a short message to every follower at regular intervals to say, “I am still here.” This is the heartbeat interval. If a follower hears nothing for a period called the election timeout, it assumes the leader is dead and starts an election to choose a new one. The defaults are a heartbeat every hundred milliseconds and an election timeout of one thousand milliseconds, which suit members that are close together in one region.
A classroom monitor waves to the teacher every minute. If the teacher stops waving for ten minutes, the class assumes the teacher has left and chooses a new leader. If the teacher is only slow, not gone, the class makes a mistake and causes confusion. Good timing settings make false alarms rare, while still noticing a real absence quickly.
Rules of thumb from the etcd documentation
| Setting | Guidance | Why |
|---|---|---|
| Heartbeat interval | Roughly the largest round trip time between members | Followers should always receive a heartbeat well before they get worried |
| Election timeout | At least ten times the round trip time, and at least five times the heartbeat interval | Short hiccups should not cause an election |
| Both too small | Frequent false elections | Each election pauses writes |
| Both too large | Slow detection of a real failure | The cluster stays frozen longer when a leader truly dies |
Why leader changes hurt
While an election is running, no writes can be accepted. A single election lasts about the length of the election timeout. If members keep losing contact because of a congested network or a stalled disk, they may elect again and again, and the cluster spends more time choosing leaders than doing work. The metric that counts leader changes should be almost flat. A leader change every few minutes is a serious warning sign, and it is almost never fixed by simply raising the timeouts, because the true cause is usually a slow disk or a busy CPU.
Raising the election timeout hides the symptom but leaves the cause. If the timeouts are made very long to stop elections, the cluster also takes very long to recover from a real leader failure. Fix the slow disk or the busy machine first, and only adjust the timing for genuine network distance.
Where to place the members
Members should be on a fast, low-latency network. Putting the three members in three availability zones of one cloud region is the usual balance: the zones are separate buildings, so one fire does not take everything, yet the round trip time is only a few milliseconds. Spreading members across regions, often hundreds of milliseconds apart, makes every write wait for that long, and is rarely a good idea for Kubernetes. If you need multi-region safety, use backups and a recovery plan rather than a stretched cluster.
Production example: multi-zone managed control planes
Managed offerings such as Amazon EKS spread their etcd members across several availability zones of one region. Customers gain protection from a single zone failing, and the latency between zones stays low enough that the default timing works well.
9CPU, Memory, and Operating System Tuning
etcd is not hungry for CPU, but it hates being starved.
For small and medium clusters, etcd needs only a few CPU cores. The important point is not raw power but steadiness. If another program on the machine grabs all the CPU for a moment, etcd cannot send its heartbeat on time, and followers may decide the leader has died. The etcd hardware guidance ranges from around two cores and eight gigabytes of memory for small clusters up to sixteen or more cores and sixty-four gigabytes for very large ones, with disk speed rising along with it.
Avoid CPU starvation
On stacked control planes, give etcd guaranteed CPU shares or run it on dedicated machines. Heartbeats late by even a fraction of a second cause trouble.
Use the performance governor
On physical machines, set the CPU frequency policy to performance, so cores do not slow down while idle and then react late.
Leave room for the page cache
etcd memory use is driven by the database size and the number of watchers. The operating system’s file cache also helps. Plan memory above the database size.
Disable swap
If etcd memory is pushed to disk, every access becomes a slow disk read, and timing guarantees disappear.
Raise file descriptor limits
Each client connection uses a file descriptor. Low limits cause strange connection failures under load.
Protect peer traffic
On busy machines, give the peer port higher network priority so that bulk transfers such as backups cannot delay heartbeats.
A conductor must beat time exactly, every time. If the conductor is distracted by someone asking for a favor, the whole orchestra falls out of rhythm. Giving etcd steady CPU is like telling everyone else in the room to leave the conductor alone.
Memory and the watch load
A watch is a long-lived connection where a client asks to be told about changes. In Kubernetes, the API server keeps its own cache and opens a small number of watches to etcd, then shares those updates with many clients. This design protects etcd from thousands of separate watchers. Still, a very large number of resource types or poorly written custom controllers can increase the watch load and the memory used per watcher.
Operators of large clusters often run etcd on dedicated machines with local NVMe storage, plenty of memory, and a small set of other programs. Their reasoning is simple: etcd needs predictable speed, and nothing helps predictability more than being alone on the machine.
10Cluster Sizing and Topology Choices
How many members, where they live, and when to split the data across clusters.
| Members | Quorum | Failures survived | When to choose it |
|---|---|---|---|
| 1 | 1 | 0 | Local testing only, never production |
| 3 | 2 | 1 | The standard production choice |
| 5 | 3 | 2 | When higher safety is worth slightly slower writes |
| 7 | 4 | 3 | Rare, with a noticeable write cost |
| Even numbers | Same as one fewer | No gain | Avoid, as they add cost without safety |
Separate etcd for Events
Kubernetes creates an Event object whenever something notable happens, such as a Pod being scheduled or an image being pulled. Events are numerous, short-lived, and not critical to the cluster’s survival. By default they live in the same etcd as everything else, with a lifetime of one hour. In a large cluster, they can account for a big share of writes. A well-known tuning step is to configure the API server to send Events to a different etcd cluster. This keeps the heavy traffic away from the important data, so a flood of Events cannot slow down Deployment updates.
A newsroom keeps important legal records in a locked cabinet, and quick sticky notes in a bin. If both go into the same cabinet, the cabinet fills with sticky notes and the legal files become hard to find. Giving the sticky notes their own bin is simple and effective.
Learners: adding members safely
Adding a new member to a live cluster is risky if it is far behind, because it can slow down the quorum. etcd supports a learner role: a new member first joins as a non-voting learner, catches up with all the data, and is promoted to a full voting member only once it is ready. Using learners makes replacement and growth much safer. Always change membership one member at a time.
When one etcd is not enough
A single etcd cluster has natural limits on how much it can write per second and how large its database should be. The Kubernetes project documents clusters of up to about five thousand nodes as the supported scale. Beyond that, teams either split a workload across many smaller clusters, which is the most common and safest answer, or they move specific hot resources such as Events to their own etcd. A few very large operators have gone further and replaced etcd with other storage systems underneath the API server.
Production example: replacing etcd at extreme scale
Google has publicly described running its very largest Google Kubernetes Engine clusters on a storage layer based on its Spanner database instead of etcd, which shows that for extreme sizes the single-etcd design becomes the limit. For nearly every other organization, tuning etcd and splitting workloads across clusters is the practical path.
11Keeping the Database Small: Quota, Compaction, and Defragmentation
A small database is a fast database. Here is the routine that keeps it that way.
A big database slows etcd in several ways. Reads that scan many keys take longer. Snapshots and restores take longer. Followers that fall behind take longer to catch up. Starting a member takes longer. And as the file approaches the quota, the risk of an outage grows. The goal is therefore to keep the file comfortably below the quota, with plenty of safety room.
Two numbers to watch
etcd reports two sizes. The first is the total size of the database file on disk. The second is the size in use, which is how much of the file actually holds live data. When the total is much bigger than the size in use, the file is full of empty pages, and defragmentation will recover that space. When both are large, the problem is real data, and no cleanup will help. You must reduce what is stored.
flowchart TD
S["Check total size versus size in use"] --> Q{"More than half of the file is wasted?"}
Q -->|"No"| N["Do nothing"]
Q -->|"Yes"| C["Confirm compaction has run"]
C --> F["Defrag one follower"]
F --> H["Wait until it is healthy"]
H --> M{"More followers?"}
M -->|"Yes"| F
M -->|"No"| L["Defrag the leader last"]
L --> D["Clear the NOSPACE alarm if it was set"]
Measure first
Compare the total size with the size in use. If most of the file is live data, defragmentation will not help.
Make sure compaction runs
In Kubernetes the API server compacts regularly. Confirm that the revision history is actually being trimmed. If it is not, the file will keep growing.
Defragment one member at a time
Defragmentation blocks that member for the duration, which can be seconds on a small database and much longer on a big one. Because the others are untouched, the cluster stays available.
Do followers first, the leader last
A busy leader that pauses for defragmentation causes a leader change. Doing it last, and at a quiet time, limits disturbance.
Check health between steps
Make sure the member rejoined and caught up before moving to the next. Never defragment all members at once.
Clear the alarm if needed
If the NOSPACE alarm fired, writes stay refused even after space is freed, until the alarm is explicitly disarmed.
A suitcase full of clothes where you removed half the items still has the same size. The empty gaps inside are wasted. Compaction is taking items out. Defragmentation is repacking so the suitcase can be folded smaller. You would never repack all the suitcases of a travelling family at the same moment, or nobody could leave the house.
Raising the quota carefully
If the database legitimately needs more than two gibibytes, you can raise the quota setting. The etcd documentation suggests staying at or below about eight gibibytes. A bigger limit is not a free gift. It also raises recovery time, memory use, and snapshot size. Raising the quota should always come with an investigation into why the database is large.
Raising the quota to make a NOSPACE alarm go away, without finding the cause, simply delays the next outage. Look for which resource types hold the most objects and the most bytes, and fix the source.
12Reducing the Load Kubernetes Puts on etcd
The cheapest request is the one you never make. Most real tuning happens on the Kubernetes side.
It is tempting to treat etcd as a fixed machine and only tune the machine. But in practice, the biggest improvements come from sending fewer and smaller requests to it. The API server and the programs that talk to it decide the load, so changing their behavior often beats any etcd setting.
Use the API server’s cache
A list request that allows slightly older data can be answered from the API server’s memory. A request demanding the very latest data goes to etcd as a full quorum read, which is much more expensive.
Page large lists
Asking for tens of thousands of objects in one call forces etcd to read and the API server to hold them all. Request them in pages instead.
Separate Events
Send the noisy, short-lived Events to a dedicated etcd, as you saw in Chapter 10.
Lease-based node heartbeats
Nodes renew a tiny Lease object instead of rewriting the large node status every few seconds. This is already the default in modern versions and greatly cuts write volume.
Keep objects small
Huge ConfigMaps, Secrets, and custom resources inflate the database and slow every replication step. Keep large data in proper storage and store only references.
Clean up finished work
Completed Jobs and their Pods stay forever unless told otherwise. Set a time-to-live after finish, and clear old ReplicaSets with a small revision history limit.
Limit release history
Package managers such as Helm store every release version as a Secret. Cap the history, because each version can be large.
Fix noisy controllers
A buggy operator that rewrites the same object every second can generate more load than a thousand nodes. Find it through API server metrics.
Finding the heavy hitters
The API server publishes a metric showing how many objects of each resource type are stored. Sort it, and the biggest types stand out at once: often Events, Secrets, ConfigMaps, Pods in a busy batch cluster, or a custom resource created by some operator. Another set of metrics shows request rates per resource and per verb, such as list, watch, and update. Together they answer the question “who is using etcd, and for what?”
If your phone bill is high, you do not argue with the phone company. You look at which app used the most data and turn it off. The API server’s per-resource metrics are the usage breakdown.
Read types and why they matter
etcd offers two kinds of reads. A linearizable read, which is the default, guarantees the newest data by checking with the leader and the quorum. A serializable read is answered by one member from what it already knows, which is faster but might be slightly behind. The Kubernetes API server uses the first kind when a client asks for the latest data, and relies on its own cache for most other requests. Programs that bypass the cache with frequent full list calls can therefore create heavy quorum read load.
Production example: the cost of one chatty agent
Teams running large clusters have publicly reported cases where a single monitoring or logging agent, installed on every node, repeatedly listed all Pods or all nodes and put heavy load on the API server and etcd. The fix was not a bigger etcd, but changing the agent to use watches and cached lists. Such stories are common enough that many platform teams review every new cluster-wide agent for its API behavior before approving it.
13Request Limits and Fairness: Protecting etcd from Big Requests
A few guard rails keep one bad request from hurting everyone.
etcd has built-in limits on the size of a single request. The default maximum request size is about one and a half mebibytes. A request larger than that is rejected. This protects the cluster, because a single huge write would have to be copied to every member and could block the leader for a noticeable time. Raising this limit makes tail latency worse, so it is best left alone and the oversized objects reduced instead.
| Guard rail | Where it lives | What it protects |
|---|---|---|
| Maximum request size | etcd | Prevents giant single writes from stalling replication |
| Maximum operations per transaction | etcd | Limits how much work one multi-step request can demand |
| Backend quota | etcd | Stops the database from growing without limit |
| API Priority and Fairness | kube-apiserver | Sorts incoming requests into levels so one noisy client cannot starve important ones |
| Maximum in-flight requests | kube-apiserver | Caps the number of concurrent requests that reach etcd |
| Event time to live | kube-apiserver | Makes noisy Events expire after a set time, one hour by default |
A post office refuses parcels over a certain size, because one huge parcel would block the conveyor belt for everyone. It also has separate lines for express mail and regular mail, so a thousand ordinary letters cannot delay an urgent one. The size limit and the priority lines correspond to these guard rails.
API Priority and Fairness in plain words
The API server groups requests into priority levels and gives each level a share of the available capacity. Requests from system components such as the kubelet and the scheduler can be protected from requests from a user script that lists everything in a loop. If one flow of requests is too heavy, the API server queues or rejects it, instead of letting it flood etcd. Tuning these rules is a way of protecting etcd indirectly.
Treat “too many requests” responses from the API server as a gift, not a failure. They mean the protection is working. The right response is to fix the client that is too aggressive, not to raise the limits until the protection disappears.
14Measuring Health: Metrics, Logs, and Thresholds
You cannot tune what you cannot see. These are the numbers worth putting on a dashboard.
etcd publishes its metrics in a format that Prometheus can collect. The list is long, but a small set tells you almost everything. Group them into four questions: is the disk fast, is the network stable, is the database healthy, and are the clients behaving?
| Metric | What it tells you | Healthy target or warning sign |
|---|---|---|
etcd_disk_wal_fsync_duration_seconds | How long WAL syncs take | 99th percentile under 10 ms |
etcd_disk_backend_commit_duration_seconds | How long database commits take | 99th percentile under 25 ms |
etcd_server_leader_changes_seen_total | How often leadership moved | Nearly flat; frequent changes mean instability |
etcd_server_has_leader | Whether a member sees a leader | Always 1 |
etcd_network_peer_round_trip_time_seconds | Delay between members | Well below the heartbeat interval |
etcd_server_proposals_pending | Writes waiting to be committed | Low; a growing backlog means the cluster cannot keep up |
etcd_server_proposals_failed_total | Writes that failed | Near zero; bursts follow leader changes |
etcd_mvcc_db_total_size_in_bytes | Database file size | Comfortably below the quota |
etcd_mvcc_db_total_size_in_use_in_bytes | Live data in the file | Compare with total to decide on defragmentation |
etcd_request_duration_seconds (API server) | How long etcd calls take from the API server’s view | Rising values show trouble before users complain |
apiserver_storage_objects | Objects stored per resource type | Finds the biggest consumers |
A doctor checks pulse, blood pressure, temperature, and weight. Four simple numbers reveal most health problems early. The same is true for etcd: fsync time, leader changes, database size, and request duration are the vital signs.
Alerts that earn their keep
No leader
Critical. Without a leader, no writes are possible at all.
High fsync latency
Warning when the 99th percentile stays above the target for several minutes. It is the earliest signal of a disk problem.
Database near quota
Warning at around seventy to eighty percent of the limit, so you have time to act.
Frequent leader changes
Warning when more than a few happen in an hour.
Logs that matter
A few log messages deserve special attention. A line saying a request took too long means the disk or CPU is slow. A message about failing to send a heartbeat on time means the leader is overloaded or the network is delayed. A message about the database space being exceeded means the quota has been hit. Keep etcd logs at normal verbosity and send them to central storage, because the clues often disappear after a restart.
The widely used kube-prometheus monitoring stack ships with ready-made alert rules and dashboards for etcd, including no-leader, high latency, and database size alerts. Many teams start from these and tune the thresholds to their cluster.
15A Troubleshooting Playbook for a Slow Control Plane
A calm order of questions that finds most causes in minutes.
flowchart TD
A["API server slow or timing out"] --> B{"WAL fsync p99 above 10 ms?"}
B -->|"Yes"| B1["Fix the disk: dedicated NVMe, remove noisy neighbors"]
B -->|"No"| C{"Leader changes frequent?"}
C -->|"Yes"| C1["Check network delay, CPU starvation and timing settings"]
C -->|"No"| D{"Database size near quota?"}
D -->|"Yes"| D1["Compact, defrag, and find the big objects"]
D -->|"No"| E{"Slow large list calls?"}
E -->|"Yes"| E1["Use paging and the watch cache, reduce object counts"]
E -->|"No"| F["Check CPU, memory and noisy clients"]
| Symptom | Most likely cause | First thing to do |
|---|---|---|
| Kubectl commands hang or time out | Slow fsync or an overloaded API server | Look at fsync percentiles and API server request duration |
| Nodes flip to NotReady across many machines | Heartbeat writes are failing or slow | Check etcd latency and leader stability |
| “mvcc: database space exceeded” errors | Quota reached | Compact, defragment, clear the alarm, then find the cause |
| Frequent “leader changed” messages | Slow disk, CPU starvation, or network jitter | Check the disk first, then the network |
| One member is far behind | Slow disk or network on that member | Compare that member’s fsync and peer latency with the others |
| Slow list calls but healthy disk | Huge object counts or full quorum reads | Use paging and cached reads, trim old objects |
| Memory climbing steadily | Very large database or many watchers | Reduce data size and review watch-heavy clients |
If the lights in a house flicker, an electrician checks the main fuse before checking each lamp. In the same spirit, check etcd’s disk and leader stability before chasing the thousands of other possible causes in a slow cluster.
Write down the readings of the key metrics while the cluster is healthy. A baseline turns “this feels slow” into “fsync was 3 ms last month and is 40 ms today,” which is a conversation that leads to a fix.
16High Availability, Failure Scenarios, Backups, and Recovery
Plan for the worst day while the cluster is healthy.
etcd was designed to survive failures. A three-member cluster keeps working if any one member dies, and a five-member cluster keeps working if any two die. The system elects a new leader if the old one disappears, and writes continue as soon as a quorum is available. What it cannot survive is the loss of a majority. At that point writes stop, because no one can guarantee agreement, and only a recovery from backup or the return of the missing members brings the cluster back.
| What fails | What happens | How it recovers |
|---|---|---|
| One follower dies (three members) | Cluster continues with two members | Replace the member, adding it as a learner first |
| The leader dies | Writes pause for about an election timeout | A follower becomes leader automatically |
| Two of three members die | No quorum, so no writes; the API server cannot change anything | Bring members back, or restore from a snapshot into a new cluster |
| A member’s disk slows down | Rising latency, maybe leader changes | Move the member to a faster disk or replace it |
| Database reaches quota | Writes refused, reads still work | Compact, defragment, then disarm the alarm |
| Data corruption or accidental deletion | All members hold the same bad data | Restore from a snapshot taken before the problem |
Backups are not optional
Replication protects against machine failure but not against mistakes. If someone deletes a namespace by accident, all three members faithfully delete it too. Only a backup can bring it back. The standard approach is to take regular snapshots with etcd’s own tool, store them off the machine, and test restoring them. A backup you have never restored is only a hope. A restore builds a fresh cluster from the snapshot, so it has a new identity and every control plane component must be pointed at it.
Having three copies of the same notebook protects you if one is lost in a fire. It does not protect you if someone writes the wrong thing in all three. A photocopy of last week’s pages kept in a different building does. That photocopy is a snapshot.
Snapshot on a schedule
Take snapshots often enough that losing the time between them is acceptable, for example every thirty minutes for busy clusters.
Store them off the machine and encrypt them
Snapshots contain all your Secrets. Treat them as the most sensitive files you own.
Practice the restore
Restore into a test environment on a regular basis and time it. Learn the steps before the emergency.
Document the membership
Keep a record of member names, addresses, and certificates, so rebuilding a failed member is quick.
Taking a snapshot also costs disk and network, so do it from a follower and at a quiet time. And never copy the data directory of a running member as a “backup.” The copy may be inconsistent and unusable.
17Security Without Slowing Down
etcd holds every secret in the cluster, so access to it is access to everything.
Anyone who can read etcd directly can read all Secrets, and anyone who can write to it can rewrite the cluster. That is why the access model is simple and strict: only the API servers should be able to connect to the client port, and only the other etcd members to the peer port. Everything else should be blocked by network rules.
TLS everywhere
Encrypt client traffic and peer traffic with certificates. Use client certificate authentication so only the API server can connect.
Firewall the ports
Allow the client port only from API servers, and the peer port only between members.
Encrypt Secrets in the API server
Turn on encryption at rest for Secrets, so the values stored in etcd and in snapshots are not readable plain text.
Protect snapshots
Store them encrypted, with tight access, and rotate old ones.
Harden the machines
Limit who can log in, keep the operating system patched, and keep the data directory readable only by the etcd user.
Rotate before expiry
Expired etcd certificates are a surprisingly common cause of outages. Monitor their dates.
The performance cost of security is small
TLS adds a little CPU work and a small delay per connection, but the API server keeps a small number of long-lived connections to etcd, so the cost is spread thin. Encryption at rest happens in the API server, not in etcd, and increases object size slightly. The cost of skipping these protections, on the other hand, is the exposure of every password and key in the cluster. There is no good performance argument for leaving etcd open.
A bank vault door is heavy and takes a moment to open. Nobody complains, because what is inside is valuable. etcd is the vault of the cluster, and a little extra time at the door is a fair price.
An expired peer or client certificate can stop members from talking to each other at the worst possible time, such as after a restart. Track certificate expiry on a dashboard and rotate with plenty of notice.
Production example: isolating etcd in regulated environments
Organizations in finance and healthcare commonly run etcd on a dedicated, tightly firewalled set of machines with their own certificate authority, so that even people with broad cluster access cannot reach the database directly.
18Upgrades and Routine Maintenance
A boring, repeatable routine is the best performance feature.
etcd supports rolling upgrades: you upgrade one member at a time, waiting for it to rejoin and catch up before touching the next. Upgrades should move one minor version at a time and follow the release notes, because defaults and behaviors do change between versions. Always take a fresh snapshot first, and always upgrade followers before the leader.
| Task | How often | Notes |
|---|---|---|
| Check key metrics and alerts | Continuously | Automated dashboards and paging |
| Take and verify snapshots | Every 30 to 60 minutes for busy clusters | Store off the machine, encrypted |
| Test restore | Every few months | Time it and update the runbook |
| Defragment | When waste is high, usually monthly or less | One member at a time, leader last |
| Review biggest resource types | Monthly | Spot growth before it becomes a problem |
| Rotate certificates | Before expiry | Track dates on a dashboard |
| Upgrade etcd and Kubernetes | Per support policy | One minor version at a time |
A car does not need heroic repairs if it gets regular oil changes. A cluster does not need emergency heroics if the routine tasks are done calmly on schedule.
Changing one thing at a time
When tuning, change a single setting, measure for long enough to see a pattern, and write down the result. If you change five things together and the cluster improves, you will not know why. If it gets worse, you will not know what to undo. Keep a simple log of every change and its effect.
On managed Kubernetes services you cannot touch etcd directly, so your tuning is about the API behavior: fewer objects, smaller objects, polite clients, and clean-up of old resources. The same principles apply, just aimed at the part you control.
19Advantages, Disadvantages, and Trade-offs
Every tuning choice trades one good thing for another. Knowing the trade helps you choose with open eyes.
Advantages of etcd
- Strong consistency: every client sees the same ordered truth.
- Simple model: keys, values, revisions, and watches are easy to reason about.
- Resilient: survives the loss of a minority of members without downtime.
- Efficient watches: changes are pushed to clients instead of polled.
- Well understood: mature tooling, metrics, and documentation exist.
- Small and focused: it does one job and does not need a heavy platform.
Disadvantages of etcd
- Disk-bound writes: every write waits for fsync on several machines.
- Single leader: all writes pass through one member, which caps throughput.
- Size limits: it is meant for small metadata, not for large data.
- Sensitive to noise: CPU, disk, and network jitter cause leader changes.
- Manual maintenance: defragmentation and backups need attention.
- Hard ceiling: at extreme scale, one etcd cluster becomes the limit.
| Trade-off | Choice | What you gain | What you give up |
|---|---|---|---|
| Three versus five members | Five members | Survive two failures | Slightly slower writes, higher cost |
| Short versus long election timeout | Longer timeout | Fewer false elections | Slower failover when a leader dies |
| Stacked versus external | External etcd | Isolation and predictable speed | More machines to run and secure |
| Large versus small quota | Larger quota | More room for data | Slower recovery, bigger snapshots |
| Single store versus split Events | Separate Events etcd | Main store stays quiet | One more cluster to operate |
| Frequent versus rare defrag | Frequent defrag | Smaller file | More short pauses on members |
| Fresh versus cached reads | Allow cached reads | Much lower etcd load | Data may be a moment old |
20Design Patterns and Anti-Patterns
A handful of habits separate calm control planes from noisy ones.
Patterns worth copying
Dedicated fast disk
Give etcd local NVMe, on its own device, and test it before use.
Three members across three zones
The standard balance of safety and speed.
Separate etcd for Events
Protect critical data from the noisiest resource.
Baseline and alert
Record healthy metrics, and alert on drift from them.
Regular, rehearsed backups
Snapshots stored off-site, with restore drills.
Review new cluster-wide agents
Check their API usage before they reach every node.
Anti-patterns to avoid
The mistake
Putting etcd on a shared or network disk that is also used by other busy programs.
Why it hurts
Every burst from a neighbor increases fsync time, which delays all writes and can cause leader changes.
Do this instead
Use a dedicated local SSD or NVMe device and test its sync latency before use.
The mistake
Stretching one etcd cluster across distant regions for safety.
Why it hurts
Every write waits for a long round trip, and timing settings must be raised so much that failover becomes slow.
Do this instead
Keep members in one region across zones, and handle regional disasters with backups and a recovery plan.
The mistake
Raising the quota every time the NOSPACE alarm fires.
Why it hurts
The root cause remains, and each increase makes recovery and backups slower.
Do this instead
Find the biggest resource types, clean up or reduce them, and keep a regular defragmentation routine.
The mistake
Defragmenting all members at the same time.
Why it hurts
Each member pauses while it runs, so the cluster may lose its quorum and stop accepting writes.
Do this instead
Go one member at a time, check health in between, and finish with the leader.
The mistake
Storing large blobs, such as big files or data sets, in ConfigMaps, Secrets, or custom resources.
Why it hurts
Large objects slow replication, inflate the database, and push requests toward the size limit.
Do this instead
Use object storage or a proper database for large data, and store only a small reference in Kubernetes.
The mistake
Treating three replicas as a backup.
Why it hurts
A mistaken deletion is replicated to every member within moments.
Do this instead
Take scheduled snapshots, store them elsewhere, and practice restoring them.
21Best Practices and Common Mistakes
A short checklist to read before you build or change an etcd setup.
Start with the disk
Choose fast local storage, test fsync latency, and record the result. Every other decision builds on this.
Use three members in three zones
Move to five only when you have a clear reason and have measured the write cost.
Isolate etcd from noisy neighbors
Use dedicated machines for large clusters, or at least guaranteed CPU and a dedicated disk for stacked ones.
Keep the database small
Limit Events, clean finished Jobs, cap release history, and review the biggest resource types each month.
Monitor the vital signs
Alert on missing leader, high fsync time, frequent leader changes, and size near quota.
Back up and rehearse restores
Snapshots that have never been restored are untrusted.
Lock down access
TLS, firewalls, encrypted Secrets, and encrypted snapshots, all in place before production.
Change one thing at a time
Measure before and after, and write down what you changed.
Mistakes beginners make
- Blaming the wrong layer. Spending days on node and network problems when a slow etcd disk was the cause.
- Tuning timeouts before fixing the disk. Longer timeouts hide instability instead of removing it.
- Ignoring Events. They are the largest source of writes in many clusters and are rarely checked.
- Forgetting the alarm. After freeing space, the NOSPACE alarm must be disarmed or writes stay refused.
- Letting Helm and Jobs pile up. Old releases and finished Jobs quietly grow the database for months.
- Skipping restore drills. Finding out the backup is unusable during a real outage is the worst possible timing.
- Copying the data directory of a live member and calling it a backup.
When the control plane is slow, ask three questions in order: is the disk fast, is the leader stable, and is the database small. Those three answer most cases before you need to look at anything more complicated.
22Real-World and Industry Examples
The same lessons appear again and again in large production clusters.
OpenAI: fast local disks and a separate Events store
In a publicly shared engineering write-up about scaling Kubernetes to thousands of nodes, OpenAI described fixing etcd latency by moving to fast local storage and splitting the noisy Event data into its own etcd cluster. These are the two most common first steps for any growing cluster.
Alibaba: improving the storage engine itself
Engineers at Alibaba, running very large Kubernetes clusters, contributed improvements to how etcd’s storage engine manages free pages, which reduced the cost of operations on large databases. The contribution shows that at huge scale, even internal details of the database matter and the community benefits from shared fixes.
Google: beyond etcd for the largest clusters
Google has publicly described using a Spanner-based storage layer for its very largest Google Kubernetes Engine clusters. For almost everyone else, the more realistic strategy is to keep each cluster within a size that etcd handles well and to run several clusters.
Managed services: Amazon EKS, Google GKE, and Azure AKS
These services run etcd on the customer’s behalf on fast storage across several zones, take backups, and handle upgrades. Customers still affect etcd through the objects and requests they send, so object hygiene, polite clients, and cleanup remain valuable even when you never see the database.
Platform teams everywhere: the chatty agent story
Many platform teams have found that a single poorly behaved agent, such as a logging, monitoring, or security tool, repeatedly listing all objects, could slow down an entire cluster. Reviewing new cluster-wide software for API behavior has become a standard part of onboarding.
In every story, the winning moves are the same: fast local disks, a small and tidy database, a quiet network, polite clients, and a practiced recovery plan. These are simple ideas that require steady discipline more than clever tricks.
23Frequently Asked Questions
Short answers to the questions beginners ask most often.
24Summary and Key Takeaways
You started with a single master notebook in a busy library and finished with a clear picture of how Kubernetes keeps its truth. etcd is small, careful, and consistent. Its price is that every write waits for a majority of disks and networks to agree, so its performance depends on steady disks, quiet networks, small data, and polite clients. Tuning is mostly a matter of protecting those four things, measuring honestly, and practicing recovery before it is needed.
Key Takeaways
- etcd is the single source of truth for Kubernetes, and only the API server talks to it, so a slow etcd slows the entire cluster in many confusing ways.
- The disk comes first. Every write needs fsync on a majority of members, so use dedicated local SSD or NVMe, and keep the 99th percentile WAL sync time under about 10 ms.
- Use three members across three zones for most clusters. More members add safety, not speed, and stretching across regions makes every write slower.
- Keep Raft timing steady. Avoid CPU starvation and network jitter, and treat frequent leader changes as a symptom to investigate, not something to hide with longer timeouts.
- Keep the database small. Let compaction run, defragment one member at a time with the leader last, watch the quota, and clean up Events, finished Jobs, and release history.
- Reduce load at the source. Use cached and paged reads, separate Events into their own etcd, keep objects small, and review any cluster-wide agent for its API behavior.
- Measure, protect, and rehearse. Alert on missing leader, slow fsync, and size near quota; lock down ports with TLS and encrypt Secrets and snapshots; and practice restoring from backups before you need them.