CQRS vs обычная CRUD-архитектура¶
Тип материала: инженерное сравнение; выводы зависят от требований и условий эксплуатации. Схемы и примеры иллюстративны.
INFERENCE: сравнение моделей приложения. CRUD не означает отсутствие domain validation, audit или транзакций. CQRS не требует отдельного broker или Event Sourcing. Схема и сценарии — HYPOTHETICAL.
Критерии выбора¶
| Критерий | Единая CRUD-модель | CQRS |
|---|---|---|
| Модель данных | Общая модель для типовых изменений/чтений | Явно разные write/read models |
| Invariants | Проверяются constraints и application logic | Сосредоточены в command side |
| Read/write asymmetry | Решается indexes/query design/replicas | Можно независимо развивать query schemas |
| Deployment | Часто один application/store | Может оставаться одним; distributed вариант сложнее |
| Read-after-write | Проще в одной transaction/primary | Async projection требует revision/wait contract |
| Изменение read schema | Сильнее связано с общей моделью | Отдельный projector/rebuild lifecycle |
| Стоимость | Меньше движущихся частей | Дополнительные contracts, state copies и recovery |
| Хороший fit | Простые операции и умеренные query needs | Сложный домен и существенно разные read workloads |
Отдельный слой команд может быть полезен до физического разделения. И read replica сама по себе не доказывает наличие разных domain/query models. Решение принимать по model responsibilities, а не по числу баз.
Лестница усложнения¶
flowchart LR
A["CRUD + constraints и indexes"] --> B["Разные command/query interfaces в одной БД"]
B --> C["Особые read views / tables"]
C --> D["Async projections при обоснованной необходимости"]
Стрелки показывают возможную эволюцию, а не обязательные стадии каждого проекта. На каждом шаге нужно подтвердить, что прежний вариант действительно ограничивает задачу.
Конкретные сценарии¶
Администрирование справочника: небольшие таблицы и стандартные queries. CRUD с audit и permissions обычно проще. CQRS не создаст бизнес-пользу без конкретной read/write проблемы.
FinTech transaction history: write model защищает payment transitions, query model денормализует детали для поиска. Это хороший CQRS scenario при явно определённом projection lag. Debit всё равно валидируется у authoritative owner.
iGaming sportsbook browsing: чтение markets отличается от принятия bet; отдельная query model помогает fan-out. Приём ставки должен проверять актуальность quote и limits по своему protocol. Быстро показанная цена не является обещанием принять ставку на тех же условиях.
Ограничения и recovery¶
Async CQRS добавляет окно между command acceptance и read visibility. Response может возвращать accepted revision; client показывает pending или просит minimum revision с bounded wait. Нельзя подтверждать несуществующий success только для имитации read-your-writes.
При потере read store его восстанавливают из authoritative source/history; если история неполна, требуется snapshot и reconciliation. Fallback на write DB допустим с ограничением нагрузки. Exactly-once projector state не доказывает single payment effect.
FACT: Fowler определяет CQRS через разделение моделей и предупреждает о risky complexity. CQRS, 2011. FACT: Betfair описывает специализированный streaming read path; полное CQRS command architecture из этого источника UNKNOWN. Betfair.
Типичные ошибки проектирования¶
Объявлять CRUD неспособным к сложной validation; вводить отдельный cluster до проверки indexes; валидировать command по stale projection; требовать ES от любого CQRS.
Вопросы на собеседовании¶
Когда не вводить async projection? Когда read workloads обслуживаются существующей БД и eventual visibility создаёт больше проблем, чем пользы.
Как проверить пользу CQRS? Сформулировать независимые требования к read/write models, доказать bottleneck и учесть rebuild/operations cost.
Практические упражнения¶
Спроектируйте одну payment-history query в двух вариантах: SQL view общей БД и async denormalized store. Укажите consistency, recovery и последствия частичной недоступности. Ожидается аргументированный выбор, а не максимальное количество компонентов.