How do you implement database scaling strategies in the cloud?
Database scaling handles growing data volumes and query loads. Vertical scaling: upgrade to a larger instance (more CPU, RAM, IOPS). Simple but has limits and requires downtime for some database types. Use when: workload is read/write balanced, schema is relational and complex, and current instance is underutilized. Horizontal read scaling: add read replicas to handle read-heavy workloads. Implementation: create read replicas in the same or different regions, route read queries to replicas using connection pooling or application-level routing, handle replication lag (eventually consistent reads). Suitable for read-heavy workloads (80%+ reads). Sharding: distribute data across multiple database instances based on a shard key. Strategies: range-based (shard by date range or ID range), hash-based (consistent hashing on a key for even distribution), and directory-based (lookup table maps keys to shards). Challenges: cross-shard queries, rebalancing when adding shards, and maintaining referential integrity. Connection pooling: PgBouncer or Supavisor for PostgreSQL, ProxySQL for MySQL. Reduces connection overhead and allows more concurrent application connections than the database natively supports. Caching: Redis or Memcached for frequently accessed data, implement cache-aside pattern, and set appropriate TTLs per data type. Cloud-native options: Aurora Serverless (auto-scaling compute), DynamoDB (auto-scaling throughput), and CockroachDB or YugabyteDB (distributed SQL). Performance optimization: analyze slow queries (pgstatstatements for PostgreSQL), implement appropriate indexes (B-tree for equality and range, GIN for JSON and arrays, GiST for spatial), partition large tables (range partitioning by date is most common), and implement materialized views for complex aggregations.