第7章 在微服务架构中实现查询

  • 前言
  • 1. 使用API组合模式进行查询
    • 1.1 findOrder()查询操作
    • 1.2 什么是API组合模式
    • 1.3 使用API组合模式实现findOrder()查询操作
    • 1.4 设计问题一:由谁来担任API组合器的角色
    • 1.5 设计问题二:如何编写有效的聚合逻辑
    • 1.6 API组合模式的好处与弊端
  • 2. 使用CQRS模式
    • 2.1 为什么要使用CQRS
    • 2.2 CQRS隔离命令与查询
    • 2.3 CQRS和查询专用服务
    • 2.4 CQRS的好处与弊端
  • 3. 设计CQRS视图
    • 3.1 选择视图存储库
    • 3.2 设计数据访问模块
    • 3.3 添加和更新CQRS视图
  • 4. 实现基于AWS DynamoDB的CQRS视图
    • 4.1 OrderHistoryService的设计
    • 4.2 OrderHistoryEventHandlers模块
  • 5. 本章小结
  • 最后

前言

在微服务架构中编写查询具有挑战性。查询通常需要检索分散在多个服务所拥有的数据库中的数据,使用传统的分布式查询处理机制虽然在技术上可行,但会打破服务之间的隔离与封装;

在微服务架构中实现查询操作有两种不同的模式:

  • API组合模式:这是最简单的方法,应尽可能使用。它的工作原理是让拥有数据的服务的客户端负责调用服务,并组合服务返回的查询结果;
  • 命令查询职责隔离(CQRS)模式:它比API组合模式更强大,但也更复杂。它维护一个或多个视图数据库,其唯一的目的是支持查询;

这是一本关于微服务架构设计方面的书,这是本人阅读的学习笔记。下面对一些符号做些说明:

()为补充,一般是书本里的内容;
[]符号为笔者笔注;


1. 使用API组合模式进行查询

1.1 findOrder()查询操作

findOrder()查询操作是从多个服务获取数据的查询方法;


图解:基于微服务架构的FTGO应用程序版本中,数据分散在以下服务中;

  • Order Service:基本订单信息,包括详细信息和状态;
  • Kitchen Service:从餐馆的角度看订单的状态以及预计取餐时间;
  • Delivery Service:订单的交付状态、预计送餐时间及送餐员的当前位置;
  • Accounting Service:订单的付款状态;

1.2 什么是API组合模式


图解

  • API组合模式:通过查询每个服务的API并组合结果,实现从多个服务检索数据的查询;
  • 其有两种类型的参与者:
    • API组合器:它通过查询数据提供方的服务来实现查询操作;
    • 数据提供方服务:拥有查询返回的部分数据的服务;
  • 是否可以使用此模式实现特定查询操作取决于几个因素,包括数据的分区方式、拥有数据的服务公开的API的功能,以及服务使用数据库的功能;

1.3 使用API组合模式实现findOrder()查询操作


图解

  • 四个提供方服务实现一个REST接口,该接口返回对应于单个聚合的响应;

1.4 设计问题一:由谁来担任API组合器的角色

由服务的客户端

  • 缺点:对于防火墙之外的客户以及通过较慢网络访问的服务,此选择不可用(详情查看第八章);

由实现应用程序外部API的API Gateway

  • 可以使得在防火墙外运行的客户端能够通过单个API调用有效地从众多服务中检索数据;

将API组合器实现为独立的服务

  • 在外部访问查询时,由于其聚合逻辑过于复杂,因此无法在API Gateway中完成查询,必须使用单独的服务;

1.5 设计问题二:如何编写有效的聚合逻辑

  • 应该使用响应式编程模型

    • 有时API聚合器需要一个提供方服务的结果才能调用另一个服务;在这种情况下,它需要按顺序调用一部分提供方服务;
    • 应该使用基于Java CompletableFuture、RxJava可观测或其他类似的响应式设计(详情见《第8章 API Gateway模式》);

1.6 API组合模式的好处与弊端

