← Назад к вопросам

Что такое CQRS?

2.7 Senior🔥 301 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

CQRS (Command Query Responsibility Segregation)

CQRS — это архитектурный паттерн, который разделяет операции на две категории: команды (записи) и запросы (чтение). Основная идея заключается в том, что модели для создания и обновления данных отличаются от моделей для чтения данных.

Основные принципы

Традиционный подход использует одну модель для всех операций. CQRS же предлагает:

  • Command (Команда) — операция, которая изменяет состояние системы (CREATE, UPDATE, DELETE)
  • Query (Запрос) — операция, которая только читает данные без побочных эффектов (SELECT)
  • Разделение моделей — команды и запросы могут иметь разные структуры данных

Пример реализации на Python

from dataclasses import dataclass
from typing import List
from datetime import datetime

# Команды (write model)
@dataclass
class CreateUserCommand:
    username: str
    email: str
    password: str

@dataclass
class UpdateUserCommand:
    user_id: int
    email: str

# Запросы (read model)
@dataclass
class GetUserQuery:
    user_id: int

@dataclass
class SearchUsersQuery:
    search_term: str

# Write-сторона (Command Handler)
class CommandHandler:
    def __init__(self, database):
        self.db = database
    
    def handle_create_user(self, cmd: CreateUserCommand):
        """Обработка команды создания пользователя"""
        # Хэшируем пароль, валидируем, сохраняем
        hashed_password = self._hash_password(cmd.password)
        user_id = self.db.insert(
            table="users",
            username=cmd.username,
            email=cmd.email,
            password_hash=hashed_password,
            created_at=datetime.utcnow()
        )
        # Публикуем событие
        self._publish_event("UserCreated", {"user_id": user_id})
        return user_id
    
    def _hash_password(self, password: str) -> str:
        import hashlib
        return hashlib.sha256(password.encode()).hexdigest()
    
    def _publish_event(self, event_type: str, data: dict):
        print(f"Event published: {event_type} -> {data}")

# Read-сторона (Query Handler)
class QueryHandler:
    def __init__(self, read_database):
        self.read_db = read_database
    
    def handle_get_user(self, query: GetUserQuery):
        """Получение пользователя (оптимизировано для чтения)"""
        # Может читать из кэша, репликированной БД или специального хранилища
        return self.read_db.get_user_by_id(query.user_id)
    
    def handle_search_users(self, query: SearchUsersQuery) -> List[dict]:
        """Поиск пользователей"""
        # Может использовать Elasticsearch, специальный индекс и т.д.
        return self.read_db.search_users(query.search_term)

# Применение в приложении
class UserService:
    def __init__(self, command_handler, query_handler):
        self.commands = command_handler
        self.queries = query_handler
    
    def create_user(self, username: str, email: str, password: str):
        cmd = CreateUserCommand(
            username=username,
            email=email,
            password=password
        )
        return self.commands.handle_create_user(cmd)
    
    def get_user(self, user_id: int):
        query = GetUserQuery(user_id=user_id)
        return self.queries.handle_get_user(query)
    
    def search_users(self, term: str):
        query = SearchUsersQuery(search_term=term)
        return self.queries.handle_search_users(query)

Преимущества CQRS

  1. Оптимизация производительности — read и write могут использовать разные технологии (PostgreSQL для записей, Redis для чтений)
  2. Независимое масштабирование — read-операции можно масштабировать отдельно от write
  3. Сложные запросы — легче реализовать сложные аналитические запросы на отдельной read-модели
  4. Разделение ответственности — код для команд и запросов не смешивается
  5. Event Sourcing — естественно интегрируется с event sourcing (история всех изменений)

Недостатки

  1. Повышенная сложность — требует больше кода и понимания архитектуры
  2. Консистентность данных — между write и read могут быть временные рассинхронизации (eventual consistency)
  3. Поддержка двух моделей — нужно обновлять и синхронизировать две модели данных

Когда использовать

CQRS особенно полезен в:

  • Системах с высокой нагрузкой на чтение
  • Приложениях с Event Sourcing
  • Микросервисной архитектуре
  • Системах с разными требованиями к read и write операциям

Для простых CRUD приложений CQRS часто является overengineering.

Что такое CQRS? | PrepBro