Ответ
CQRS (Command Query Responsibility Segregation) — это архитектурный паттерн, который предлагает разделять модели и логику для операций изменения состояния (Commands) и операций чтения данных (Queries).
Основная идея: Вместо единой модели для всех CRUD-операций создаются две отдельные, специализированные модели:
- Command Model (модель команд): Отвечает за изменение состояния системы (создание, обновление, удаление). Команды не должны возвращать данные.
- Query Model (модель запросов): Отвечает только за чтение данных. Эта модель может быть денормализована и оптимизирована для быстрых и сложных выборок.
Ключевые преимущества:
- Масштабируемость: Позволяет независимо масштабировать сервисы чтения и записи. Например, можно иметь один мощный сервер для записи и множество легковесных реплик для чтения.
- Оптимизация: Модель для чтения может использовать другую технологию хранения (например, Elasticsearch или Redis), идеально подходящую для конкретных запросов, в то время как модель записи использует транзакционную реляционную БД (например, PostgreSQL).
- Гибкость и безопасность: Четкое разделение логики упрощает разработку и тестирование. Можно настроить разные права доступа для команд и запросов.
Упрощенный пример на Python:
# --- Command Side --- #
class ProductRepository:
def save(self, product):
# Логика сохранения в основную БД (например, PostgreSQL)
print(f"Сохранение продукта '{product.name}' в основную базу данных.")
class ProductCommands:
def __init__(self):
self.repo = ProductRepository()
def create_product(self, name, price):
product = Product(name=name, price=price)
self.repo.save(product)
# Команда не возвращает результат
# --- Query Side --- #
class ProductQueries:
def get_product_list_for_display(self):
# Чтение из оптимизированной для чтения реплики или кэша (например, Redis)
print("Получение списка продуктов из денормализованного хранилища.")
return [{"name": "Laptop", "price_formatted": "$1200.00"}]
Когда применять: CQRS эффективен в сложных системах с высокой нагрузкой на чтение и высокими требованиями к производительности. Паттерн является избыточным для простых CRUD-приложений из-за вносимой им сложности.