System Design intermediate LIVE SIMULATOR
[ARCH]

Reactive Architecture Builder

Build a typed software architecture, change realistic capacity settings, and watch overload, backpressure, and Kubernetes recovery propagate through the system.

system designarchitectureAPI gatewayKubernetesqueuesbackpressurecapacity planning
Interactive Simulator

Continue with the guided workspace

Use the paired workspace to connect this guide's mental model with live component state, visible signals, and the outcome each step or scenario is meant to prove.

Most architecture diagrams stop when they show an arrow from one box to another. That is useful for naming dependencies, but it does not answer the question that matters during an incident: what changes when one component receives more work than it can safely handle?

This builder treats an architecture as a small deterministic runtime. Each component has typed input and output ports, configuration, capacity, lifecycle state, a runtime profile, and a responsibility. Changing request rate, rate limit, replica count, worker throughput, or a Pod health state immediately changes the visible system. The animation is not decoration: it follows the same model that derives throughput, backlog, pressure, degradation, and controller actions.

Connections are part of that runtime rather than decorative arrows. Every edge joins one exact output port to one compatible input port. An enabled edge can report offered work, accepted throughput, and dropped work; reconnecting or removing it changes downstream state because simulation follows the current graph rather than a hidden template path.

For synchronous request/dependency edges, forward throughput and caller-visible completion are separate measurements. accepted is work admitted by the callee, processed is the admitted work evaluated for that call, and the result is partitioned into completed, failed, and timedOut. A request can therefore be forwarded successfully and still fail or time out deeper in the dependency path. Completion is derived after the forward graph settles by walking the existing synchronous DAG backward; it does not add reverse edges or execute the graph a second time. Cache hits complete locally, while cache misses inherit the outcome of the origin dependency. Event, job, telemetry, replication, health, and control edges stay one-way and do not fabricate synchronous return metrics.

The runtime conserves work. Ordinary request connections from the same output share traffic by healthy destination capacity instead of each receiving a copy of the full rate. A Load Balancer is the explicit exception: after reserving probe overhead, its round-robin model gives every ready backend path an equal offer and lets each backend’s own capacity determine acceptance or pressure. Telemetry, health, and control signals broadcast because their definitions use signal semantics. Service and Deployment cache-aside policies check Redis first and send only misses or fail-open overflow to PostgreSQL, while all callers share one Redis capacity budget per tick.

Compatibility has two gates. Port types describe the data contract (http-request, sql-query, sql-result, sql-replication, cache-command, event, job, data, telemetry, or health), while peer roles describe the architecture boundary. A Client may call a Frontend, API Gateway, or Load Balancer, but it cannot call PostgreSQL, Redis, a Queue, or a Worker directly. A Service exposes separate SQL, cache, event, and telemetry outputs so those responsibilities stay visible.

The component cards and persistent Inspector expose the same model from different levels. Cards keep the most important operational signal visible, while the Inspector explains current state, capacity, runtime stages, typed input and output, and recent component-local events. Connector pulses show modeled throughput rather than captured network packets.

When you load a system preset, the Preset Guide explains its architectural purpose, end-to-end mental model, scope boundaries, component responsibilities, omission consequences, and teaching scenarios. Selecting a component there highlights the same canvas node; the Inspector then shows that component’s live state and runtime evidence. Keeping purpose in the Guide and changing evidence in the Inspector lets you compare what the architecture is meant to teach with what the current simulation is doing.

Every teaching scenario includes an Apply scenario action. Clicking it first runs component mechanics evidence: an isolated baseline → variant diagnostic that answers whether the component’s own contract reacts. It then runs the full-preset comparison through the complete authored graph, including the declared warmup and observation window; that result must satisfy the scenario relation and any declared causal-path evidence before the variant can replay on your live preset graph. The result panel labels all three surfaces separately: component mechanics, full-preset comparison, and the live preset value. Applying a scenario selects the responsible component and then continues the live clock from that recorded observation, so you can watch later effects unfold. The scenario restarts from authored config every time, so scenarios do not contaminate each other. A full-graph failure leaves the live preset unchanged and reports the missing evidence instead of presenting a synthetic success. The live value refreshes on normal ticks, but direct mutations or Chaos Lab incidents clear the applied status.

