为什么 CRUD 架构开始崩了?来看看 CQRS。

举报
PikeTalk 发表于 2025/12/23 13:43:38 2025/12/23
【摘要】 几年前,我参与一个项目,它的架构在纸面上看起来再正常不过了:简单的 CRUD 接口、单一的关系型数据模型、读写共用一套干净的 API。说实话,这套设计在相当长一段时间里都运行得很顺畅——我们快速交付功能,客户满意,没人质疑架构。但随着系统不断扩张,现实终于追了上来。和许多从小做起、逐步壮大的系统一样,我们那个“够用就好”的设计,开始扛不住我们想要的规模了。架构崩坏的临界点我们的应用有个重度使...

几年前,我参与一个项目,它的架构在纸面上看起来再正常不过了:
简单的 CRUD 接口、单一的关系型数据模型、读写共用一套干净的 API。
说实话,这套设计在相当长一段时间里都运行得很顺畅——我们快速交付功能,客户满意,没人质疑架构。

但随着系统不断扩张,现实终于追了上来。
和许多从小做起、逐步壮大的系统一样,我们那个“够用就好”的设计,开始扛不住我们想要的规模了。


架构崩坏的临界点

我们的应用有个重度使用的报表看板。
大约 70%–75% 的流量都是读请求
但问题在于:支撑这些看板的数据库表,同时也被一个工作流引擎疯狂写入——状态变更、任务分配、时间戳更新、评论添加……所有操作都在同一套表上进行。

这带来了两个大问题:

1. 写得多的时候,读就慢得要命

我们的数据模型高度规范化(normalised)。
这对数据一致性很好,但对查询简直是灾难——光是展示一个看板页面,就要做 8 到 10 个表连接(JOIN)

2. 读得多的时候,写也开始失败

数据库锁竞争(lock contention)越来越严重。
用户抱怨:“更新怎么这么慢?”
业务团队抱怨:“看板卡死了!”
两边都没错,但都快崩溃了。

我们尝试过各种优化:改查询、加索引、调缓存、甚至重做前端页面。
但每次修复都像捏气球——这边压下去,那边又鼓起来。

系统其实没“坏”。
它只是被撑到极限了
而且每周都比上周更紧绷一点。


转折点:那句让我至今难忘的话

一天下午,我们开了一个冗长的设计会,白板上画满了箭头、方框和擦了一半的草图。
讨论了一个小时还在原地打转。
这时,我们的解决方案架构师突然停下来,直视着我说:

“Bicky,这样行不通。我们不是在解决问题,而是在跟架构打架。”

这句话的冲击力,远超我的预期。

因为他说对了。

我们面对的不是一个 bug,
而是当初设计选择的自然边界

就在那天,我们决定不再打补丁,而是重新思考整个架构。
于是,CQRS(命令查询职责分离)走进了我们的视野——
不是因为它听起来酷,也不是因为它流行,
而是因为我们的系统真的需要它


我们是怎么落地 CQRS 的?(真实、务实的做法)

我们没有走极端:

  • 没有全盘引入事件溯源(Event Sourcing)
  • 没有新增四五个数据库
  • 没有为了模式而模式

我们只做了最必要、最实用的部分。

1. 命令侧(Command Side)——干净、可预测的写操作

我们定义了清晰、意图明确的命令,比如:

  • AssignTask(分配任务)
  • UpdateStatus(更新状态)
  • AddComment(添加评论)

命令处理器(Command Handler)接收这些命令,做校验、执行业务规则,然后发出明确的事件:

  • TaskAssigned
  • StatusUpdated
  • CommentAdded

原有的规范化表,仍然是唯一真相源(single source of truth)。

2. 查询侧(Query Side)——快速、反规范化的读操作

针对看板,我们专门构建了读模型(read models)——
这些表的结构完全按照 UI 需求来设计:

  • 不需要 JOIN
  • 不需要跨表跳转
  • 不需要复杂的 SQL 技巧

每当命令侧有更新,系统就通过事件异步刷新这些读模型。

效果立竿见影:

  • 看板加载时间从 4–6 秒 降到 300 毫秒以内
  • 数据库锁竞争彻底消失
  • 扩展读能力变得几乎 trivial(简单到不值一提)
  • 用户甚至问:“你们是不是换了服务器?”

这种满足感,不是因为我们用了某个高大上的模式,
而是因为系统终于表现得像它本该有的样子


什么时候该用 CQRS?(基于真实痛点,而非理论)

如果你遇到以下情况,就该认真考虑 CQRS 了:

  • 读负载极重,压垮了你的写模型
  • 读模型和写模型长得完全不像
  • 你需要大幅扩展读能力,但写操作不多
  • 你为了满足 UI 需求,SQL 越写越复杂
  • 你的系统已经超出了最初 CRUD 设计的假设

这时候,CQRS 就像给系统开了一扇窗,让它能自由呼吸。


什么时候不该用 CQRS?

很多团队滥用模式,只因为它们看起来“优雅”。
别犯这个错。

以下情况,请远离 CQRS:

  • 你的应用还很小,或处于早期阶段
  • 读和写用的是同一个简单模型
  • 你还没遇到真正的性能或扩展问题
  • 团队无法承担额外的运维复杂度
  • 你只是为了显得“企业级”才用它

CQRS 很强大,但用错了的 CQRS,不过是涂了口红的复杂性。


真正的教训——也送给你

回望过去,那句“Bicky,这样行不通”依然在我耳边回响。
不是因为它严厉,而是因为它诚实

有时候,系统最大的瓶颈根本不是代码,
而是那个把一切困住的架构

一旦你改变了系统的“形状”,
功能、性能、团队效率……一切都会自然对齐。

如果你也曾反复修复同一个问题,结果新问题又在别处冒出来,
也许,现在就是你的转折点

所以我想问问你:

你有没有经历过自己的 “this will not work” 时刻?
是什么架构上的改变,最终拯救了你的项目?

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。