好处

  • 实现查询操作简单直观;

弊端

  • 增加了额外的开销:涉及多个请求和数据库查询,需要更多的计算和网络资源;
  • 带来可用性降低的风险:操作的可用性随着所涉及的服务数量而下降;
    • 解决办法:在提供方不可用时,返回先前缓存的数据;或者让API组合器返回不完整的数据;
  • 缺乏事务数据一致性

2. 使用CQRS模式

2.1 为什么要使用CQRS

  • 涉及多个服务的查询,API组合模式无法有效实现;

    • 因为并非所有服务都存储用于过滤或排序的属性,如Order Service和Kitchen Service两项服务存储了Order的菜单项,而Delivery Service和Accounting Service都不存储菜单项;
    • 解决办法:让API组合器进行内存中连接;让API组合器从Order Service和Kitchen Service检索匹配的订单,然后通过ID从其他服务请求订单;
  • CQRS可以解决服务的数据库(数据模型)不能有效查询的问题;
    • 如:在进行地理空间查询时会生成数据副本,CQRS解决了同步副本问题;
  • CQRS考虑隔离问题的必要性,避免过多的职责导致过载服务;

2.2 CQRS隔离命令与查询


图解

  • 位于命令端的领域模型处理CRUD操作并映射到其自己的数据库;
  • 命令端在数据发生变化时发布领域事件;

2.3 CQRS和查询专用服务


图解

  • 查询服务的API只包含查询操作,并无命令操作;
  • 它通过订阅一个或多个其他服务发布的事件来确保它的数据库是不断更新的,并由此实现查询操作;
  • 查询端服务订阅由多个服务发布的事件;

2.4 CQRS的好处与弊端

好处

  • 在微服务架构中高效地实现查询;
  • 高效地实现多种不同的查询类型;
  • 在基于事件溯源技术的应用程序中实现查询;
  • 更进一步地实现问题隔离;

弊端

  • 更加复杂的架构:开发人员必须编写更新和查询视图的查询端服务;
  • 处理数据复制导致的延迟;
    • 即:更新聚合后查询聚合会看到聚合的先前版本;
    • 解决方案:采用命令端和查询端API为客户端提供版本信息,使其能够判断查询端是否过时;

3. 设计CQRS视图

CQRS视图模块包括由一个或多个查询操作组成的API;

3.1 选择视图存储库

NoSQL

  • CQRS视图受益于NoSQL数据库更丰富的数据模型和性能,不受NoSQL数据库事务处理能力的限制;

SQL数据库

  • 在主流硬件上运行的现代关系型数据库具有出色的性能;
  • SQL数据库通常具有非关系特征的扩展,如地理空间数据类型和查询;
  • CQRS视图可能需要使用SQL数据库才能支持报表引擎;

支持更新操作

  • 通常使用其主键更新或删除视图数据库中的记录;
  • 有时需要使用类似外键的做法来更新或删除记录;

3.2 设计数据访问模块

事件处理程序和查询API模块不直接访问数据库存储区。相反,它们使用数据访问模块,该模块由数据访问对象(DAO)及其辅助类组成;

  • 处理并发更新确保更新幂等

    • 当视图订阅由多个聚合类型发布的事件时,多个事件处理程序可能同时更新同一记录;
  • 幂等事件处理程序
    • 为了确保可靠,事件处理程序必须记录事件ID并以原子化的方式更新数据存储区,如何试下取决于数据库类型;
    • 事件处理程序不需要记录每个事件的ID,每个记录仅需要存储从给定聚合实例接收的max(eventId);
  • 让客户端应用程序采用最终一致性的视图
    • 执行更新命令后执行查询命令可能看到的是更新前的数据 [有延迟],客户端可以使用以下方法检测这种不一致性:
    • 命令端操作将包含已发布事件和ID标记返回给客户端。然后,客户端将事件有关的ID传递给查询操作,如果该事件尚未更新视图,则返回查询错误;
    • 视图模块可以使用重复事件检测机制来实现这样的功能;