Challenge Mode in the Run tab turns the same simulator into a repeatable design exercise. Pick traffic spike, dependency interruption, or backlog drain; prepare the authored architecture before Begin; then the runner applies demand or dependency changes on fixed challenge ticks and captures start/end evidence through the same baseline/variant comparison model. Editing the architecture or using Chaos after Begin keeps the experiment usable but marks that attempt practice-only, so it cannot later be confused with the untouched measured run. Retry restores the learner’s prepared architecture and starts a fresh deterministic attempt. Untouched measured attempts evaluate explicit model-backed objectives and show the measured value, target, and an overall “N of M objectives met” verdict. Practice-only attempts remain unscored, and Challenge Mode does not invent a weighted 0–100 quality score.

Mental Model

Start with the request path: Client -> Frontend App -> API Gateway -> Service. Client traffic becomes offered load constrained by its modeled concurrency window and deadline. The Frontend can serve a configured static share locally. The API Gateway can cap the API share. The Service compares accepted load with its thread-pool and request capacity. For cached reads, every request checks Redis; hits finish there, while misses continue to PostgreSQL. A 100% effective hit rate therefore produces no cache-aside database reads while Redis has capacity. The effective rate falls when TTL is too short or the working set exceeds memory. If Redis is saturated, accepted cache checks are capped and the default fail-open policy sends overflow to PostgreSQL. Hit and miss totals include accepted direct cache traffic without counting cache-aside reservations twice.

A queue can absorb a mismatch between producer and worker throughput, but it cannot erase that mismatch. Backlog is the visible record of unfinished work; once retained work reaches the configured bound, additional arrivals are rejected.

Select a component to compare its current state, capacity, and recent runtime evidence with the active architecture path. The Inspector is the teaching surface for component-local behavior; the guide focuses on the system tradeoffs rather than a toolbar manual.

Five Templates

  • Web overload follows Client -> Frontend App -> API Gateway -> Service, with Service cache and SQL effects reaching Redis and PostgreSQL. It isolates admission limits, thread-pool capacity, cache fallback, and recovery.
  • Deployment repair follows Load Balancer -> Kubernetes Deployment -> PostgreSQL. Two owned Pods provide ready capacity; a failed Pod is replaced only after the controller’s replacement detection delay, and its replacement must become ready before contributing capacity.
  • Event backpressure sends 900 events/s from an Event Producer to a Queue with 600 jobs/s of aggregate Worker capacity. The Queue dispatches to two Workers, but only one Worker sends SQL queries to PostgreSQL, so the template demonstrates backlog and fan-out without implying identical downstream wiring.
  • Blank starts from a near-empty canvas holding a single Client, so you can build an architecture from scratch instead of editing a prepared one.
  • Full system lab joins every built-in type in one acyclic architecture. Browser and adapted event traffic meet at the API Gateway, the Load Balancer divides work between a Service and Kubernetes Deployment, compute uses Redis and PostgreSQL, PostgreSQL results feed ETL batches, Service and ETL events meet at the Queue, and Service/Worker telemetry reaches Monitoring.

Full System Lab Component Reference

The source catalog currently contains 33 registered component types. The Full system lab template contains 24 nodes and 29 typed edges; the generated contract also tracks 5 built-in templates and 31 preset entries.

The table names each Full System Lab component’s responsibility, the component-specific settings that shape its work, and the live evidence that confirms the setting had an effect.

