面试知识库
中 进阶

CQRS模式#

一句话答案#

CQRS 将读写分离为不同模型/数据库,写端保证一致性,读端用 ES/Redis/宽表优化查询,适合读写负载差异大的场景。

核心要点

Command(写): 标准化数据库,保证一致性 Query(读): 可用 ES/Redis/宽表,优化查询性能

配合事件溯源(Event Sourcing): 写入事件流 → 异步构建读模型

注意边界: CQRS 不要求一定分库、一定异步——读写模型可以在同一个库、同一事务里同步更新,分库+异步是为了独立扩展时的常见做法;CQRS 也不等于 Event Sourcing,两者常一起用但可以单独用。Java 生态常用框架是 Axon Framework(5.0 于 2025-11 GA),事件存储有 Axon Server、KurrentDB(原 EventStoreDB,2025 年改名)。

面试回答(2分钟版)

CQRS 全称是命令查询职责分离,核心思想是把系统的读和写拆成两套独立的模型。写端用规范化的关系模型保证数据一致性,比如标准的 MySQL 表结构;读端则根据查询需求做反范式化优化,可以用 Elasticsearch 做全文检索、Redis 做缓存、或者建宽表加速复杂查询。两边通常通过事件或消息队列异步同步数据(也可以同库同步更新,按一致性要求选)。它和简单的数据库读写分离不同——读写分离只是数据库层面主从复制,CQRS 是模型层面的分离,读写各自有独立的数据结构甚至不同的存储引擎。这个模式特别适合读写负载差异大的场景,比如电商商品详情页读多写少,读模型可以针对性优化。但它引入了最终一致性的复杂度,简单的 CRUD 系统不建议使用。

追问与易错

追问方向:

  • “读写模型怎么同步?”→ 写端变更后发布领域事件到 MQ,消费者异步更新读端模型(ES/Redis/宽表);存在秒级延迟,需要容忍最终一致性
  • “增加了什么复杂度?”→ 数据最终一致性(用户写完立刻读可能读到旧数据)、事件丢失需补偿机制、读写两套模型需要同时维护和演进
  • “什么场景适合?”→ 读写负载差异大(电商商品详情读多写少)、读写模型差异大(写用关系型、读用搜索引擎)、需要独立扩展读写的场景;简单 CRUD 不适合

易错点:

  • ❌ 所有系统都该用 CQRS——简单 CRUD 没必要
  • ❌ CQRS 就是读写分离——CQRS 是模型分离
  • ❌ 用 CQRS 就必须上 Event Sourcing——两者独立,写端用普通关系表 + 发领域事件(配合本地消息表/Outbox 保证不丢)也是 CQRS