3.3 添加和更新CQRS视图

  • 添加和更新CQRS视图在概念上很简单,即:

    • 创建新视图:开发查询端模块、设置数据存储区并部署服务。查询端模块的事件处理程序处理所有事件,最终视图将是最新的;
    • 更新现有视图:更改事件处理程序并从头开始重构视图;
  • 但在实际中会产生一些问题,如下:
  • 消息代理无法无限期存储信息;
    • 如:RabbitMQ会在消费者处理完消息后删除该消息;Apache Kafka可在配置的保留期内保留消息,但也不会无限期存储事件;
    • 解决办法:使用归档事件构建CQRS视图,使用可扩展的大数据技术(如Apache Spark)实现;
  • 处理所有事件所需的时间和资源随时间推移而不断增长;
    • 解决办法:增量式构建CQRS视图,使用两步增量算法。第一步基于先前的快照和自创建快照以来发生的事件,定期计算每个聚合实例的快照;第二步使用快照和任何后续事件创建视图;

4. 实现基于AWS DynamoDB的CQRS视图

介绍如何使用DynamoDB为findOrderHistory()操作实现CQRS视图;

4.1 OrderHistoryService的设计

图解

  • OrderHistoryEventHandlers:订阅各种服务发布的事件并调用OrderHistoryDAO;
  • OrderHistoryQueryAPI模块:实现REST API接口;
  • OrderHistoryDataAccess:包含OrderHistoryDAO,它定义了更新和查询ftgo-order-history DynamoDB表及其辅助类的方法;
  • ftgo-order-history DynamoDB表:存储订单的DynamoDB表;

4.2 OrderHistoryEventHandlers模块

此模块由接收事件和更新DynamoDB表的事件处理程序组成;


图解

  • 每个事件处理程序都有一个DomainEventEnvelope类型的参数,其中包含事件和描述事件的一些元数据;

5. 本章小结

  • 实现从多个服务检索数据的查询具有挑战性,因为每个服务的数据都是私有的;
  • 有两种方法可以实现这些类型的查询:API组合模式和命令查询职责隔离(CQRS)模式;
  • 从多个服务获取数据的API组合模式是实现查询的最简单方法,应尽可能使用;
  • API组合模式的局限性是某些复杂查询需要大型数据集的低效内存连接;
  • 使用视图数据库实现查询的CQRS模式功能更强大,但实现起来更复杂;
  • CQRS视图模块必须处理并发更新以及检测和丢弃重复事件;
  • CQRS有助于改善问题隔离,服务不必为自己拥有的数据实现查询功能;
  • 客户必须处理CQRS视图的最终一致性;

最后

新人制作,如有错误,欢迎指出,感激不尽! 欢迎关注公众号,会分享一些更日常的东西! 如需转载,请标注出处!

