Skip to main content

Featured

GPU Memory Sharding with FSDP

GPU Memory Sharding with FSDP

DISTRIBUTED DEEP LEARNING — PART 1/5 Day 1: Demystifying GPU Memory & The ZeRO Revolution — DeepSpeed, FSDP & State Sharding 25 min read Series: The Dharma of Development Distributed DL (Day 1 / 5) Level: Principal / Systems AI Engineer 💥 Context: You attempt to fine-tune or pretrain a 13-billion parameter dense transformer on an 80GB NVIDIA H100 or A100 GPU using standard PyTorch. You set your batch size to 1. You press enter. Within three seconds, your terminal explodes with the most dreaded error in artificial intelligence: torch.cuda.OutOfMemoryError: CUDA out of memory . How is this possible? In 16-bit precision, 13 billion parameters occupy only ~26 GB of disk space. Why can't an 80 GB state-of-the-art GPU train a 26 GB model? Because the naive mental model of machine learning memory is deeply flawed. Today, we demystify the true $16\Phi$ memory footprint of neural networks and master the architecture that made modern large language models possi...

Advanced Database Architecture — Connection Pooling, PgBouncer, and Transaction Isolation Levels

BACKEND SERIES

Day 31: Advanced Database Architecture — Connection Pooling, PgBouncer, and Transaction Isolation Levels

Series: Logic & Legacy
Day 31 / 50
Level: Senior / Database Reliability

Context: High-concurrency async Python services (like FastAPI or async SQLAlchemy) can easily spawn thousands of concurrent green threads or asyncio tasks. But PostgreSQL uses a process-per-connection model. Spawning 5,000 direct database connections causes memory exhaustion, severe context switching overhead, and connection starvation (FATAL: sorry, too many clients already). Today, we dive deep into database scaling architecture: Connection Pooling, PgBouncer multiplexing, and ACID Transaction Isolation Levels.




1. The PostgreSQL Process-Per-Connection Cost

Unlike MySQL (which uses threads), PostgreSQL forks a dedicated OS process (postgres: user db [idle]) for every active client connection. Each connection consumes approximately 2MB to 10MB of RAM just sitting idle. At 1,000 connections, your database server wastes 5GB–10GB of RAM on idle connection overhead alone before executing a single query.

SQLAlchemy Async Engine with Connection Pool Configuration
from sqlalchemy.ext.asyncio import create_async_engine

# Tune application-level connection pool limits
engine = create_async_engine(
    "postgresql+asyncpg://user:password@localhost:6432/production_db",
    pool_size=20,          # Steady-state open connections per worker pod
    max_overflow=10,       # Temporary burst connections allowed under spike
    pool_timeout=30,       # Wait up to 30s before throwing TimeoutError
    pool_recycle=1800,     # Recycle connections every 30m to prevent leaks
    pool_pre_ping=True     # Test connection health before handing to application
)

2. PgBouncer Modes: Session vs. Transaction vs. Statement

PgBouncer sits between your application pods and PostgreSQL server, operating in three distinct pooling modes:

  • Session Pooling: Assigns a server connection for the duration the client stays connected. Safest, but lowest density multiplexing.
  • Transaction Pooling (Recommended): Assigns a server connection only for the duration of a single BEGIN ... COMMIT block. As soon as the transaction completes, the connection returns to the pool.
  • Statement Pooling: Assigns a connection per SQL statement. Multi-statement transactions are forbidden.
PgBouncer Configuration (pgbouncer.ini snippet)
[databases]
production_db = host=127.0.0.1 port=5432 dbname=production_db

[pgbouncer]
listen_addr = *
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 5000
default_pool_size = 50
reserve_pool_size = 10

3. Transaction Isolation Levels & Dirty Read Safeguards



When multiplexing concurrent database transactions, software architects must understand SQL Standard Transaction Isolation Levels:

  • Read Committed (PostgreSQL Default): Prevents Dirty Reads. Queries only see data committed before the query began.
  • Repeatable Read: Prevents Non-Repeatable Reads. All queries inside a transaction see a consistent snapshot as of transaction start.
  • Serializable: Strictest isolation. Emulates serial transaction execution; raises serialization anomalies if concurrent transactions conflict.

The Shareable Quote: "Do not scale database hardware to fix connection bloat; scale connection architecture with transaction-level pooling."

🛠️ Day 31 Project: Configure PgBouncer & AsyncPG Benchmark

Set up a local PgBouncer proxy container and write a Python asyncpg benchmark testing 1,000 concurrent tasks against direct vs. pooled DB connections.

  • Deploy a PgBouncer container set to pool_mode = transaction.
  • Run 1,000 concurrent asyncio queries via asyncpg targeting PgBouncer (Port 6432).
  • Measure memory footprint and execution latency compared to direct PostgreSQL connections.
🔥 PRO UPGRADE / TEASER

Tomorrow, we explore database indexing mechanics: Day 32: PostgreSQL Indexing Internal Mechanics — B-Trees, GIN Indexes, and Query Execution Plans (EXPLAIN ANALYZE).

Architectural Consulting

If you are building high-concurrency Python backends or microservices and need senior architectural guidance, I am available for direct contracting.

Explore Enterprise Engagements →

Comments