Module 8: Scaling Strategies
When your application grows beyond what a single server can handle, you need scaling strategies. This module covers horizontal scaling, sharding, and partitioning. The most important scaling principle: Do not shard until you absolutely must. Sharding adds irreversible complexity — cross-shard joins, distributed transactions, and operational overhead that will slow your team down for years. Most PostgreSQL instances can handle far more load than teams realize, especially with proper indexing, connection pooling, and read replicas. The order of operations should be: optimize queries, add indexes, use connection pooling, add read replicas, partition tables, and only then consider sharding.Estimated Time: 12-14 hours
Hands-On: Implement table partitioning
Key Skill: Choosing the right scaling strategy
Hands-On: Implement table partitioning
Key Skill: Choosing the right scaling strategy
8.1 Scaling Fundamentals
Vertical vs Horizontal Scaling
When to Scale
8.2 Table Partitioning
What is Partitioning?
Partition Types
- Range Partitioning
- List Partitioning
- Hash Partitioning
Best for: Time-series data, continuous values
Partition Maintenance
8.3 Database Sharding
Sharding Concepts
Sharding Strategies
Key-Based (Hash) Sharding
Key-Based (Hash) Sharding
Range-Based Sharding
Range-Based Sharding
Directory-Based Sharding
Directory-Based Sharding
Cross-Shard Challenges
This table is the reason experienced engineers avoid sharding as long as possible. Each row represents a problem that does not exist in a single-node database and has no perfect solution in a sharded architecture. Read this table as a cost-benefit analysis, not a feature list.8.4 Caching Strategies
Caching Layers
Real-world analogy: Database caching works like a series of increasingly distant warehouses. Your application checks the closest warehouse (Redis) first, then the regional warehouse (PostgreSQL buffer pool), then the national warehouse (OS page cache), and finally the factory (disk). Each layer is larger but slower. The art of cache engineering is keeping the data most likely to be needed in the closest warehouse.Cache Patterns
- Cache-Aside
- Write-Through
- Write-Behind
Application manages cache explicitly.
Cache Invalidation Strategies
“There are only two hard things in Computer Science: cache invalidation and naming things.” — Phil Karlton. Cache invalidation is genuinely the hardest part of caching. The patterns below represent different tradeoffs between staleness tolerance and implementation complexity. Choose the simplest one that meets your staleness requirements.8.5 Connection Scaling
Connection Pooling with PgBouncer
Optimizing PostgreSQL for Connections
The golden rule of PostgreSQL connections: Fewer connections usually means higher throughput. This is counterintuitive but well-established. Beyond approximately2 * CPU_cores + disk_spindles active connections, performance degrades due to context switching, lock contention in ProcArray, and cache thrashing. A server with 16 cores will often perform better with 40 active connections than with 400.
8.6 Global Distribution
Multi-Region Architecture
Geo-Sharding
Practical context: Geo-sharding is often driven by data residency regulations (GDPR, CCPA, data sovereignty laws) as much as by performance requirements. If your EU users’ data must stay in EU data centers, geo-sharding is not optional — it is a compliance requirement.8.7 Scaling Decision Framework
Decision Tree
Scaling Complexity Ladder
8.8 Practice: Implement Partitioning
Lab Exercise
Create a time-series orders table with monthly partitions and automated maintenance.Complete Solution
Complete Solution
Summary
You’ve learned how to scale PostgreSQL from a single instance to a globally distributed system. Key takeaways:Optimize First
Indexes and queries before hardware
Partition Early
Plan for growth from the start
Cache Strategically
Right data, right layer
Course Completion
Congratulations! You’ve completed the Database Engineering course.
- Write efficient SQL and design schemas
- Understand transactions and isolation
- Optimize queries and indexes
- Navigate PostgreSQL internals
- Build highly available systems
- Scale to millions of users
Next Steps
Get Certified
Take the certification exam
Join Community
Connect with other database engineers
Interview Deep-Dive
Your 2TB PostgreSQL database is slowing down. Walk through your scaling strategy before reaching for sharding.
Your 2TB PostgreSQL database is slowing down. Walk through your scaling strategy before reaching for sharding.
Strong Answer:
- The scaling ladder in order: (1) Query optimization via pg_stat_statements — find top 10 queries by total_exec_time, fix missing indexes and N+1 patterns (often buys 2-5x headroom with zero infrastructure changes). (2) Configuration tuning — verify shared_buffers at 25% RAM, random_page_cost at 1.1 for SSD. (3) PgBouncer in transaction mode to reduce max_connections from 500 to 100. (4) Read replicas for read-heavy workloads. (5) Table partitioning for the largest tables. (6) Vertical scaling (modern instances offer 96+ cores, 768GB RAM). (7) Sharding only after exhausting all of the above.
Compare partitioning and sharding. What mistakes do teams make when implementing partitioning?
Compare partitioning and sharding. What mistakes do teams make when implementing partitioning?
Strong Answer:
- Partitioning splits a table within one instance — all SQL features work normally. Sharding splits across multiple instances — requires routing layer, breaks cross-shard JOINs and transactions. Partition when single-node hardware is sufficient but table size causes maintenance issues. Shard when write throughput exceeds single-node capacity.
- Common mistakes: (1) Too many partitions — daily partitions on 10-year data creates 3650 partitions, causing planner overhead and catalog bloat. Use monthly or quarterly. (2) Queries missing the partition key in WHERE, causing full partition scans. (3) Not automating future partition creation — inserts fail when data falls outside existing ranges. Use pg_partman.
Design a caching strategy for a PostgreSQL-backed application. When do you use Redis versus PostgreSQL's buffer pool?
Design a caching strategy for a PostgreSQL-backed application. When do you use Redis versus PostgreSQL's buffer pool?
Strong Answer:
- PostgreSQL’s buffer pool is already a cache. If the working set fits in RAM, PostgreSQL serves data at sub-millisecond latency. Adding Redis only helps when: (1) the same small result is read thousands of times/sec (hot key — Redis handles 100K+ reads/sec per key), (2) session/ephemeral data without durability needs, (3) expensive computed results that tolerate bounded staleness, or (4) rate limiting and atomic counters.
- Cache invalidation: use cache-aside with TTL for simplicity. For stronger consistency, use PostgreSQL LISTEN/NOTIFY to push invalidation events. Never use write-behind for critical data.
- The biggest mistake: caching individual row lookups when the real bottleneck is an expensive aggregation query. Cache the aggregation result, not individual rows.