ComponentResponsibility in the full labMain component settingsLive evidence
ClientGenerates browser demand and applies its own concurrency window and deadline before emitting HTTP work.Request rate, concurrency, response latency, deadlineStarted, in-flight, concurrency-limited, timed-out, and completed requests
Frontend AppServes the configured static share locally and forwards the remaining API traffic.Capacity, asset-cache hit rateStatic responses and API requests forwarded
Event ProducerGenerates event traffic, applies its source ceiling, and reports batch count without inventing extra events.Event rate, source capacity, batch sizeAccepted events, source rejects, batches, and emitted events
API AdapterConverts event envelopes into HTTP requests through decode, transform, and encode stages.Capacity, transform time, transform parallelismConfigured versus effective ceiling and transform rejects
API GatewayCombines browser and adapted HTTP traffic, then applies admission, burst, and route-deadline rules.Steady rate limit, burst budget, timeout, base and overload latencyAdmitted, rejected, forwarded, timed-out requests, and remaining burst tokens
Load BalancerReserves health-probe capacity and divides the remaining traffic equally across ready Service and Deployment paths.Capacity, probe rate per backendReady backend count, probe load, and routed throughput
ServiceExecutes application requests through a bounded thread pool and emits cache, SQL, event, and telemetry effects.Capacity, thread count, request time, telemetry rate, failure and recovery ticksBusy threads, effective ceiling, utilization, lifecycle state, and typed outputs
Kubernetes DeploymentReconciles desired, actual, and ready replicas, replaces failed Pods, and dispatches accepted traffic to ready children.Minimum and maximum replicas, target utilization, replacement detection delay, scale-down windowRecommended, actual, and ready counts plus controller actions and Pod dispatches
PodRepresents one readiness-gated application replica owned by the Deployment.Replica capacity, readiness delay, telemetry rate retained in the replica templateReadiness countdown, served requests, utilization, and parent dispatch
PostgreSQLSplits SQL demand into reads and writes that share a finite connection pool, then emits successful results to ETL.Read/write ceilings and latency, read share, connections, isolation, lock contention, provider-style presetActive pool use, reads, commits, retries, rejects, and result throughput
RedisServes cache checks from Service, Deployment, and Worker through one shared budget.Capacity, configured hit rate, TTL, memory limit, working setEffective hit rate, memory pressure, hits, misses, fallback, and dropped checks
ETL / JobExtracts successful database results, transforms bounded batches, and emits successful records as events.Capacity, batch size, transform error rateBatch count, average fill, rejected records, and emitted events
QueueBuffers Service and ETL events, dispatches jobs to Workers, and bounds retry and overflow state.Maximum backlog, delivery attempts, redelivery budgetBacklog, fresh and redelivered work, retry wait, overflow, and dead letters
WorkerConsumes queued jobs with configurable parallel slots and emits cache and telemetry effects.Per-slot capacity, concurrency, telemetry rateActive slots, fresh and retried jobs, utilization, and typed outputs
MonitoringSamples telemetry before ingest limits and derives a retained educational window without carrying business traffic.Sampling rate, ingest capacity, retention windowSampled-out units, ingested units, ingest drops, and retained units
Message BrokerPublishes events into a partitioned, replicated log and broadcasts the full delivered stream to every connected consumer group (pub/sub, distinct from Queue’s competing consumers).Partition count, per-partition append rate, replication factorActive partitions, consumer groups, per-group and total delivered records, ingest rejects
PostgreSQL Read ReplicaAsynchronously replicates writes from the primary and serves local reads. Replication lag climbs when primary write throughput exceeds the replica’s replication bandwidth; read staleness scales with lag.Local read capacity, replication bandwidth, connections, read latencyReplication applied, replication lag, read staleness, read rejects
CDN / Edge CacheSits in front of the Frontend, serving the hit share from the edge and forwarding only misses to origin. An origin shield collapses a slice of misses, and the stale-while-revalidate window shields a further share, so only a small fraction of client traffic reaches origin.Edge capacity, edge hit rate, origin shield, stale-while-revalidate windowEdge hits, origin forwarded, shielded, stale served, and origin-offload percentage
Circuit BreakerProtects the compute path: it watches the downstream failure share, trips open when it crosses the threshold, sheds for a cool-down, then half-opens a probe trickle before closing again.Trip failure rate, open cool-down ticks, half-open probe rate, pass-through capacityBreaker state, downstream failing share, shed volume, and cumulative trips
Object StorageStores and serves large objects for the Worker. Throughput is bounded by whichever binds first: the per-request ceiling or egress bandwidth divided by object size.Request ceiling, average object size, egress bandwidth, time to first byteObjects served, egress Mbps, active limiter, and storage rejects
Scheduled Job / CronFires a burst of work every N ticks instead of a steady stream, so downstream queues and autoscalers see spiky, time-varying load.Fire interval, burst size, interval jitter, maximum burst rateFiring/idle schedule state, burst size, next-fire countdown, and over-rate rejects

Every component also exposes the shared resilience policy: stress, degradation, crash, sustained-overload, recovery threshold, and recovery-tick settings. Frontend App, API Gateway, Service, Worker, API Adapter, and ETL / Job additionally expose generic workload replica bounds and scale-down stabilization. Those shared controls change the same runtime state and capacity evidence rather than creating a separate hidden simulation.

