Какие знаешь архитектурные паттерны сервисов?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Архитектурные паттерны сервисов
Архитектурные паттерны определяют структуру и взаимодействие компонентов системы. Рассмотрю основные паттерны, которые используются в современной разработке.
1. Монолит (Monolithic Architecture)
Описание: Весь код в одном приложении, все модули запускаются вместе.
┌──────────────────────────────────────┐
│ Single Application │
│ ┌────────┬──────────┬──────────┐ │
│ │ Users │ Products │ Orders │ │
│ │ Module │ Module │ Module │ │
│ └────────┴──────────┴──────────┘ │
└──────────────────────────────────────┘
Single Database
Плюсы:
- Простота разработки и развертывания
- Легче отладить
- Хороший performance (нет сетевых вызовов)
Минусы:
- Сложно масштабировать части отдельно
- Любой баг может сломать всё приложение
- Сложно менять технологический стек
Когда использовать: Стартапы, pequeños проекты, MVP.
2. Микросервисы (Microservices)
Описание: Множество независимых сервисов, каждый отвечает за одну функцию.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ User Service │ │Product Service│ │Order Service │
│ :8001 │ │ :8002 │ │ :8003 │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
[MySQL] [PostgreSQL] [MongoDB]
Плюсы:
- Независимое масштабирование
- Отказоустойчивость (падение одного сервиса не ломает всё)
- Разные технологии для разных сервисов
- Разные команды могут работать независимо
Минусы:
- Сложность в разработке
- Сложная отладка (distributed tracing)
- Network latency
- Consensus проблемы (distributed transactions)
Когда использовать: Крупные системы, разные команды, разные требования к масштабируемости.
3. Слоистая архитектура (Layered Architecture)
Описание: Код разделён на слои — presentation, business logic, data access.
┌─────────────────────────────────┐
│ Presentation Layer │
│ (Controllers, REST API) │
├─────────────────────────────────┤
│ Application Layer │
│ (Services, Use Cases) │
├─────────────────────────────────┤
│ Domain Layer │
│ (Business Rules, Models) │
├─────────────────────────────────┤
│ Infrastructure Layer │
│ (Database, External APIs) │
└─────────────────────────────────┘
Плюсы:
- Легко понять структуру
- Хорошее разделение ответственности
- Легко тестировать
Минусы:
- Может стать "толстым слоем" (много кода в одном слое)
- Зависимости могут быть циклические
Python пример:
# Presentation layer
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
def get_user(user_id: int, service: UserService = Depends()):
return service.get_user(user_id) # Application layer
# Application layer
class UserService:
def __init__(self, repository: UserRepository):
self.repo = repository
def get_user(self, user_id: int):
return self.repo.find_by_id(user_id) # Infrastructure layer
# Infrastructure layer
class UserRepository:
def find_by_id(self, user_id: int):
return db.query(User).filter(User.id == user_id).first()
4. Луковая архитектура (Onion Architecture / DDD)
Описание: Слои организованы концентрически, внешние зависят от внутренних.
┌─────────────────────────────┐
│ Presentation (UI, API) │
├─────────────────────────────┤
│ Application (Use Cases) │
├─────────────────────────────┤
│ Domain (Business Rules) │
├─────────────────────────────┤
│ Infrastructure (DB, APIs) │
└─────────────────────────────┘
Главное правило: Зависимости только вовнутрь!
# Domain (самый внутренний, без зависимостей)
class User:
def __init__(self, name: str, email: str):
self.name = name
self.email = email
def is_valid(self) -> bool:
return len(self.name) > 0 and "@" in self.email
# Application
class CreateUserUseCase:
def __init__(self, repository: UserRepository):
self.repo = repository
def execute(self, name: str, email: str):
user = User(name, email)
if not user.is_valid():
raise ValueError("Invalid user")
return self.repo.save(user)
# Infrastructure
class UserRepository:
def save(self, user: User):
db.session.add(user)
db.session.commit()
# Presentation
@app.post("/users")
def create_user(dto: UserDTO, use_case: CreateUserUseCase = Depends()):
return use_case.execute(dto.name, dto.email)
5. CQRS (Command Query Responsibility Segregation)
Описание: Разделить операции на чтение (Query) и запись (Command).
┌──────────────┐
│ Client │
└──────┬───────┘
│
┌──┴──┐
│ │
┌──▼─┐ ┌─▼──┐
│Cmd │ │Qry │
└──┬─┘ └─┬──┘
│ │
┌───▼─────▼────┐
│ Database │
└──────────────┘
Пример:
# Command (изменение состояния)
class CreateOrderCommand:
def __init__(self, user_id: int, items: List[Item]):
self.user_id = user_id
self.items = items
class CreateOrderCommandHandler:
def handle(self, cmd: CreateOrderCommand):
order = Order(user_id=cmd.user_id)
for item in cmd.items:
order.add_item(item)
db.session.add(order)
db.session.commit()
return order.id
# Query (чтение)
class GetOrderQuery:
def __init__(self, order_id: int):
self.order_id = order_id
class GetOrderQueryHandler:
def handle(self, query: GetOrderQuery):
return db.query(Order).filter(Order.id == query.order_id).first()
# API
@app.post("/orders") # Command
def create_order(cmd: CreateOrderCommand):
handler = CreateOrderCommandHandler()
return {"order_id": handler.handle(cmd)}
@app.get("/orders/{order_id}") # Query
def get_order(order_id: int):
handler = GetOrderQueryHandler()
return handler.handle(GetOrderQuery(order_id))
6. Event-Driven Architecture
Описание: Компоненты взаимодействуют через события.
┌────────────┐
│ Service A │ ──┐
└────────────┘ │ publishes
│ Event
┌────────────┐ │ ┌───────────────┐
│ Service B │ ◄─┼──│ Event Broker │
└────────────┘ │ │ (Kafka, RMQ) │
│ └───────────────┘
┌────────────┐ │
│ Service C │ ◄─┘
└────────────┘
Python пример с Celery:
from celery import Celery
app = Celery('tasks')
# Publisher
from myapp.tasks import send_email_task
def create_order(order_data):
order = Order.create(**order_data)
# Emit event
send_email_task.delay(order.id, order.user.email)
return order
# Subscriber
@app.task
def send_email_task(order_id, email):
order = Order.get(order_id)
send_email(email, f"Your order #{order_id} is confirmed")
7. Serverless (FaaS - Function as a Service)
Описание: Код запускается как функции без управления сервером.
# AWS Lambda
import json
def lambda_handler(event, context):
user_id = event['pathParameters']['user_id']
user = db.get_user(user_id)
return {
'statusCode': 200,
'body': json.dumps(user.__dict__)
}
Плюсы: Автоматическое масштабирование, платим только за использование.
Минусы: Cold start, ограничения по памяти и CPU, сложнее отладить.
Сравнение паттернов
| Паттерн | Сложность | Масштабируемость | Performance | Когда использовать |
|---|---|---|---|---|
| Монолит | Низкая | Плохая | Отличное | MVP, стартап |
| Микросервисы | Высокая | Отличная | Хорошее | Крупные системы |
| Слоистая | Средняя | Средняя | Хорошее | CRUD приложения |
| Луковая | Высокая | Средняя | Хорошее | Сложная логика |
| CQRS | Высокая | Отличная | Отличное | Асимметричные Чтения/Писания |
| Event-Driven | Высокая | Отличная | Хорошее | Слабо связанные сервисы |
| Serverless | Средняя | Отличная | Зависит | Периодические задачи |
Практические рекомендации
- Начните с монолита — это проще и меньше overhead
- Переходите на микросервисы когда монолит становится слишком большим
- Используйте правильный паттерн для правильной проблемы
- Комбинируйте паттерны — например, слоистая архитектура внутри микросервиса
- Документируйте выбор паттерна и причины