Files
english/.opencode/skills/backend-development/references/backend-architecture.md
2026-04-12 01:06:31 +07:00

455 lines
12 KiB
Markdown

# Backend Architecture Patterns
Microservices, event-driven architecture, and scalability patterns (2025).
## Monolith vs Microservices
### Monolithic Architecture
```
┌─────────────────────────────────┐
│ Single Application │
│ │
│ ┌─────────┐ ┌──────────┐ │
│ │ Users │ │ Products │ │
│ └─────────┘ └──────────┘ │
│ ┌─────────┐ ┌──────────┐ │
│ │ Orders │ │ Payments │ │
│ └─────────┘ └──────────┘ │
│ │
│ Single Database │
└─────────────────────────────────┘
```
**Pros:**
- Simple to develop and deploy
- Easy local testing
- Single codebase
- Strong consistency (ACID transactions)
**Cons:**
- Tight coupling
- Scaling limitations
- Deployment risk (all-or-nothing)
- Tech stack lock-in
**When to Use:** Startups, MVPs, small teams, unclear domain boundaries
### Microservices Architecture
```
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ User │ │ Product │ │ Order │ │ Payment │
│ Service │ │ Service │ │ Service │ │ Service │
└────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
┌──▼──┐ ┌──▼──┐ ┌──▼──┐ ┌──▼──┐
│ DB │ │ DB │ │ DB │ │ DB │
└─────┘ └─────┘ └─────┘ └─────┘
```
**Pros:**
- Independent deployment
- Technology flexibility
- Fault isolation
- Easier scaling (scale services independently)
**Cons:**
- Complex deployment
- Distributed system challenges (network latency, partial failures)
- Data consistency (eventual consistency)
- Operational overhead
**When to Use:** Large teams, clear domain boundaries, need independent scaling, tech diversity
## Microservices Patterns
### Database per Service Pattern
**Concept:** Each service owns its database
```
User Service → User DB (PostgreSQL)
Product Service → Product DB (MongoDB)
Order Service → Order DB (PostgreSQL)
```
**Benefits:**
- Service independence
- Technology choice per service
- Fault isolation
**Challenges:**
- No joins across services
- Distributed transactions
- Data duplication
### API Gateway Pattern
```
Client
┌─────────────────┐
│ API Gateway │ - Authentication
│ (Kong/NGINX) │ - Rate limiting
└────────┬────────┘ - Request routing
┌────┴────┬────────┬────────┐
▼ ▼ ▼ ▼
User Product Order Payment
Service Service Service Service
```
**Responsibilities:**
- Request routing
- Authentication/authorization
- Rate limiting
- Request/response transformation
- Caching
**Implementation (Kong):**
```yaml
services:
- name: user-service
url: http://user-service:3000
routes:
- name: user-route
paths:
- /api/users
- name: product-service
url: http://product-service:3001
routes:
- name: product-route
paths:
- /api/products
plugins:
- name: rate-limiting
config:
minute: 100
- name: jwt
```
### Service Discovery
**Concept:** Services find each other dynamically
```typescript
// Consul service discovery
import Consul from 'consul';
const consul = new Consul();
// Register service
await consul.agent.service.register({
name: 'user-service',
address: '192.168.1.10',
port: 3000,
check: {
http: 'http://192.168.1.10:3000/health',
interval: '10s',
},
});
// Discover service
const services = await consul.catalog.service.nodes('product-service');
const productServiceUrl = `http://${services[0].ServiceAddress}:${services[0].ServicePort}`;
```
### Circuit Breaker Pattern
**Concept:** Stop calling failing service, prevent cascade failures
```typescript
import CircuitBreaker from 'opossum';
const breaker = new CircuitBreaker(callExternalService, {
timeout: 3000, // 3s timeout
errorThresholdPercentage: 50, // Open circuit after 50% failures
resetTimeout: 30000, // Try again after 30s
});
breaker.on('open', () => {
console.log('Circuit breaker opened!');
});
breaker.fallback(() => ({
data: 'fallback-response',
source: 'cache',
}));
const result = await breaker.fire(requestParams);
```
**States:**
- **Closed:** Normal operation, requests go through
- **Open:** Too many failures, requests fail immediately
- **Half-Open:** Testing if service recovered
### Saga Pattern (Distributed Transactions)
**Choreography-Based Saga:**
```
Order Service: Create Order → Publish "OrderCreated"
Payment Service: Reserve Payment → Publish "PaymentReserved"
Inventory Service: Reserve Stock → Publish "StockReserved"
Shipping Service: Create Shipment → Publish "ShipmentCreated"
If any step fails → Compensating transactions (rollback)
```
**Orchestration-Based Saga:**
```
Saga Orchestrator
↓ Create Order
Order Service
↓ Reserve Payment
Payment Service
↓ Reserve Stock
Inventory Service
↓ Create Shipment
Shipping Service
```
## Event-Driven Architecture
**Impact:** 85% organizations recognize business value
### Event Sourcing
**Concept:** Store events, not current state
```typescript
// Traditional: Store current state
{
userId: '123',
balance: 500
}
// Event Sourcing: Store events
[
{ type: 'AccountCreated', userId: '123', timestamp: '...' },
{ type: 'MoneyDeposited', amount: 1000, timestamp: '...' },
{ type: 'MoneyWithdrawn', amount: 500, timestamp: '...' },
]
// Reconstruct state by replaying events
const balance = events
.filter(e => e.userId === '123')
.reduce((acc, event) => {
if (event.type === 'MoneyDeposited') return acc + event.amount;
if (event.type === 'MoneyWithdrawn') return acc - event.amount;
return acc;
}, 0);
```
**Benefits:**
- Complete audit trail
- Temporal queries (state at any point in time)
- Event replay for debugging
- Flexible projections
### Message Broker Patterns
**Kafka (Event Streaming):**
```typescript
import { Kafka } from 'kafkajs';
const kafka = new Kafka({
clientId: 'order-service',
brokers: ['kafka:9092'],
});
// Producer
const producer = kafka.producer();
await producer.send({
topic: 'order-events',
messages: [
{
key: order.id,
value: JSON.stringify({
type: 'OrderCreated',
orderId: order.id,
userId: order.userId,
total: order.total,
}),
},
],
});
// Consumer
const consumer = kafka.consumer({ groupId: 'inventory-service' });
await consumer.subscribe({ topic: 'order-events' });
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
const event = JSON.parse(message.value.toString());
if (event.type === 'OrderCreated') {
await reserveInventory(event.orderId);
}
},
});
```
**RabbitMQ (Task Queues):**
```typescript
import amqp from 'amqplib';
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
// Producer
await channel.assertQueue('email-queue', { durable: true });
channel.sendToQueue('email-queue', Buffer.from(JSON.stringify({
to: user.email,
subject: 'Welcome!',
body: 'Thank you for signing up',
})));
// Consumer
await channel.consume('email-queue', async (msg) => {
const emailData = JSON.parse(msg.content.toString());
await sendEmail(emailData);
channel.ack(msg);
});
```
## CQRS (Command Query Responsibility Segregation)
**Concept:** Separate read and write models
```
Write Side (Commands): Read Side (Queries):
CreateOrder GetOrderById
UpdateOrder GetUserOrders
↓ ↑
┌─────────┐ ┌─────────┐
│ Write │ → Events → │ Read │
│ DB │ (sync) │ DB │
│(Postgres) │(MongoDB)│
└─────────┘ └─────────┘
```
**Benefits:**
- Optimized read models
- Scalable (scale reads independently)
- Flexible (different DB for reads/writes)
**Implementation:**
```typescript
// Command (Write)
class CreateOrderCommand {
constructor(public userId: string, public items: OrderItem[]) {}
}
class CreateOrderHandler {
async execute(command: CreateOrderCommand) {
const order = await Order.create(command);
await eventBus.publish(new OrderCreatedEvent(order));
return order.id;
}
}
// Query (Read)
class GetOrderQuery {
constructor(public orderId: string) {}
}
class GetOrderHandler {
async execute(query: GetOrderQuery) {
// Read from optimized read model
return await OrderReadModel.findById(query.orderId);
}
}
```
## Scalability Patterns
### Horizontal Scaling (Scale Out)
```
Load Balancer
┌───┴───┬───────┬───────┐
│ App 1 │ App 2 │ App 3 │ ... App N
└───┬───┴───┬───┴───┬───┘
└───────┴───────┘
Shared Database
(with read replicas)
```
### Database Sharding
**Range-Based Sharding:**
```
Users 1-1M → Shard 1
Users 1M-2M → Shard 2
Users 2M-3M → Shard 3
```
**Hash-Based Sharding:**
```typescript
function getShardId(userId: string): number {
const hash = crypto.createHash('md5').update(userId).digest('hex');
return parseInt(hash.substring(0, 8), 16) % SHARD_COUNT;
}
const shardId = getShardId(userId);
const db = shards[shardId];
const user = await db.users.findById(userId);
```
### Caching Layers
```
Client
→ CDN (static assets)
→ API Gateway Cache (public endpoints)
→ Application Cache (Redis - user sessions, hot data)
→ Database Query Cache
→ Database
```
## Architecture Decision Matrix
| Pattern | When to Use | Complexity | Benefits |
|---------|-------------|------------|----------|
| **Monolith** | Small team, MVP, unclear boundaries | Low | Simple, fast development |
| **Microservices** | Large team, clear domains, need scaling | High | Independent deployment, fault isolation |
| **Event-Driven** | Async workflows, audit trail needed | Moderate | Decoupling, scalability |
| **CQRS** | Different read/write patterns | High | Optimized queries, scalability |
| **Serverless** | Spiky traffic, event-driven | Low | Auto-scaling, pay-per-use |
## Anti-Patterns to Avoid
1. **Distributed Monolith** - Microservices that all depend on each other
2. **Chatty Services** - Too many inter-service calls (network overhead)
3. **Shared Database** - Microservices sharing same DB (tight coupling)
4. **Over-Engineering** - Using microservices for small apps
5. **No Circuit Breakers** - Cascade failures in distributed systems
## Architecture Checklist
- [ ] Clear service boundaries (domain-driven design)
- [ ] Database per service (no shared databases)
- [ ] API Gateway for client requests
- [ ] Service discovery configured
- [ ] Circuit breakers for resilience
- [ ] Event-driven communication (Kafka/RabbitMQ)
- [ ] CQRS for read-heavy systems
- [ ] Distributed tracing (Jaeger/OpenTelemetry)
- [ ] Health checks for all services
- [ ] Horizontal scaling capability
## Resources
- **Microservices Patterns:** https://microservices.io/patterns/
- **Martin Fowler - Microservices:** https://martinfowler.com/articles/microservices.html
- **Event-Driven Architecture:** https://aws.amazon.com/event-driven-architecture/
- **CQRS Pattern:** https://martinfowler.com/bliki/CQRS.html