Pods are contained children rather than top-level edge endpoints: the Deployment accepts traffic at its boundary, dispatches to ready Pods internally, and aggregates their typed effects back through its own outputs. This keeps controller ownership distinct from ordinary network connections.

Not every declared port needs a peer, and the two signal paths that are wired here matter. Monitoring’s health output feeds the Deployment’s health input, so a saturated Monitor pulls the Deployment’s health signal down. The Deployment also aggregates owned Pod telemetry and emits it through its own telemetry output to Monitoring — the individual Pod telemetry ports are not routed out; the parent rolls them up, so the telemetry rate stays a property of the replica template while its effect still reaches Monitoring. Ports left without a compatible peer (for instance the second Worker’s SQL output, unused so only one Worker queries the store) simply carry no flow until connected.

Components and Why They Exist

Client, Frontend App, and API Gateway

These components define the intake boundary. The Client generates demand through a bounded concurrency/deadline window, the Frontend App can serve a static share locally, and the API Gateway admits traffic through its rate limit and burst budget. The Gateway separately reports requests that exceeded its modeled route deadline because forwarding work and caller-visible completion are not the same event. Use them to see why upstream limits matter: they protect downstream systems only when configured against the capacity below them.

Load Balancer and API Adapter

The Load Balancer reserves a visible part of its request budget for active backend probes, then divides business traffic equally across ready backend paths. A low-capacity backend therefore becomes pressured instead of becoming invisible to the routing and autoscaling model. The API Adapter converts event envelopes into HTTP work; its card separates the configured rate from the transform-limited effective rate, so a large configured number cannot mask a slower conversion stage.

Reading Flow and Runtime State

Every enabled edge carrying modeled throughput has a continuously moving pulse. Healthy connectors stay visually neutral so the moving dots, not an arbitrary highlighted route, show where modeled work is flowing. Pulses represent the model’s current throughput, not literal packets captured from a network.

Selecting any component makes the sidebar belong to that component: its metrics are sampled from its runtime profile and its timeline records named local operations, state changes, and controller actions. The bounded runtime log is an educational model record, not a connection to production infrastructure or an external telemetry backend.

Every output port can also be left on automatic behavior or given a throughput cap. A cap applies after the component does its own modeled work and before connected inputs receive it. For example, capping an Event Producer’s event-out at 120 makes the Queue receive 120 events/s even when the producer can generate more. For a fan-out, the cap is shared across that one output; cache-aside components apply cache and origin caps independently.

Service and Pod

The Service represents application compute with a bounded thread pool and a tick-based lifecycle. failureTicks controls how long overload must persist before degradation; recoveryTicks controls sustained low-load recovery. When you manually recover a safe component while the clock is paused, the simulator briefly advances the whole architecture for its configured verification ticks, then pauses again; if load is still unsafe, it shows the current stress and recovery threshold instead of pretending the component recovered. A Pod represents one runnable replica. Owned Pods share the Deployment’s replica template, so changing capacity or readiness delay on one owned Pod updates its siblings and future replacements. Readiness delay temporarily removes every affected replica from parent capacity, matching the distinction between running and ready work.

Kubernetes Deployment

The Deployment is a parent component, not just a visual group. It continuously reconciles actual Pods with policy. Deleting a Pod below minReplicas creates a replacement immediately. A failed Pod follows the configured replacement detection delay. Sustained load computes a recommended replica count at target utilization and clamps it between minimum and maximum. A Kubernetes-style per-tick limit commands the greater of doubling the current count or adding four, then creates those actual children in the same reconciliation pass. Pending Pods must become ready before another scale-up command; scale-down waits for a stabilization window. The card reports recommended, actual, and ready counts separately. Increasing maximum replicas expands the compound shell and contained Pod grid, moving conflicting top-level peers aside to keep the diagram readable. The same policy engine is available to any registered parent and child types.

Queue and Worker

The Queue stores work that has arrived but has not yet been completed. Workers first drain up to their aggregate healthy capacity; the remainder is retained as backlog up to maxBacklog. Arrivals beyond that bound are rejected as overflow, while the model derives retry-wait, redelivery, and dead-letter estimates from the configured delivery-attempt and redelivery budgets. Adding worker capacity or lowering producer rate reverses backlog growth.