《微服务架构设计模式》读书笔记 | 第7章 在微服务架构中实现查询相关推荐

  1. 微服务架构设计模式读书笔记

    1.总览 2.单体架构 2.1 单体架构好处 主要体现在早期 应用开发简单 易于对应用程序进行大规模的更改 测试相对简单直观 部署简单明了 横向扩展不费吹灰之力 2.2 局限性 过度的复杂性会吓退开发 ...

  2. 微服务架构设计模式 读书笔记一

    作者:[美] 克里斯·理查森(Chris Richardson) 是Java社区的著名布道师.JavaOne等知名技术大会的常年主讲人,也是<POJOs in Action>(中文名< ...

  3. Head First设计模式读书笔记八 第九章上 迭代器模式

    之前的总结: https://blog.csdn.net/u011109881/article/details/59677544 个人觉得本章节,HeadFirst讲的没有之前看到的网站讲的清晰,至少 ...

  4. 《分析服务从入门到精通读书笔记》第二章、分析服务工具篇

    Microsoft提供了一套完整的商业智能平台应用程序.使我们能够创建企业级.功能齐全的商业智能系统. Microsoft商业智能平台基于SQL Server 2008和Microsoft Offic ...

  5. linux多线程服务端编程读书笔记——第三章

    本章作者主要是总结了一两种常用的线程模型.归纳了进程通信与线程同步的最佳实践 进程与线程的区别: 进程是文件系统中的最重要的两个概念之一(令一个是文件).简单地说,一个进程是内存中正在运行的程序.每个 ...

  6. Head First设计模式读书笔记八 第九章下 组合模式

    之前的总结链接: https://blog.csdn.net/u011109881/article/details/58710579 对比headFirst书中的例子,我觉得书中的组合模式的例子比上面 ...

  7. 规模化微服务——《微服务设计》读书笔记

    改变思维的角度:故障无处不在 当微服务规模化后,故障是无可避免的,以往我们总是想尽力避免故障的发生,而当故障实际发生时,我们往往束手无策.我们花了很多时间在流程设计和应用设计的层面上来阻止故障的发生, ...

  8. 康威定律和系统设计——《微服务设计》读书笔记

    康威定律 任何组织在设计一套系统时,所交付的设计方案在结构上都与该组织的沟通结构保持一致. --梅尔.康威 如何理解这句话在软件工程上的含义?埃里克.S.雷蒙德说:如果你有四个小组开发一个编译器,那你 ...

  9. 安全——《微服务设计》读书笔记

    身份认证和授权       1.单点登录(SSO) 当主体试图访问一个资源,他会被定向到一个身份提供者那里进行身份验证,身份提供者验明正向后会发消息给服务提供者,让服务提供者来决定是否允许它访问资源. ...

  10. 监控——《微服务设计》读书笔记

    在单块应用的世界里,当我们遇到问题时,我们至少清楚从哪里开始调查.网站访问速度?网站访问异常?CPU占用过高?这些都是单块应用程序的问题,单一的故障点会极大地简化对问题的排查. 而现在我们面对了多个微 ...

最新文章

  1. 1080解析 芒果tv_国内主流视频平台解析下载观看
  2. Set Up a Simple Knowledge Base
  3. 关于SAP中物料双单位的解析
  4. windows简易使用composer 安装国内镜像
  5. 前端人员如何在linux服务器上搭建npm私有库
  6. Redux的全家桶与最佳实践
  7. 最大化窗口设置_Qt学习笔记4(窗口操作及插入图片)
  8. QGIS中如何加载identify
  9. 在d3中使用2D.js获取图形间的交点
  10. 【Unity开源项目精选】ML-Agents:给你的游戏加入AI
  11. tomcat启动startup出现闪退问题
  12. onlyoffice开发java_OnlyOffice功能及演示
  13. flexbuilder 4.6破解
  14. C语言中char字符为0时的情况,c语言中char的用法
  15. rabbitmq配置guest用户远程访问失败
  16. STM32F4系列定时器简介
  17. 如何使用Ajax更新echarts工作省份信息
  18. 获取手机电池百分比和电池容量方法
  19. 2022年下半年软考所有科目详情表
  20. TinyPng:在线PNG图片压缩工具

热门文章

  1. 太难了!河北承德程序员在GitHub远程给外企工作,105.8万元收入,竟全部没收!...
  2. 浪潮云开发者大会济南站成功召开 加速构筑“融合 开放 共享”生态
  3. 宝塔安装PHP占用多少内存,宝塔内存占用率高怎么办?解决办法分享一下
  4. minibatchgd代码_【DeepLearning】优化算法:SGD、GD、mini-batch GD、Moment、RMSprob、Adam...
  5. 舵机反向控制解决方案
  6. 一文速学数模-K-means聚类算法实战:信用卡用户画像聚类分析
  7. 开源PHP 代挂机源码,可对接QQ、网易云、哔哩哔哩、QQ空间、等级加速等等
  8. xc的java学习日记(Day04:循环结构)
  9. 全国首家火车站自助无人售票厅亮相南昌
  10. Qt6 QML Book/QtQuick控件/通用模板