Elasticsearch, simulated
An animated, step-by-step Elasticsearch (and OpenSearch) cluster in your browser: murmur3 routing, primaries and replicas, the indexing buffer, translog, refresh, flush and segment merging inside every shard, query-then-fetch search, node failures, master elections, split brain and shard sizing — with guided scenarios and a REST console.
Added
Works with
- MongoDB replica sets and sharding, simulated Databases and streamingMongoDB's primaries, secondaries, elections and shard routing, animated the same way
- System design interviews Interview prepa web-scale search engine as an interview design — document-partitioned shards, a root-and-leaf serving tree, replicas and a real-time index
How to use it
An Elasticsearch cluster in miniature that runs entirely in this page: a client, a coordinating node, three master-eligible nodes and a few data nodes holding the shards of an index — and inside every shard copy, its Lucene engine: the in-memory indexing buffer, the translog and the segments. Every request, replication, refresh, flush, merge, cluster-state publication and vote is drawn as it happens, and the rules — where a document goes, when it becomes searchable, what survives a crash, who may be master, when health turns yellow or red — follow Elasticsearch 7.x–9.x, with OpenSearch’s differences noted. Nothing here talks to a real cluster.
How to use it
Pick a scenario and press Start. Each step sets something up — indexes documents, searches, kills a node, cuts the network — then plays for a few simulated seconds and pauses so you can read what happened and why, with links to the Elasticsearch documentation. Next step moves on, Back rewinds (the simulator is deterministic, so it replays the earlier steps), ⏭ jumps to the end of the step and Step ⇥ advances to the next single thing that happens. Space plays and pauses; → is the next step. The Playground has no script.
Speed scales everything. Hop time is how long a message takes to cross a wire at 1×: while a drawn message is on its way the simulated clock slows, so a shard changes only when the message lands. Sim clock turns that off. Hop time changes only how the run is shown, never what happens. With reduced motion set in your system, messages jump instead of travelling.
⛶ Full screen (or F) gives the diagram the whole window — the browser’s full screen where it
is allowed, otherwise a full-window layer (iPhone). H hides the narration and leaves a compact
bar with the step, play and next controls; Escape leaves. The diagram is scaled to fit the window
and redrawn when it changes size.
-
The diagram. At the top, the client, the coordinating-only node (it routes writes and scatters and gathers searches) and the master-eligible nodes, with ★ on the elected master and the current term, cluster-state version and voting configuration. Below, one card per data node (tier, zone, and pills for down, slow, cut off and no master), with a box for every shard copy: P primary or R replica, its sequence number and local and global checkpoints, and three rows — the indexing buffer (one chip per document not yet in a segment), the translog (one cell per operation since the last flush; filled = fsynced, outlined = not yet) and the segments (width by document count; blue = live documents, red hatching = deleted documents, dashed outline = not committed by a flush, faded = written but not yet searchable). Packets are labelled: an index request and the shard it was routed to,
seq Nreplication and itsack,query/top k/fetchfor search,v12/commitfor cluster-state publication, votes between master nodes, recovery transfers. Inside a shard,refresh,fsync,flushandmerge _1+_2+_3show where they act. A promoted replica flashes. On a phone the diagram stacks top to bottom and busy nodes switch to one line per shard. Tap a node or a shard to inspect it and act on it (kill, power cut, restart, slow down, cut off the network; refresh, flush or force-merge one shard copy). -
Counters. Cluster health, the master, the cluster-state version and term, writes acknowledged and failed, acked but lost (acknowledged to the client but no longer in the current primary), searchable and not-yet-searchable documents, segments, deleted documents, unassigned shards and average search time.
-
Do something. Index documents (with an id, a text, a count and
refresh=false|wait_for|true), delete or GET by id, steady traffic; search with a query andfrom, take the next page withsearch_after, open a point in time;_refresh,_flush,_forcemerge, change the number of replicas; kill, power-cut, restart, slow down or cut off any node; add a data node; heal the network. -
REST console. Type requests as you would with curl or Kibana’s Dev Tools; responses come back when the simulated cluster answers, in Elasticsearch’s format.
helplists what it understands:PUT /idx(withnumber_of_shards,number_of_replicas,refresh_interval,index.translog.durability),POST /idx/_doc,PUT /idx/_doc/<id>?routing=&refresh=,GET /idx/_doc/<id>?realtime=false,DELETE,GET /idx/_search?q=&size=&from=or amatchquery body withsearch_afterandpit,POST /idx/_refresh,POST /idx/_flush,POST /idx/_forcemerge?max_num_segments=1,PUT /idx/_settings,POST /idx/_pit,POST /alias/_rollover,GET _cluster/health,GET _cluster/state,GET _cluster/allocation/explain, and_cat/health,_cat/nodes,_cat/master,_cat/indices,_cat/shards,_cat/segments,_cat/allocation(add?vfor headers). -
Last search. The query, its phase, the time each shard took and on which copy, how many entries the coordinating node merged and kept, the top hits, and the adaptive replica selection statistics the coordinating node keeps for each data node.
-
Shard copies (like
_cat/shardswith the engine inside) and the event log, with a filter for cluster-state publications and elections. -
Settings rebuild the cluster: Elasticsearch or OpenSearch, master-eligible and data nodes, a coordinating-only node, data tiers, zones and awareness, shards, replicas, the routing function,
routing_partition_size, starting documents, refresh interval, translog durability and sync interval,wait_for_active_shards, delayed allocation timeout, OpenSearch segment replication,segments_per_tier, adaptive replica selection, legacyminimum_master_nodes, latency and seed.
The other tabs: Routing computes the shard for any _id or routing value, step by step, with
both the 7.0–9.3 and the 9.4 functions and the textbook formula; Fan-out shows how search
latency’s tail grows with the number of shards a query touches, and what deep pagination costs;
Shard sizing plans primaries, shards per node and shard size for time-series data against
Elastic’s guidance.
Scenarios
-
Indexing a document — the coordinating node routes with murmur3, the primary assigns a sequence number and replicates to every in-sync copy,
wait_for_active_shardsas a pre-flight check (and the 503 when it cannot be met), the response. -
Near-real-time search — the indexing buffer, a search that finds nothing, a realtime GET that finds the document through the live version map, the refresh that creates a searchable segment,
refresh=wait_for. -
Durability — the translog fsynced before each acknowledgement, flush as a Lucene commit, a power cut, store recovery replaying the translog, and
durability: asynclosing the last acknowledged writes. -
Segments and merging — a segment per refresh, the tiered merge policy, updates as delete plus add, deleted documents reclaimed by merges, force-merge.
-
Search — query then fetch, per-shard top
from + size, the coordinating node’s merge, deep pagination,search_afterwith a point in time, a slow node, adaptive replica selection, fan-out and tail latency. -
Node failure — follower checks, replica promotion with a new primary term, yellow, delayed allocation, re-allocation with peer recovery, a returning node recovering ops-based, red.
-
Master election — publish, acknowledge, commit; leader checks, pre-vote and election in a new term; losing the quorum; recovering it.
-
Shard sizing, tiers and rollover — an over-sharded index, the 10–50 GB guidance, rollover through an alias, hot to warm relocation by
_tier_preference, force-merging read-only data. -
Split brain — a partitioned master steps down without a quorum, the minority refuses writes, the majority carries on, healing; replayed with legacy
minimum_master_nodes: 1, two masters and a lost acknowledged write. -
Playground — your own cluster.
What it models
-
Routing.
shard = hash(_routing) % number_of_primary_shardsis how the documentation explains it. Exactly: the hash is Elasticsearch’sMurmur3HashFunction— Lucene’smurmurhash3_x86_32with seed 0 over the routing string’s UTF-16 code units, low byte first — and indices created by 7.0–9.3 computefloorMod(hash, routing_num_shards) / routing_factor, whererouting_num_shardsis the largestnumber_of_shards × 2^x ≤ 1024so the index can be split; indices created by 9.4 usefloorMod(hash, number_of_shards).routing_partition_sizeaddsfloorMod(hash(_id), size). The tests check these against Elasticsearch’s ownMurmur3HashFunctionTestsandIndexRoutingTests(all 99 values oftestBWC). -
Writes. The coordinating node resolves the shard and forwards to the primary; the primary checks
wait_for_active_shards, assigns the next sequence number under its primary term, applies the operation, replicates it to every copy in its routing table, waits for all of them, fsyncs the translog whenindex.translog.durability: request, and answers with_shards,_seq_no,_primary_termand_version. A replica that does not answer is reported to the master and removed from the in-sync set before the write is acknowledged; a primary that cannot reach a master does not acknowledge (data replication model). Local and global checkpoints are tracked per copy. Updates are a delete of the old version plus an add; optimistic concurrency withif_seq_noreturns 409 on a conflict. A write to an index that does not exist creates it (1 shard, 1 replica). -
Inside a shard. New documents go to the indexing buffer and the translog, and their id into the live version map. A refresh (every
index.refresh_interval, 1 s by default) writes the buffer as a new segment, applies pending deletes and opens it for search; a realtime GET of an id still in the version map refreshes only the internal reader. A flush is a Lucene commit: the buffer becomes a segment, every segment is fsynced, the commit point records the local checkpoint and the translog rolls to a new generation; it happens when the translog grows past a threshold or ages pastflush_threshold_age, or on_flush. Merges follow Lucene’s TieredMergePolicy: the allowed segment count per tier fromsegments_per_tier, candidate merges of up tomax_merge_at_oncesegments scored by skew, size and reclaimed deletes, too-large segments left alone unless they are mostly deletes; force-merge rewrites tomax_num_segments. Search uses BM25 (k1 = 1.2, b = 0.75) with shard-local statistics, in which deleted documents still count until merged. -
Crashes. Kill is a process crash: what reached the operating system survives (the whole translog). Power cut keeps only what was fsynced: the last commit and the fsynced part of the translog. On restart the master allocates a primary only to a node holding an in-sync copy on disk (store recovery: open the last commit, replay the translog above its checkpoint); replicas recover from the primary — ops-based (replaying only the missing operations, as retention leases allow) when the node had the shard, file-based (copying segments, then the operations since) otherwise.
-
Allocation. The master assigns primaries, then replicas once their primary is active, with the deciders that matter here: never two copies of a shard on one node (
same_shard),_tier_preference(data_hot,data_warm,data_cold), zone awareness, and at most two incoming recoveries per node. Among allowed nodes it picks the lowest weight of the BalancedShardsAllocator: 0.45 × (shards − average) + 0.55 × (index shards − average); it rebalances (relocating) when that improves the weight by more than 1, and moves shards off a tier they no longer belong to. When a node leaves, its primaries are replaced by promoting an in-sync replica (primary term + 1) and its replicas waitindex.unassigned.node_left.delayed_timeout(delayed allocation). Health is red with an unassigned primary, yellow with an unassigned replica, green otherwise. -
Cluster coordination (the 7.0+ "Zen2" design, discovery and cluster formation). Master-eligible nodes elect a master by a quorum of the voting configuration, after a pre-vote, in ever-increasing terms. The master publishes every cluster-state change to all nodes, commits it once a quorum of master-eligible nodes has acknowledged and steps down if it cannot. Leader and follower checks detect failures (interval, retry count); a restarted node is a new node to the master. The voting configuration is kept odd-sized and never shrinks below three nodes on its own (as
Reconfiguratordoes). WithminMastersset the simulator instead behaves like legacy Zen discovery withdiscovery.zen.minimum_master_nodes: any that many visible master-eligible nodes may elect a master, and when two masters meet the one with the older cluster state yields. -
Search. The coordinating node sends the query to one copy of each shard — chosen by adaptive replica selection (on by default since 7.0, C3: rank = R − 1/µ + q̂³/µ over EWMAs with α = 0.3, as
ResponseCollectorServicecomputes it) or round-robin — each shard returns its topfrom + sizeids and scores, the coordinating node merges them and fetches the page’s documents from the shards that hold them.from + size > 10000is refused (index.max_result_window).search_afterand points in time are supported; a point in time keeps its segment readers. Each data node has two search threads; a slow node multiplies its service time.
OpenSearch
Set Flavour to OpenSearch (or flavor=os). OpenSearch forked from Elasticsearch 7.10, so the
model above holds, with these differences:
-
The master is called the cluster manager; the coordination protocol is the same.
-
Routing keeps
routing_num_shards(there is no 9.4-style modulo routing). -
index.replication.type: SEGMENT(segment replication) is available: replicas write the translog but do not index; the primary copies its segments to them after each refresh, so replicas use less CPU but see new documents a little later. Realtime GETs go to the primary (segment replication). -
There is no
_tier_preferenceor ILM: nodes are tagged with an attribute and indices move with Index State Management (ISM) policies.
Limits
-
A handful of nodes and shards; documents are a short
titlefield; onlymatch-style queries (BM25 on that field), no aggregations, mappings, analyzers beyond lower-cased words, or scroll. -
Timeouts are shorter than Elasticsearch’s so failures play out in seconds (each setting shows the real default). The flush threshold is a number of operations standing in for
flush_threshold_size. Merge sizes are counted in documents, and the merge policy is Lucene’s algorithm reduced to those sizes. Network latency is fixed. -
Not modelled: the write-load and disk-usage terms of the allocator, disk watermarks, shard request caching,
search_idle(described, not simulated), translog retention for recovery (retained history is assumed), primary-replica resync after promotion, cross-cluster features, snapshots, stateless/serverless Elasticsearch, and the 8.x/9.x merge policy for time-series data (LogByteSizeMergePolicy). -
The shard-sizing tab is guidance arithmetic, not a benchmark; the fan-out tab assumes independent lognormal shard latencies.
Related: Kafka, simulated, Kubernetes, simulated, latency numbers, probability, statistics, PostgreSQL, Redis, Big-O.
Linking to an example
Links can be written by hand. Add a tab after #: sim (the default), routing, fanout or
sizing. A link’s settings replace this page’s saved settings (a button restores yours).
| Parameter | Meaning | Example |
|---|---|---|
|
A scenario (list below), with its own cluster; parameters given with it override the scenario’s |
|
|
The same, without the scenario’s own settings |
|
|
|
|
|
Master-eligible nodes, 1–5 |
|
|
Data nodes, 1–8 |
|
|
A coordinating-only node ( |
|
|
|
|
|
Zones the data nodes are spread over, 1–3 |
|
|
Shard allocation awareness by zone |
|
|
Primary shards of the first index, 1–12 |
|
|
Replicas, 0–3 |
|
|
|
|
|
|
|
|
Documents already in the index at the start, 0–200 |
|
|
|
|
|
|
|
|
|
|
|
Default |
|
|
|
|
|
OpenSearch |
|
|
|
|
|
Adaptive replica selection |
|
|
Legacy Zen |
|
|
One-way network latency in ms |
|
|
Random seed (document text, ids, timings) |
|
|
Playback speed: |
|
|
Hop time: seconds a message takes to cross a wire at 1× ( |
|
Scenarios:
example= |
Shows |
|---|---|
|
Indexing a document: routing, primary then replicas, wait_for_active_shards, the response (open) |
|
Near-real-time search: the buffer, refresh, realtime GET, refresh=wait_for (open) |
|
Translog fsync, flush, a power cut and translog replay; async durability losing writes (open) |
|
Segments, the tiered merge policy, deleted documents, force-merge (open) |
|
Query then fetch, deep pagination, search_after and PIT, adaptive replica selection, fan-out (open) |
|
Replica promotion, yellow, delayed allocation, recovery, red (open) |
|
Cluster-state publication, master election, losing and regaining the quorum (open) |
|
Over-sharding, rollover, hot to warm, force-merge (open) |
|
A network partition with quorums — and with |
|
A cluster with 30 documents to experiment with (open) |
Examples: split brain with legacy Zen, search without adaptive replica selection, node failure without delayed allocation, OpenSearch segment replication, a two-zone playground, the routing calculator.
Sources: the Elasticsearch reference
(replication model, near-real-time search, translog, merge settings, cluster health, allocation,
discovery and cluster formation, voting configurations, pagination, point in time, adaptive
replica selection); Elasticsearch source (Murmur3HashFunction, IndexRouting, RoutingFunction,
MetadataCreateIndexService, Reconfigurator, ResponseCollectorService, WeightFunction,
MergePolicyConfig, IndexSettings); Lucene’s TieredMergePolicy and BM25Similarity;
Size your shards;
A new era for cluster coordination in Elasticsearch;
Suresh et al., C3: Cutting Tail Latency in Cloud Data Stores via Adaptive Replica Selection (NSDI 2015);
Dean and Barroso, The Tail at Scale (CACM 2013).
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.