article.read --id=157

CQRS:命令与查询的分道扬镳

// published: 2025-07-19

读和写有着截然不同的需求,CQRS让它们各走各的路。传统的CRUD模式用同一个模型处理读和写,简单但在复杂场景下力不从心。写操作关注的是业务逻辑的正确性、数据的一致性、事务的完整性;读操作关注的是查询的高效性、数据的展示、用户体验的流畅。用同一个模型同时满足这两种需求,就像用一辆车既要跑越野又要跑赛道,很难做到最优。CQRS(命令查询职责分离)的核心思想是:把写操作(Command)和读操作(Query)拆分为两个独立的模型,让它们各自优化。这种分离不仅是技术层面的,更是思维层面的。

CQRS的写模型专注于业务逻辑的正确性。它使用规范化的数据结构,保证数据的一致性和完整性;它处理复杂的业务规则,验证数据的合法性;它记录领域事件,追踪业务状态的变化。写模型可以使用关系型数据库,利用事务保证ACID特性。写模型不需要考虑查询的性能,它只需要保证写入的正确性。CQRS的读模型专注于查询的高效性。它使用反规范化的数据结构,将多个表的数据聚合到一起,避免复杂的JOIN操作;它可以使用不同的存储技术,如文档数据库、搜索引擎、缓存,选择最适合查询场景的工具;它可以针对不同的查询需求建立多个读模型,每个模型优化特定的查询场景。读模型不需要考虑写入的复杂性,它只需要提供高效的查询。

Amazon在其电商系统中广泛应用了CQRS模式和Event Sourcing。商品信息的写入使用关系型数据库,保证数据的一致性;商品的搜索使用Elasticsearch,提供强大的全文搜索和过滤能力;商品的详情页使用缓存,提供毫秒级的响应速度。当商品信息更新时,写模型处理业务逻辑并持久化数据,然后发布事件;读模型订阅这些事件,更新自己的数据。这种架构让Amazon能够支撑海量的商品查询,同时保证商品信息的准确性。在黑色星期五这样的购物高峰期,读模型可以独立扩展,不影响写模型的性能。Amazon的订单系统也采用了Event Sourcing,所有订单状态的变化都被记录为事件,可以随时回溯订单的完整历史。

CQRS与Event Sourcing是天然的搭档。Event Sourcing把事件作为数据的唯一真相来源,CQRS从事件流中构建读模型。写模型只需要追加事件,不需要更新数据库,性能极高;读模型通过重放事件流构建自己的数据,可以根据需要建立任意多个读模型。如果需要新的查询视图,只需要创建一个新的读模型,重放历史事件即可。这种架构的灵活性是传统CRUD模式无法比拟的。当业务需求变化,需要新的查询维度时,不需要修改写模型,只需要添加新的读模型。

但CQRS也增加了系统的复杂性。首先是数据的最终一致性:写模型和读模型之间存在延迟,用户可能读不到刚写入的数据。这需要在业务层面处理,比如在写入后立即返回写入的数据,而不是从读模型查询。其次是代码的复杂性:需要维护两套模型,写模型和读模型的代码是分离的,增加了开发和维护的工作量。再次是运维的复杂性:需要保证写模型和读模型的同步,处理同步失败的情况,监控数据的一致性。CQRS不是适用于所有场景的,只有在读写需求差异很大、查询场景复杂多样时,CQRS的优势才能体现。

CQRS的精髓在于分离关注点。写操作关注业务逻辑,读操作关注用户体验,两者的优化方向不同,不应该混在一起。这种思想可以推广到架构设计的各个层面:把变化快的和变化慢的分离,把核心的和边缘的分离,把同步的和异步的分离。分离不是目的,而是手段,目的是让每个部分都能做到最优。当我们把读和写分离,它们都获得了自由,可以选择最适合自己的技术栈、最适合自己的优化策略。这就是CQRS的魅力所在。CQRS告诉我们:不要试图用一个模型解决所有问题,有时候分离比统一更有价值。

在实践中,CQRS的应用要循序渐进。可以先从局部开始,选择读写差异最大的模块应用CQRS,积累经验后再推广。不要一开始就全面采用CQRS,那样风险太大。CQRS是一种强大的模式,但也是一种复杂的模式,需要团队有足够的能力驾驭。当读写需求真的差异很大,当查询场景真的很复杂,CQRS才是值得的。否则,简单的CRUD模式可能更合适。架构设计要务实,不要为了模式而模式。

CQRS的成功应用需要团队对业务有深刻的理解。只有真正理解了读和写的不同需求,才能设计出合理的读写模型。CQRS不是技术问题,而是业务问题。它要求我们从业务的角度思考:哪些操作是写?哪些操作是读?它们的需求有什么不同?如何优化它们?这种思考方式本身就很有价值,即使最终没有采用CQRS,这种思考也会让架构设计更清晰。

CQRS的实践告诉我们:分离是管理复杂性的有效手段。当两个事物的需求不同时,不要强行用一个方案解决,而是让它们各自优化。这种思维方式可以应用到架构设计的各个方面,帮助我们构建更清晰、更高效的系统。

最终,CQRS教会我们的是:不要害怕分离。当两个事物的需求不同时,让它们独立发展,往往比强行统一更好。这是架构设计的智慧,也是生活的智慧。