微服务之CRQS设计
CQRS是命令查询职责隔离(Command Query Responsibility Segregation)的简称。其主要实现核心是通过使用事件来维护从多个服务复制数据的只读视图,借此实现对来自多个服务的数据查询操作。CQRS将对持久化数据的使用划分成两个部分:命令端和查询端。
命令端:负责数据的增删改(CUD)操作
查询端:负责数据的查询(R)操作
这里需要说明的是,CQRS不是简单的数据读写分离,通常我们说的读写分离是指为了提升数据库的效率,将数据库分为读库和写库,写库负责CUD操作,读库负责R操作,但是读写分离有一个大前提,就是两套数据库里的数据是一致的(实时同步)。但是CQRS的查询库并不是和CUD主库是一致的数据,而是通过订阅一些应用事件,同步更新过来的有查询需求的数据。甚至中间可能还存在一层数据加工的过程。
优缺点
在许多方面,CQRS也代表了当前流行的基于事件的数据库应用场景,例如它使用关系型数据库作为记录系统,使用文本搜索引擎(如 Elasticsearch)来处理文本查询。不同之处在于CQRS使用更广泛的数据库类型,而不仅仅是文本搜索引擎。此外,通过订阅事件,近乎实时的更新CQRS查询端视图。
优点
在微服务架构中高效的实现查询(聚合了多数据源,统一了查询视图数据)
高效地实现多种不同的查询类型(视图数据库可以是多种类型的体现)
在基于时间溯源技术的应用程序中实现查询。
更进一步的实现了问题隔离
缺点
更加复杂的架构:开发人员必须编写更新和查询视图的查询端服务,管理和运维额外的数据存储,提高了运维成本。
处理数据复制导致的延迟:基于事件同步数据必然存在一定的延迟
设计CQRS视图
通常一个CRQS视图包括事件处理程序、查询API、数据访问模块和视图数据库四部分:
事件处理器:通过订阅多个事件聚合更新视图数据库
查询API:对外暴露的统一查询接口
数据访问模块:封装对视图数据库的访问逻辑,包括DAO层转换,数据幂等更新、并发处理等功能。
视图数据库:根据CQRS实际业务需求,提供视图数据查询支撑的数据库(SQL、NoSql)。
通常在开发试图模块时,我们要遵守一些通用的重要原则:
必须选择适的低层数据库,并且设计数据库结构。
在设计数据访问模块时,必须解决各种数据访问问题,包括确保更新是幂等的、能够处理并发更新等常见问题。
在现有应用程序中实现新视图或更改现有应用程序的模式时,必须实现一种机制,以便有效地构建或重建视图(即维护视图的可扩展性)。
必须决定如何设计视图的客户端,以应对数据通过事件同步带来的延迟问题(即业务调用方要剧本重试或者可接受数据延迟的问题),建议客户端应用程序采用最终一致性的视图。
关键的设计决策还是在数据库的选择和数据库结构的设计上面,数据库和数据库模型的存在主要的目的是有效地实现视图模块的查询操作。在一些场景下,NoSQL数据库比SQL数据库更有优势,主要体现在灵活的数据模型以及更好的性能和可扩展性方面。但有时选择SQL数据库也是有意义的,可以根据各团队的技术栈水平,运维能力等多方面因素来衡量,MySQL针对Json格式的支持让其突破了传统关系型数据库的数据结构关联瓶颈,也可以满足我们日常的一些查询模型需求。
使用场景 | 建议选型 | 举例说明 |
基于主键的JSON对象查询 | 文档型数据库。例如MongoDB或DynamoDB,或者使用Redis这样的键值存储数据库。 | 根据登录账号获取博文信息。 |
基于查询的JSON对象查找 | 文档型数据库。例如MongoDB或DynamoDB | 根据楼主论坛,查询评论信息。 |
文本查询 | 文本搜索引擎,例如Elasticsearch。 | 根据订单编号查询订单详情的文本搜索或订单交易日志详情。 |
图查询 | 图数据库,例如Neo4j。 | 通过维护客户、订单和其他数据的图表来实现欺诈检查。 |
传统的SQL报表/BI | 关系型数据库,例如MySQL、Oracle、SQLServer等。 | 标准业务报表和分析 |