0
0
Microservicessystem_design~7 mins

Database decomposition strategy in Microservices - System Design Guide

Choose your learning style9 modes available
Problem Statement
When a monolithic database grows too large, it becomes a bottleneck for development and scaling. Teams face challenges like slow deployments, complex schema changes, and performance degradation because all services share the same database.
Solution
Database decomposition splits a large monolithic database into smaller, service-specific databases. Each microservice owns its own database schema or instance, enabling independent development, scaling, and deployment. Services communicate via APIs or events instead of direct database sharing.
Architecture
Microservice A
Database A
Microservice B
Database B
Microservice C
Database C

This diagram shows multiple microservices each owning their own database. They communicate with each other through APIs or event messages instead of sharing a single database.

Trade-offs
✓ Pros
Enables independent service deployment and scaling without affecting others.
Reduces risk of schema conflicts and complex migrations across teams.
Improves fault isolation; one database failure doesn't bring down all services.
Allows technology heterogeneity; each service can choose the best database type.
✗ Cons
Increases complexity of data consistency across services due to distributed data.
Requires additional infrastructure for inter-service communication and data synchronization.
Makes complex queries involving multiple services harder and less efficient.
When the system has multiple teams working on different domains and the monolithic database causes deployment or scaling bottlenecks, typically at tens of thousands of requests per second or more.
When the system is small with low traffic (under 1,000 requests per second) or when strong transactional consistency across all data is critical and cannot be compromised.
Real World Examples
Amazon
Decomposed their monolithic database into service-specific databases to enable independent scaling and faster deployments across their vast e-commerce platform.
Netflix
Uses database decomposition to allow each microservice to own its data, improving fault isolation and enabling polyglot persistence.
Uber
Split their monolithic data store into multiple databases per service to handle high write volumes and reduce cross-team dependencies.
Code Example
The before code shows two services directly accessing the same shared database, causing tight coupling. The after code shows each service using its own database connection, enforcing database decomposition. Services communicate via events or APIs instead of shared tables.
Microservices
### Before: Monolithic database access (violating decomposition)
class OrderService:
    def create_order(self, user_id, product_id):
        # Directly access shared orders table
        db.execute("INSERT INTO orders (user_id, product_id) VALUES (?, ?)", (user_id, product_id))

class PaymentService:
    def process_payment(self, order_id, amount):
        # Directly access shared payments table
        db.execute("INSERT INTO payments (order_id, amount) VALUES (?, ?)", (order_id, amount))


### After: Each service owns its own database
class OrderService:
    def __init__(self, order_db):
        self.order_db = order_db

    def create_order(self, user_id, product_id):
        self.order_db.execute("INSERT INTO orders (user_id, product_id) VALUES (?, ?)", (user_id, product_id))

class PaymentService:
    def __init__(self, payment_db):
        self.payment_db = payment_db

    def process_payment(self, order_id, amount):
        self.payment_db.execute("INSERT INTO payments (order_id, amount) VALUES (?, ?)", (order_id, amount))

# Communication via API or events instead of shared DB
# For example, OrderService emits event 'OrderCreated' that PaymentService listens to.
OutputSuccess
Alternatives
Shared Database with Schema Separation
All services share the same database instance but use separate schemas or tablespaces.
Use when: When teams want some isolation but cannot afford multiple database instances due to cost or operational complexity.
Database Sharding
Data is partitioned horizontally across multiple database instances based on a shard key, but still logically one database.
Use when: When scaling a single large dataset horizontally is the main concern rather than service ownership.
Event Sourcing with CQRS
Services store events instead of current state and build read models separately, decoupling writes and reads.
Use when: When complex data consistency and auditability are required along with scalability.
Summary
Database decomposition splits a large monolithic database into smaller, service-owned databases to reduce coupling and improve scalability.
It enables independent service deployment, fault isolation, and technology flexibility but adds complexity in data consistency and communication.
This pattern is best for large systems with multiple teams and high traffic, while small systems may not benefit from its complexity.