PostgreSQL, Redis, and Monitoring

PostgreSQL is the durable system of record. It models separate read and write ceilings, a finite shared connection pool, read/write latency, transaction isolation, and lock-contention retries; it does not present a misleading generic request-rate capacity. Its query results can feed ETL without weakening the typed-port contract. Redis separates configured hit rate from effective runtime quality: TTL and memory pressure influence the read-hit fraction, while one shared capacity budget controls accepted cache checks across callers. Monitoring samples before applying ingest capacity and derives a retained telemetry window. ETL groups successful records into visible batches and exposes average fill and rejected records.

Message Broker vs Queue

Queue and Message Broker share the “buffer events; hand jobs to workers” role but model different delivery semantics, and the demo makes both visible on the same lab. A Queue is a competing-consumer channel: one job goes to one worker, and adding workers splits the arrival stream. A Message Broker is pub/sub: every connected worker acts as an independent consumer group, and each group receives the full stream — adding a consumer group increases total delivered records, not each group’s share. The broker card names both numbers separately: per-group records this tick and the total across all groups. Broker capacity is derived from partitionCount × partitionWriteRps / replicationFactor — increasing replication trades write throughput for durability, which is the intended teaching moment.

PostgreSQL Read Replica

The Read Replica pairs with the primary PostgreSQL to model the asynchronous replication → local-read pattern. A dedicated sql-replication edge carries the primary’s committed writes to the replica; the replica applies as much as its replicationBandwidthTps allows each tick, and everything else accumulates as replication lag. When lag grows, read staleness climbs — the ratio a real caller would perceive as “how far behind is my read from the write I just made”. The card shows both a lag bar and a staleness percentage. This is the first component in the demo where a slow downstream (bandwidth) directly causes a time-based correctness dynamic (stale reads), not just capacity rejection.

Latency

Every component reports a modeled latency, and every request path reports an end-to-end figure. Each is derived, not measured: a component’s latency is its configured service time plus a queueing wait, where the wait is either Little’s Law (backlog ÷ throughput) for the buffers that hold a queue, or the M/M/1 waiting time service × u ÷ (1 − u) for finite-capacity compute. The single most important thing this teaches is the knee: as utilization u climbs toward 100%, that 1 ÷ (1 − u) term explodes — latency at 70% load is modest, but at 95% it is many times larger. That non-linear cliff is the reason capacity planning targets headroom, and it is the thing a static diagram cannot show.

Path latency accumulates along the critical path: a component that fans in from several upstreams waits for the slowest branch, not the sum. Only synchronous request types (HTTP, SQL query/result, cache commands, record commands, search queries, and data) add to a caller’s latency — fire-and-forget work (events, jobs, telemetry, replication, health, and control) never makes the caller wait, because the typed-port contract knows which edges are asynchronous. Where a component declares a request deadline (the Client and Gateway timeoutMs), its latency is clamped there and the reported limiter reads deadline-clamp — the same deadline that drives its timeout counters.

Set the serviceLatencyMs (or the component’s existing service-time field, such as the Service requestLatencyMs or the Adapter transformMs) and watch both the ⏱ chip on the card and the Latency block in the Inspector, which shows the service, wait, node, and end-to-end figures plus the active limiter and the exact equation.

Latency is also visible in motion: the forward request dots crawl in proportion to a component’s own latency, so an edge is animated as slowly as the slower of the two components it touches. Raising a component’s service time — with the Chaos Lab’s Slow incident, or by hand — makes the dots on its edges visibly drag, even though nothing is dropped. Latency stays read-only: slowing a component changes how fast the dots move, never how many flow, so throughput and rejection are unaffected (it is purely a timing signal, not backpressure).

A component that is meaningfully slower than its own normal is marked directly: its card gains a pulsing dashed orange outline and a ⏱ N× slow badge shown next to its health badge — because slowness is a latency signal, not a health state, a card can read “healthy” and ”⏱ 5× slow” at the same time. The mark never recolors the state border, so you can always tell a slow-but-healthy component from a degraded one.

