Repository navigation
Replies: 3 comments 11 replies
|
tldr? |
It's interesting. Some of them seem reasonable, such as Also, learner doesn't support snapshot requests either, so the |
It is true for K8S use case.
Sharing a concrete production scenario from our side that maps to two of the use cases in the OP. Environment
Use case 1 — Hot standby for fast voter recovery When a voter goes down, replacing it with a fresh member requires the full snapshot transfer + restore path. At our db size this consistently takes ~3–4 minutes before the If we keep a learner as a warm standby that is already caught up on the raft log, MemberPromote returns the cluster to full voter count in seconds rather than minutes. The Use case 2 — Backup isolation via snapshot save against a learner We take periodic snapshots for disaster recovery. Running snapshot save against a voter at this db size produces a non-trivial amount of read I/O and network egress on a member that is This is not a read-scaling argument. It's about moving heavy local I/O off the voter set, which is something a non-voting replica is uniquely well-suited for. Happy to share more numbers if useful. |


Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
TL;DR
Core argument: An etcd learner should not be treated only as a short-lived
pre-promotion state. It is also a long-running, non-voting, read-capable
replica. etcd already lets learners serve
Status, serializableRangereads,and
Snapshotstreams — but theDefragmentRPC is still rejected, so along-lived learner's backend can grow unbounded with no supported way to
reclaim space.
Why learner defrag matters
read-only service, hot-standby capacity, backup target, operational
isolation, and topology flexibility.
have. Compaction changes logical revisions; defragment is what reclaims
physical backend space.
Industry precedent (non-voting replicas as durable infrastructure, not
transient state):
columnar OLAP replicas.
read-scaling primitive.
replication factors.
availability.
Proposed implementation (minimal, low-risk):
mutation, and membership changes.
does not require quorum, starting with
Defragment.DefragmentRequesttoisRPCSupportedForLearnerinserver/etcdserver/api/v3rpc/util.go, plus a small test update. No newserver logic or replication coordination.
directly target learner endpoints for maintenance.
Bottom line: Opening
Defragmentfor learners is low-hanging fruit. Itpreserves the non-voting nature of learners while making the long-running
learner use cases etcd already supports operationally viable.
Background
This note summarizes why an etcd learner should not be treated only as a
short-lived pre-promotion state. It was written in the context of
etcd issue #21740, where a
learner member can accumulate backend fragmentation but currently rejects the
online
DefragmentRPC.Current learner behavior
The current RPC allowlist already gives a learner useful operational roles:
StatusRequestis explicitly acceptedfor learners, and the status response reports fields such as raft index,
applied index, backend size, backend size in use, and
IsLearner.RangeRequestis accepted whenSerializableis true, while linearizable reads and mutating KV operationsare rejected.
SnapshotRPC. The stream interceptorrejects learner stream RPCs except the snapshot method, and
etcdctl snapshot save --endpoints=<learner>can therefore use a learner as the snapshotsource.
DefragmentRPC, becauseDefragmentRequestis not in the learner unary allowlist. The maintenanceserver implementation itself is local backend maintenance, but the learner
interceptor rejects it before it reaches the handler.
Code references:
server/etcdserver/api/v3rpc/util.go:isRPCSupportedForLearnerallowsStatusRequestand serializableRangeRequest.server/etcdserver/api/v3rpc/interceptor.go: unary learner requests outsidethat allowlist return
ErrGRPCNotSupportedForLearner; stream learnerrequests are rejected except for
Snapshot.server/etcdserver/api/v3rpc/maintenance.go:Defragmentperforms localbackend defragmentation, and
Snapshotstreams a backend snapshot.tests/integration/clientv3/kv_test.go:TestKVForLearnerlocks thecurrent contract that a learner accepts serializable reads and rejects
linearizable reads, put, delete, and txn.
Why long-running learners are valuable
It is reasonable to view learner membership primarily as a safe path toward
promotion, especially because that was the original operational motivation for
adding learners. At the same time, the behavior etcd already exposes suggests
there may be room for a few carefully scoped, longer-running learner use cases.
A learner is also a replicated, non-voting, read-capable member. That shape is
useful when an operator wants an up-to-date copy of the keyspace without adding
quorum cost or write-path risk.
Long-running learners can support several practical deployment patterns:
serializable reads close to local consumers. This is not a replacement for
linearizable reads, but it can serve read-heavy workflows that can tolerate
serializable semantics.
promoted when the cluster needs to restore voter count. This is materially
faster and less risky than adding a cold member after capacity is already
degraded.
snapshot save, movingsnapshot read I/O and network egress away from voting members.
backup jobs can be routed to a non-voting member so voters remain focused on
consensus and write service.
expensive for quorum latency, such as a distant region, a constrained
disaster-recovery site, or a network segment dedicated to backup tooling.
These patterns are only sustainable if the learner has the same local storage
maintenance primitives as other bbolt-backed members. Compaction changes the
logical revision history, but defragmentation reclaims physical backend space.
If learners can be long-lived read and snapshot sources, they also need a
supported defrag path. Otherwise a learner that is intentionally retained for
read, standby, or backup use can grow unbounded even though the equivalent voter
maintenance is available.
Similar designs in other storage systems
Other storage systems describe non-voting or learner-like replicas as durable
read-serving infrastructure, not only as temporary membership states.
TiDB TiFlash
TiFlash is described as a columnar storage extension that makes TiDB an HTAP
database. TiFlash replicas are asynchronously replicated by the Raft Learner
consensus algorithm. The docs describe this as a way to store columnar replicas
with snapshot isolation, workload isolation, and computing acceleration for
analytical queries.
Important details from the TiFlash documentation:
TiKV and replicated to TiFlash rather than written directly to TiFlash.
continue normally when TiFlash is down or has high network latency.
same snapshot isolation level as TiKV.
steady-state mechanism for an OLAP-serving replica.
Source: https://docs.pingcap.com/tidb/stable/tiflash-overview/
OceanBase read-only replicas
OceanBase and Alibaba Cloud OceanBase describe read-only replicas as replicas
that do not participate in Paxos voting. Instead, they observe and replay logs
from Paxos members, then provide read-only service when the application can
accept the consistency model.
Important details from the OceanBase documentation:
and replays them locally.
read requests and reduces pressure on the primary cluster.
read/write isolation, complex reporting, and OLAP analysis without
interfering with transaction processing on the primary cluster.
read-only replicas, which treats read-only status as an explicit operational
replica type.
Sources:
YugabyteDB read replicas
YugabyteDB describes read replicas as observer nodes that extend Raft. They do
not participate in writes, receive an asynchronously replicated,
timeline-consistent copy of data, and can be placed in remote data centers for
read-only workloads.
Important details from the YugabyteDB documentation:
synchronous write latency.
write latency is not tolerable.
even replica counts, because they are outside Raft write consensus.
Sources:
CockroachDB follower reads
CockroachDB follower reads are not identical to etcd learners, because they
read from ordinary replicas rather than a dedicated learner member type.
However, the design shows the same broader product pattern: a replicated copy
can intentionally serve stale or bounded-staleness reads to improve locality,
availability, and read scalability while avoiding write-path coordination for
those reads.
Important details from the CockroachDB documentation:
view.
routing to a remote leaseholder.
replicas can continue serving reads even when the SQL gateway cannot reach the
leaseholder.
Sources:
Implication for learner defragmentation
Learner defrag is not only about helping a soon-to-be-promoted member. It is a
maintenance primitive for a bbolt-backed replica that etcd already permits to
serve status, serializable reads, and snapshots. If etcd supports these
long-running read and backup roles, then the learner needs a safe way to reclaim
backend space after compaction.
A narrow implementation principle follows from the current contract:
membership-changing operations rejected.
not require quorum participation, starting with
Defragment. Opening upDefragmentfor learners is a low-hanging fruit: the maintenance handleralready performs purely local backend defragmentation, so the change is
effectively limited to adding
DefragmentRequestto the learner unaryallowlist in
isRPCSupportedForLearnerplus a small test update — no newserver logic or replication coordination is required.
directly target learner endpoints for maintenance.
This preserves the non-voting nature of learners while making the already
supported long-running learner use cases operationally viable.
All reactions