零度编程命令和查询责任分离 (CQRS) 模式
命令和查询责任分离 (CQRS) 模式分隔数据存储的读取和更新操作 。 在应用程序中实现 CQRS 可以最大限度地提高其性能、可扩展性和安全性 。 迁移到 CQRS 创建的灵活性使系统能够随着时间的推移更好地发展 , 并防止更新命令在域级别引发合并冲突 。
问题
在传统的体系结构中 , 使用同一数据模型查询和更新数据库 。 这十分简单 , 非常适用于基本的 CRUD 操作 。 但是 , 在更复杂的应用程序中 , 此方法会变得难以操作 。 例如 , 在读取方面 , 应用程序可能执行大量不同的查询 , 返回具有不同形状的数据传输对象 (DTO) 。 对象映射可能会变得复杂 。 在写入方面 , 模型可能实施复杂验证和业务逻辑 。 结果 , 模型执行太多操作 , 过度复杂 。
读写工作负载通常是不对称的 , 具有非常不同的性能和规模要求 。
本文插图
数据的读写表示形式之间通常不匹配 , 例如必须正确更新的其他列或属性 , 即使这些列在操作的一部分不需要 。 当在同一组数据上并行执行操作时 , 可能会发生数据争用 。 由于数据存储和数据访问层的加载以及检索信息所需的查询的复杂性 , 传统方法可能会对性能产生负面影响 。 管理安全性和权限可能会变得复杂 , 因为每个实体都受读取和写入操作的约束 , 这可能会在错误的上下文中公开数据 。
CQRS 将读取和写入分离到不同的模型中 , 使用 命令更新 数据 , 查询用于读取数据 。命令应基于任务 , 而非以数据为中心 。("预订酒店客房" , 而不是"将预订状态设置为保留") 。 命令可以放置在队列中进行异步处理 , 而不是同步处理 。 查询从不修改数据库 。查询返回的 DTO 不封装任何域知识 。
然后可以隔离模型 , 如下图所示 , 尽管这不是绝对要求 。
本文插图
具有单独的查询和更新模型可简化设计和实现 。 但是 , 一个缺点是 CQRS 代码不能使用基架机制(如 O/RM 工具)从数据库架构自动生成 。
为更好地实现隔离 , 可将读取数据与写入数据通过物理方式分离 。 在此情况下 , 读取数据库可使用自己的已针对查询进行优化的数据架构 。 例如 , 它可以存储数据的具体化视图 , 从而避免复杂联接或复杂 O/RM 映射 。 它甚至可能使用不同类型的数据存储 。 例如 , 写入数据库可能是关系数据库 , 而读取数据库是文档数据库 。
如果使用单独的读写数据库 , 则必须保持同步 。 通常 , 每当编写模型更新数据库时 , 都会发布事件 , 从而完成这一目的 。 必须在一个事务中更新数据库和发布事件 。
本文插图
读取存储可以是写入存储的只读副本 , 或者读取和写入存储可以具有完全不同的结构 。 使用多个只读副本可以提高查询性能 , 尤其是在只读副本位于应用程序实例附近的分布式方案中 。
读取和写入存储的分离还允许彼此适当地缩放以匹配负载 。 例如 , 读取存储通常会遇到高于写入存储的负载 。
某些 CQRS 实现使用事件溯源模式 。 在此模式中 , 应用程序状态存储为事件序列 。 每个事件表示对数据所作的一系列更改 。 通过重播事件构造当前状态 。 在 CQRS 上下文中 , 事件溯源的一个好处是 , 可以使用相同的事件通知其他组件 — 特别是通知读模型 。 读模型使用事件创建当前状态的快照 , 这对查询而言更高效 。 但是 , 事件溯源增加了设计的复杂度 。
CQRS 的优势包括:独立缩放。CQRS 允许读取和写入工作负载独立缩放 , 这可能会减少锁争用 。 优化的数据架构。读取端可使用针对查询优化的架构 , 写入端可使用针对更新优化的架构 。 安全性 。更轻松地确保仅正确的域实体对数据执行写入操作 。 将问题分离。分离读取和写入端可使模型更易维护且更灵活 。大多数复杂的业务逻辑被分到写模型 。读模型会变得相对简单 。 查询更简单。通过将具体化视图存储在读取数据库中 , 应用程序可在查询时避免复杂联接 。
推荐阅读
- 博科园|太好了,在硅光电子芯片上实现:可编程的电路、可擦除的元件!
- 编程小火车|你在群里提的技术问题没人回答!是为什么?因为没注意这 4 点
- 哈工新欧液压测试台|labview组态编程的五大经验总结,助你开发过程事半功倍
- CSDN|如何在容器内高效编程?
- CSDN|“编程能力差,90%输在了选择上!”CTO:多数程序员都是瞎努力!
- 品影轩|5G引爆缘计算,下一个万亿市场来临:阿里云CDN边缘轻量编程环境
- 钛媒体APP|专访罗布乐思段志云:游戏、编程、出海多路并进
- ##还在吹嘘编程语言的应该就只有小白和培训机构了吧
- 「数字」全国政协委员丁磊:推动编程教育纳入我国基础教学体系
- zol中关村在线不支持局域网?命令与征服:重制版将上线