Every synchronous call is drawn as a round trip: the dot travels to the callee, dwells there while it works, then returns to the caller as a hollow ring in the edge’s own color. Asynchronous work (events, jobs, telemetry, replication) flows one way and never returns — so on every tick you can see, not just read, why async never makes a caller wait. The dwell length scales with how slow the callee is relative to its own normal: a fast dependency turns around almost instantly, while a component you have slowed sits there visibly, a soft breathing ring marking the wait. That is the slowness signal — how long the dot lingers, not whether it exists. It is also the visual answer to “how many requests were dropped by slowing this?” — none; they are delayed, and the response comes back late. Red is never used for a response — a red returning dot always means a rejection, a colored one a slow-but-successful reply.

System Status Bar

A compact status strip runs along the bottom of the canvas and always reflects the live architecture at a glance: client-completed throughput, total work being dropped on edges, the current constraint, and the longest end-to-end path latency. When a constraint is active, select its label to reveal the component and inspect the evidence behind it: the visible symptom, immediate limiter, affected flow when an active edge proves one, and a safe experiment to try next.

“Current constraint” describes the strongest evidence in the present runtime snapshot. It is not a claim about the original historical root cause: a downstream component may be the active constraint after an earlier incident elsewhere. The simulator therefore names the observed limiter and supported peer evidence instead of inventing a multi-hop causal story.

Live Metrics

The right sidebar’s Live Runtime view keeps four separate model-backed cards for the most recent 60 ticks: Throughput, Drops, Latency, and Queue Backlog. Each card uses its own scale and visual, so abrupt changes do not cross or obscure another metric. Their latest values use green for normal, amber for pressure, red for breach, or neutral when the simulator has no truthful threshold. Select Expand Metrics for the wider operational dashboard and its shared event timeline. A zero drop rate is normal, while any modeled loss is a breach. Select a component or connection to replace the system view with only that item’s modeled evidence; an edge intentionally labels latency and backlog as not independently modeled.

Configuration edits, topology changes, Chaos actions, restores, and lifecycle transitions appear as tick-aligned markers. This is a session-only deterministic runtime history, not exported project state, production telemetry, or a performance benchmark. Loading or importing a different architecture starts a new history.

For a more operational-looking run, enable Realistic traffic variation in the Run tab. It varies only external source demand by up to 10% around the configured target, using the same repeatable pattern for the same architecture and tick. Downstream changes remain simulated consequences, not decorative noise. Where a selected scope has a direct source target, the dashboard’s dashed throughput reference shows that configured baseline.

Resilience Experiments

The simulator can model reversible crash, traffic-surge, and latency incidents against the selected architecture. These experiments are useful because they connect a changed condition to backlog, rejection, latency, and recovery evidence; they are transient runtime events rather than production integrations or exported business state.

Rejection Visibility

When a component is degraded, unavailable, or recovering, the traffic its upstream peers keep sending is refused — and now you can read how much, not just see the red dots. Every component reports two derived numbers: how much of its own output is being refused downstream and how much of what it is offered it is refusing upstream. A healthy sender feeding a failed component no longer looks fine: its card shows ⤺ N/s refused by <peer>, naming the component turning its work away, while the failed component shows ✕ N/s rejected. The rate is also drawn in red on the edge itself, so the number sits exactly where the rejected-traffic particles animate. The Inspector’s Rejection block gives both totals with the worst peer named on each side. These marks appear only when something is actually being dropped, so a healthy architecture stays clean.

