Where Did We Start?
Suppose you built a simple web application.
In the beginning, your architecture looks like this:
Users
↓
Internet
↓
Single Server
├── Web Application
└── Relational Database
When 10 users visit your site, everything runs smoothly.
When 100 users visit, it still works well.
Then traffic begins to explode:
↓
10,000 Users
↓
100,000 Users
↓
1,000,000 Users
Now, that single machine experiences severe hardware strain across its CPU cores, RAM memory, disk I/O, and network bandwidth.
This brings us to the quintessential engineering question:
"What do we do when user traffic surges exponentially?"
The answer is:
What is Scaling?
Scaling is the systematic engineering process of expanding a system's capacity to gracefully handle an ever-increasing workload without degrading performance or crashing.
Suppose a single server can comfortably process 1,000 HTTP requests per second.
If incoming customer traffic spikes to 2,000 requests per second, the system must expand its processing throughput or begin dropping requests. This is the fundamental challenge of scaling.
Two Fundamental Philosophies of Scaling
There are two primary paradigms to increase system capacity:
Making a single existing machine more powerful by adding more CPU cores, more RAM, and faster NVMe storage.
Adding more physical or virtual machines to form a cooperative cluster and distributing traffic across them.
Vertical Scaling (Scale Up)
Suppose your initial server has hardware specifications of:
Initial Hardware:
4 vCPUs
8 GB RAM
To handle greater traffic, you upgrade the hardware to a higher tier:
Upgraded Hardware:
16 vCPUs
64 GB RAM
This is Vertical Scaling: making the exact same machine physically or virtually larger.
The Advantages of Vertical Scaling
The primary virtue of vertical scaling is extreme simplicity:
- Zero Architectural Changes: Your application code remains identical. The software still runs as a single process connecting to localhost.
- No Distributed Coordination: You avoid network partitions, complex distributed transactions, and multi-node session synchronization.
- Low Operational Overhead: Managing one server requires minimal DevOps tooling compared to orchestrating dozens of nodes.
For early-stage startups and moderate workloads, scaling vertically is often the most pragmatic and cost-efficient choice.
The Fatal Limitations of Vertical Scaling
Despite its simplicity, vertical scaling hits severe physical and financial boundaries:
1. Hardware Ceiling
You can upgrade from 8 GB to 64 GB, or even 512 GB. But you cannot purchase a machine with infinite CPU cores or unlimited RAM bus speed. Motherboards and chipsets possess hard physical limits.
2. Exponential Cost Curve
The cost of ultra-high-end enterprise servers grows non-linearly. A server with 128 cores costs substantially more than four independent 32-core commodity servers combined.
3. Single Point of Failure (SPOF)
If your single supercomputer experiences a power supply blowout, kernel panic, or OS crash, 100% of your users face complete downtime.
Therefore, relying solely on larger machines fails to solve the scaling challenge at high volume.
Horizontal Scaling (Scale Out)
Now let's examine the alternate engineering paradigm.
Instead of buying one giant server, we provision a fleet of standard, commodity servers:
Server A (4 vCPUs, 8 GB RAM)
Server B (4 vCPUs, 8 GB RAM)
Server C (4 vCPUs, 8 GB RAM)
Server D (4 vCPUs, 8 GB RAM)
This is Horizontal Scaling (Scale Out):
The Routing Dilemma: Which Server Receives the User?
With multiple servers running concurrently, an immediate architectural problem arises.
When a client's browser sends an HTTP request:
GET /products
Which exact machine should accept and process the packet?
┌── Server A
├── Server B
Client ──> ?????? ──┼── Server C
└── Server D
Clients cannot be expected to know the private IP addresses of dynamic server fleets. To solve this routing puzzle, we introduce:
The Load Balancer Returns
We encountered the Load Balancer in Lesson 9 as a reverse proxy.
Here in scaling architecture, the Load Balancer serves as the single public entry point that terminates inbound client traffic and distributes requests across the internal pool of backend application servers:
┌── Server A (Private IP)
│
User ──> [Load Balancer] ─────┼── Server B (Private IP)
(Public IP) │
├── Server C (Private IP)
│
└── Server D (Private IP)
The outside world communicates exclusively with the Load Balancer's public IP address, keeping the internal topology decoupled and private.
Load Balancing Algorithms & Traffic Distribution
How does a load balancer decide which node receives each incoming request?
The simplest algorithm is Round Robin, which distributes requests sequentially:
Request 1 ──> Server A
Request 2 ──> Server B
Request 3 ──> Server C
Request 4 ──> Server D
Request 5 ──> Server A (Cycles back)
In production systems, load balancers implement advanced routing strategies:
- Least Connections: Directs traffic to the server currently processing the fewest active TCP connections.
- Weighted Round Robin: Assigns more traffic to beefier machines (e.g. Server A with 16 cores gets 3x traffic of Server B with 4 cores).
- IP Hash: Hashes the client's IP address to map specific users consistently to particular backend nodes.
What Happens If Server C Crashes?
Consider a scenario where one node experiences hardware failure:
Server A: Healthy ✅
Server B: Healthy ✅
Server C: Dead ❌ (Kernel Panic / Network Loss)
Server D: Healthy ✅
The load balancer executes continuous background Health Checks (e.g., pinging GET /healthz every 2 seconds).
Upon detecting that Server C is unresponsive, the load balancer immediately evicts it from the active rotation pool:
A → B → D
End-users experience zero disruption. This milestone brings us to:
Availability and Scalability Are Not Synonymous
Engineers must carefully distinguish between these two foundational metrics:
The ability to handle increased volume of requests and data by expanding system capacity.
The percentage of time a system remains operational and accessible to users without interruption.
Consider this comparison:
- A single 128-core supercomputer can process 1,000,000 requests/sec (Highly Scalable). But if its power cord is pulled, uptime drops to 0% (Zero Availability).
- A cluster of five 16-core commodity servers provides both horizontal scalability and high availability: if two servers fail, the remaining three continue serving traffic seamlessly.
What is a Stateless Application?
Here lies the cornerstone requirement of modern horizontal scaling.
Suppose a user logs into your site, and the load balancer routes Request 1 to Server A. Server A stores the user's shopping cart inside its local RAM memory.
Two seconds later, the user clicks "Checkout", and the load balancer routes Request 2 to Server B.
What happens? Server B's RAM knows nothing about Server A's memory! The shopping cart appears completely empty, and the user is unexpectedly asked to log in again!
To prevent this failure, scalable architectures must be designed as:
Does "Stateless" Mean Servers Have No State at All?
No. Software cannot function without data.
"Stateless" specifically means that the application execution tier does not anchor state to its local ephemeral machine memory:
State is NOT kept in:
❌ Server A local RAM variables
❌ Server B local disk temp files
State IS stored in shared, dedicated data services:
✅ In-Memory Distributed Cache (Redis)
✅ Relational Database (PostgreSQL)
✅ Cloud Object Storage (S3)
Because state is externalized, application servers can be spun up or destroyed dynamically without losing a single byte of user information.
Where Should User Sessions Be Stored?
When a user authenticates, where does their session identity live?
Modern web engineering offers two industry-standard approaches:
1. Centralized Session Store
All application servers share a centralized, blazing-fast Redis cache cluster. When any server receives a request, it queries Redis for the session token in <1 ms:
Server A ─┐
Server B ─┼──> Centralized Session Store (Redis Cluster)
Server C ─┘
2. Stateless Token Authentication (JWT)
The user's authentication details and permissions are cryptographically signed into a JSON Web Token (JWT) and stored in the user's browser. With every request, the token is sent in the HTTP header, allowing any server to verify the signature mathematically without querying a database.
What Are Sticky Sessions (Session Affinity)?
Before stateless architectures became universal, legacy systems often used Sticky Sessions:
The load balancer inspects a cookie or client IP address and guarantees that all consecutive requests from User A are routed strictly to Server A:
User A → Server A | User A → Server A | User A → Server A
While this allows local in-memory session variables, it creates catastrophic scaling problems:
- If Server A crashes, all users pinned to it lose their active sessions immediately.
- Traffic becomes unbalanced when heavy users congregate on a single node.
Consequently, truly modern cloud-native systems prioritize stateless application tiers.
The Return of the Cache: Scaling's Greatest Multiplier
Suppose every inbound HTTP request executes an SQL query directly against the primary database:
100,000 Inbound Requests
↓
PostgreSQL Database (Disk I/O and Connection Exhaustion!)
The database quickly bottlenecks. By placing an in-memory Cache (Redis) in front of the database, the equation transforms:
100,000 Inbound Requests
↓
Redis Cache (In-Memory RAM <1ms)
↓
Most requests served instantly!
↓
(Only Cache Misses fall through to the Database)
Caching is the single most potent tool to absorb massive traffic spikes without re-architecting your entire database tier.
The Mathematical Scaling Effect of Caching
Consider the concrete mathematics of a high-performance caching layer:
Suppose 100,000 users visit your store's homepage simultaneously. If your cache achieves a 95% Cache Hit Ratio:
100,000 Requests
│
▼
Redis Cache (RAM)
│
┌────────────────┴────────────────┐
▼ ▼
95,000 Cache Hits ✅ 5,000 Cache Misses ❌
Served in <1.5 ms Processed by Database
(Zero disk I/O load!) (Easily handled by DB)
The database was spared 95,000 heavy queries! It only had to process 5,000 queries, keeping CPU utilization cool and headroom wide open.
Scaling the Cache Itself
What happens when your platform expands so aggressively that even a single Redis cache node experiences memory or network saturation?
The cache itself must scale horizontally into a multi-node cluster:
Redis Cache Node A (Keys: a - h)
Redis Cache Node B (Keys: i - p)
Redis Cache Node C (Keys: q - z)
Keys are partitioned across cache nodes using advanced hashing algorithms such as Consistent Hashing, ensuring minimal key redistribution when nodes are added or removed.
Can Databases Scale Horizontally?
Yes—but horizontal database scaling is vastly more difficult than scaling application servers.
Why? Because application servers are stateless, while databases maintain state, disk persistence, and rigorous physical invariants:
- ACID Consistency: Transactions must never violate invariants.
- Relational Joins: Foreign keys link data across multiple tables.
- Concurrency Locks: Preventing two users from buying the same stock simultaneously.
Consequently, database scaling requires specialized architectural patterns.
What is a Read Replica?
Most web applications are heavily read-dominated. In typical consumer applications, 90% to 95% of database traffic consists of SELECT queries, while only 5% to 10% are write mutations (INSERT, UPDATE, DELETE).
To alleviate read pressure, we pair our authoritative Primary Database with read-only copies called Read Replicas:
Primary Database (Master)
│
▼ (Asynchronous WAL Stream)
Read Replica 1 & Read Replica 2
Whenever data changes on the Primary, changes stream asynchronously to the replicas, keeping them in sync.
Read Replica Architecture & Query Splitting
In this architecture, application servers direct queries based on operation type:
Application Servers
/ (Writes & Transactions) \ (Read Queries)
▼ ▼
Primary DB Load Balancer
(PostgreSQL) │
│ ┌───────┴───────┐
▼ ▼ ▼
(Async Stream) Replica 1 Replica 2
All data-modifying queries execute on the Primary DB, while heavy search, listing, and reporting queries are distributed across read replicas.
The Reality of Replication Lag
Because replication between primary and replicas is typically asynchronous to maintain write speed, a tiny time delay exists called Replication Lag.
Consider this sequence of events:
Initial Inventory: Stock = 10
1. Customer purchases 1 unit:
Primary DB executes: UPDATE products SET stock = 9 (Instant Commit)
2. During the next 100 milliseconds:
Primary DB: Stock = 9
Read Replica: Stock = 10 (Lagging behind by 100 ms!)
If a user immediately refreshes their order confirmation page and reads from the lagging replica, they might see the outdated stock count! Software architects solve this by routing post-write reads to the Primary DB for a brief grace period.
Why is Write Scaling So Difficult?
Read queries can easily be distributed across dozens of replicas. But scaling write throughput is significantly more complex.
What happens when your platform processes 10,000 concurrent write transactions per second?
A single Primary database must sequentially flush Write-Ahead Logs (WAL) to physical disk, manage exclusive row locks, and update index trees. When write volume exceeds a single machine's physical limits, engineers must consider:
What is Database Sharding?
Suppose your user database holds 1 billion accounts.
Instead of forcing a single database instance to store all 1 billion rows, the dataset is split horizontally across multiple independent database instances called Shards:
User Database
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ ▼
Shard A Shard B Shard C
(User IDs 1 - 333M) (User IDs 334M - 666M) (User IDs 667M - 1B)
Each shard runs on separate physical hardware with its own CPU, memory, and disks, distributing both storage and write workloads.
The Advantages of Sharding
Sharding breaks through the physical ceiling of single-machine limitations:
- Virtually Infinite Storage: Need to store 500 TB? Distribute the data across 50 shards of 10 TB each.
- Horizontal Write Scalability: 10 shards can sustain 10x the write throughput of a single master node.
The Severe Costs & Complexities of Sharding
Sharding is a double-edged sword that introduces immense operational complexity:
- Cross-Shard Queries: If a query needs to find all users over age 30, the system must dispatch parallel queries to every shard and aggregate the results (Scatter-Gather), destroying latency.
- Cross-Shard Transactions: Maintaining ACID guarantees across multiple physical database machines requires complex Two-Phase Commit (2PC) protocols that are notoriously slow.
- Resharding: Rebalancing data across shards when one shard becomes full is an operational nightmare.
Why Do We Need Message Queues?
Consider what happens when a customer clicks "Place Order":
Application must execute:
1. Save order to database ........... (35 ms)
2. Charge credit card via Stripe .... (450 ms)
3. Send email receipt via SMTP ...... (1,200 ms)
4. Generate PDF invoice & watermark . (850 ms)
5. Push push-notification ........... (300 ms)
6. Emit data analytics event ........ (200 ms)
If all of these tasks are executed synchronously within the user's HTTP request:
Worse: If the third-party email server is down, the entire checkout fails! To decouple slow, non-critical tasks from user-facing responses, we use a Message Queue:
User ──> API ──> Save Order (25ms) ──> Return HTTP 200 OK immediately!
│
▼
Push Jobs to Message Queue:
├── Send Email Job
├── Generate PDF Invoice Job
└── Analytics Event Job
What is a Message Queue?
The classic Producer-Consumer topology:
[Web Application] ──(Push Job)──> [Message Queue] ──(Pull Job)──> [Background Worker]
(Producer) (Buffer) (Consumer)
Popular message queues include RabbitMQ, Apache Kafka, Amazon SQS, and Redis Streams.
What is a Background Job?
A Background Job (or worker task) is any unit of computational work that can be deferred and processed asynchronously outside the lifecycle of the user's immediate HTTP request.
Consider this user interaction:
User clicks: "Export 10,000 Transcripts to PDF"
App responds in 15ms: "Your export has started. We will email you the download link!"
Queue holds task: {"action": "render_pdf", "user_id": 42}
Worker processes task: Generates PDF over 12 seconds → Uploads to S3 → Dispatches email.
The web server never had to hold an open HTTP connection for 12 seconds, preventing server thread starvation.
Scaling Queues and Background Workers
Message queues act as elastic shock absorbers against unexpected traffic surges.
If task volume grows from 100 jobs/sec to 10,000 jobs/sec, workers can be scaled horizontally independently of web servers:
┌── Worker 1
├── Worker 2
Message Queue ────────┼── Worker 3
(10,000 Jobs Queue) ├── Worker 4
└── Worker N (Auto-scaled based on queue depth)
The message queue buffers excess jobs safely in memory and disk without dropping tasks, draining the backlog as workers catch up.
Resilience: Handling External Service Downtime
Suppose your third-party email provider (e.g. SendGrid or SES) experiences an unexpected 15-minute global outage.
Without a queue, every single checkout attempt on your site fails with a 504 Gateway Timeout, destroying revenue.
With a message queue:
1. Customer checkout succeeds in 25ms.
2. Email job is safely held inside the queue.
3. Worker detects SendGrid failure → Retries using Exponential Backoff.
4. When SendGrid recovers 15 minutes later, all queued emails are delivered!
Queues isolate your critical core workflows from transient external failures.
Is a Queue a Replacement for a Database?
No. Queues and databases fulfill completely different architectural roles:
Permanent, authoritative, structured ledger of your business. Data is meant to persist indefinitely.
Ephemeral transit buffer for work distribution. Once a job is processed, it is deleted from the queue.
What is Failover?
Suppose your primary database suffers an unexpected hardware crash or power loss:
Primary DB (Master) ──> ❌ CRASHED!
System automated watchdog detects loss of heartbeat
│
▼
Promotes Read Replica 1 to become the NEW PRIMARY MASTER!
This automatic promotion of a standby redundant node to take over active duties is called Failover.
Failover can be manual (requiring engineer intervention) or fully automated using consensus orchestrators (such as Consul, Raft, or Kubernetes).
What is Redundancy?
Redundancy is the engineering practice of provisioning duplicate, interchangeable components so that no single failure can halt the broader system:
Redundant Application Servers: [Server A, Server B, Server C]
Redundant Power Supplies: [PSU 1, PSU 2]
Redundant Network Links: [Fiber Uplink A, Fiber Uplink B]
Redundant Database Nodes: [Primary Master, Standby Replica]
Redundancy is the absolute prerequisite for high availability.
Single Point of Failure (SPOF)
Consider this architecture:
Server A, Server B, Server C (3 Stateless Nodes)
│
▼
Single Database (Only 1 instance) ──> ❌ Dies!
Even though you scaled your application servers to three instances, you still have only one database. When that single database dies, the entire platform collapses.
A Single Point of Failure (SPOF) is any non-redundant component whose failure will bring down the entire system. High-availability architecture is the continuous process of identifying and eliminating SPOFs.
Evolution to a Scalable Multi-Server Architecture
Observe how dramatically our simple architecture has transformed:
Users ──> Single Server (App + DB)
Users ──> CDN ──> Load Balancer
├── Server A
├── Server B
└── Server C
│
▼
Redis Cache ──> DB Cluster
The web application tier is now horizontally scalable, fault-tolerant, and stateless.
Scaling to Hyper-Growth
As traffic scales towards millions of active users, specialized systems join the ecosystem:
Global Users
↓
Edge CDN & DDoS Protection (Cloudflare)
↓
Layer 7 Load Balancer
↓
Stateless Web/API Server Fleet
↓
In-Memory Cache Cluster (Redis)
↓
Primary-Replica Database Cluster (PostgreSQL)
↓
Cloud Object Storage (AWS S3)
↓
Search Engine Cluster (Elasticsearch)
↓
Message Queue (RabbitMQ / Kafka)
↓
Asynchronous Background Worker Pool
Your application is no longer a single program running on a computer. It has become a:
What is a Distributed System?
To the student visiting Byteion Academy, they are simply loading a webpage. Beneath the surface, dozens of networked machines in different racks and data centers are cooperating to render every frame.
The New Challenges of Distributed Systems
A single machine is conceptually straightforward: function calls succeed or throw immediate errors. In a distributed cluster with 100 machines, reality becomes significantly more complex:
- Network Partitions: Cables can be severed or switches can misroute packets, isolating nodes.
- Partial Failure: A node might not be dead, but merely responding slowly, tying up upstream connections.
- Data Consistency: Reconciling state when messages arrive out of order across network hops.
- Observability: Debugging an error requires distributed tracing across dozens of microservices.
Why Latency Dominates Distributed Design
When software runs on a single machine, memory lookups take nanoseconds.
In a distributed architecture, every communication between tiers incurs a Network Hop:
App Server ──(Network Hop: 1ms)──> Redis Cache
App Server ──(Network Hop: 2ms)──> PostgreSQL Database
App Server ──(Network Hop: 4ms)──> Elasticsearch
App Server ──(Network Hop: 85ms)─> Third-Party Payment Gateway
If your application makes 10 serial network calls to process a single web request, your baseline latency automatically exceeds 100 milliseconds regardless of how fast your CPU is. Managing network hops is paramount.
Synchronous vs. Asynchronous Communication
A core optimization in distributed systems is converting blocking synchronous requests into non-blocking asynchronous events:
App → Service → Waits idle... → Response returned.
High latency, tight coupling.
App → Queue → Returns immediately! → Worker handles processing in background.
Ultra-low latency, loosely coupled.
Is Scaling Just "Adding More Servers"?
Definitely not.
Adding 100 servers to run an unindexed SQL query that performs a sequential disk scan across 100 million rows will not make your app fast—it will simply exhaust your database connection pool 100 times faster!
Case Study: The Scaling Evolution of an Education Platform
Observe how an application grows over time:
Single $10/month VPS hosting Node.js and PostgreSQL together. Simple, zero complexity.
Load Balancer + 3 Stateless Web Servers + Dedicated Redis Cache + Independent PostgreSQL DB.
Global Anycast CDN + Auto-scaling Web Cluster + Redis Cluster + Primary-Replica DB with Sharding + S3 Video Streaming + Elasticsearch + RabbitMQ Worker Pool.
An Essential Systems Perspective
When looking at a modern enterprise architecture diagram, never dismiss components as "buzzwords":
Every component is a direct mathematical answer to a physical constraint.
The Full Lifecycle of a Scaled Request
When a student clicks "Watch Lesson 17", observe the orchestration:
1. Browser ──> DNS Resolver (Lesson 6) ──> Returns nearest Anycast IP
2. Browser ──> CDN Edge (Lesson 9) ──> Terminates TLS 1.3 Handshake (Lesson 8)
3. CDN forwards dynamic API request to origin Load Balancer (Lesson 10)
4. Load Balancer health-checks pool and routes to least-loaded App Server (Lesson 17)
5. App Server checks Redis Cache for lesson metadata (Lesson 16) → Cache Hit (<1ms)!
6. Browser parses JSON and requests video stream from CDN & S3 Storage
7. User marks lesson completed → Write transaction commits to Primary DB
8. App pushes "Issue Certificate" event to Message Queue → Background worker generates PDF!
The Three Essential Scalability Questions
Whenever you evaluate any software architecture, ask these three fundamental questions:
Today's Evolutionary Mental Model
Every massive internet application progresses through this evolutionary journey:
Single Server (App + DB)
↓
Vertical Scaling (Bigger Box)
↓
Separate DB from App Server
↓
Load Balancer + Multiple App Servers
↓
Stateless Architecture (Session in Redis)
↓
Read Replicas for Database
↓
Message Queues & Background Workers
↓
Database Sharding & Polyglot Storage
↓
Globally Distributed Multi-Region Cloud
Key Architectural Definitions
The Grand Panoramic Picture of Course 08
Look how far we have traveled since Lesson 1:
Physical Cables & Optical Waves (Lesson 2)
↓
MAC, IP & DHCP Addressing (Lesson 3)
↓
Packets, Routers & Routing Tables (Lesson 4)
↓
TCP, UDP & Sockets (Lesson 5)
↓
DNS Resolution (Lesson 6)
↓
HTTP Protocol (Lesson 7)
↓
HTTPS & TLS 1.3 Cryptography (Lesson 8)
↓
CDNs & Reverse Proxies (Lesson 9)
↓
NAT & Firewalls (Lesson 10)
↓
WebSockets & Real-Time Streaming (Lesson 11)
↓
BGP & Global Autonomous Systems (Lesson 12)
↓
Browser DOM/CSSOM Rendering Engine (Lesson 13)
↓
REST APIs & Client-Server Contracts (Lesson 14)
↓
Databases, SQL, B-Trees & ACID (Lesson 15)
↓
Cache, Object Storage & Search Engines (Lesson 16)
↓
Scaling, Load Balancing & Distributed Systems (Lesson 17)
You now possess a complete mental map of the internet, from undersea fiber optics to global distributed cloud architectures!
Up Next: The Foundation Beneath the Cloud
Throughout this course, we repeatedly referenced the word "server".
But what actually constitutes a modern server?
- Do cloud companies buy physical computers for every website?
- How does a Hypervisor divide a physical motherboard into multiple Virtual Machines (VMs)?
- How do Docker Containers isolate software without the overhead of a full virtualized operating system?
In the next lesson, we dive deep into the fundamental building blocks of modern cloud computing:
Lesson 18 — Server, Virtual Machine & Container: How Modern Computing Infrastructure is Built
We will explore:
Physical Hardware Server
↓
Hypervisor (Type 1 & Type 2)
↓
Virtual Machines (KVM, VMware)
↓
Linux Namespaces & Cgroups
↓
Docker Containers
↓
Container Orchestration (Kubernetes)
Get ready to discover the invisible virtualization layers that power the entire modern cloud!
Interactive Lab: System Scaling, Message Queues & Distributed Failover Simulator
Simulate Scale-Up vs Scale-Out stress tests, synchronous blocking vs asynchronous queues, and automated database failover
Knowledge Check: Test Your Understanding
1. What is the fundamental architectural limitation of relying solely on Vertical Scaling (Scale Up)?
2. Why must application servers be designed as "Stateless" to enable effective Horizontal Scaling?
3. What is the primary benefit of offloading heavy tasks (like invoice generation and email delivery) to an asynchronous Message Queue?