Edge Cases and Misconceptions

  • Reported latency is a model, not a measurement. It is a deterministic queueing approximation (Little’s Law and M/M/1), useful for teaching the shape of overload — not a percentile distribution. There is deliberately no p99: this engine does not model a random arrival process, so it does not claim one.
  • A valid arrow is not always a valid integration. Event, HTTP, job, data, telemetry, health, and control signals need compatible ports. Use a specific adapter when the contract changes.
  • An unconnected component receives no upstream work. Positioning two cards beside one another does not create a dependency. Only an enabled typed edge propagates load and state.
  • Rate limiting is not a cure for every overload. A gateway limit above the Service capacity still lets too much traffic through. Capacity planning must follow the full request path.
  • Queues trade immediate failure for delay and retained work. They are valuable only when backlog is monitored and workers can eventually drain it.
  • A 100% configured cache hit rate can still become a lower effective rate. TTL and memory pressure reduce cache quality. Utilization compares offered cache checks with capacity and may exceed 100%, producing fail-open overflow or rejection.
  • A parent controller has a delay. A Deployment cannot replace a failed Pod before the replacement detection delay elapses. While the controller waits and the replacement becomes ready, remaining healthy replicas carry more load.
  • Running is not the same as ready — and starting up is not recovering. A replica the controller creates while the clock is advancing shows a blue initializing state and contributes no ready capacity until its readiness delay expires — it is not labeled “recovering”, which would wrongly imply it had crashed. A component you add while the clock is paused is ready immediately (no simulated time is passing to initialize it), so wiring it shows traffic at once; the readiness ramp is reserved for live time and autoscaling.
  • Some components are contained, not standalone. A Pod exists only inside a Kubernetes Deployment. The library will not drop one onto the empty canvas — select a Deployment first and the Pod is added as an owned replica, so no orphaned replicas can exist.
  • Owned Pods are replicas, not unrelated servers. Editing an owned Pod changes the Deployment’s replica template, so siblings, scale-ups, and replacements keep the same workload capacity and readiness configuration.
  • Sampling and ingest rejection are different losses. Monitoring first discards unsampled telemetry, then may drop sampled telemetry that exceeds ingest capacity; retention changes stored history, not business traffic.
  • Bigger batches do not create records. ETL batch size changes invocation count and average fill while conserving accepted and rejected records.
  • A provider preset is a starting point. The PostgreSQL RDS-style preset supplies plausible configuration values, but it does not reproduce every provider or runtime rule.
  • Broker fan-out is not queue split. Adding a worker to a Queue divides the arrival stream; adding a consumer group to a Message Broker gives that new group the whole stream. If broker total delivered records climbed when you added a group but per-group stayed the same, the fan-out is working as intended.
  • A read replica does not eliminate write pressure — it displaces it in time. Under high primary write throughput, the replica’s replication lag grows; local reads served from the replica become stale by the same amount. Reducing lag means either raising replicationBandwidthTps or lowering primary writes.

The Reactive Architecture Builder simulator uses Full system lab as the concrete reference for tracing local, downstream, and parent effects across the complete built-in catalog.

Common Questions

Why should architecture components have typed ports?

Typed ports make the contract between components explicit. An HTTP request, an event, a job, telemetry, and a control signal have different delivery and failure behavior. Blocking an incompatible connection forces the architecture to show the adapter that performs the transformation rather than hiding it in an arrow.

What happens when an API Gateway sends more traffic than a service can handle?

The Service becomes pressured as offered work reaches its effective capacity. If overload lasts for the configured number of ticks, its lifecycle advances to degraded and can eventually become unavailable. A Gateway limit can cap offered traffic before the Service receives it, but a limit above downstream capacity still allows overload to propagate.

Why does a queue help with backpressure?

A queue decouples arrival rate from processing rate. When producers outpace workers, backlog grows up to the configured bound. After that bound is full, new work is rejected and recorded as dropped; a queue buys recovery time but does not create unlimited capacity.

Why can Redis show a high hit rate while PostgreSQL still has traffic?

For one cache-aside dependency, only cache misses and configured fail-open overflow reach PostgreSQL. PostgreSQL can still receive work from another direct query path. A high configured hit rate is not a promise of a high effective hit rate: short TTLs and a working set above memory limit reduce cache quality before the database fallback is calculated.

How does a Kubernetes Deployment respond when a Pod dies?

A Deployment observes child health, waits for its replacement detection delay, then creates a replacement Pod from the same replica template. A new or reconfigured Pod contributes no ready capacity until its readiness delay expires. The controller distinguishes its autoscaling recommendation, actual children, and ready children while scaling between the configured minimum and maximum.

Why can configured and effective capacity differ?

Configured capacity is only one possible limit. A Service can be constrained by its thread count and request time, an API Adapter by transform workers and transform time, a Load Balancer by probe overhead, and a Deployment by ready Pod capacity. The active limiter is the smallest applicable ceiling, so the model reports configured, derived, and effective capacity separately.

Is this simulator an exact model of AWS, GCP, Kubernetes, or PostgreSQL?

No. It uses realistic names, capacity limits, health states, typed contracts, and controller behavior to teach cause and effect. The PostgreSQL RDS-style preset is an educational default, not a promise of provider-perfect runtime, pricing, scaling, or service-level behavior.