微服务之模式
[TOC]
Microservices.io官网给我们提供了一套微服务的方法论,就是有关微服务架构会用到的“模式语言”。
A pattern language is a method of describing good design practices or patterns of useful organization within a field of expertise.
一、核心
问题:应用的架构是什么?
1单体模式
整个应用打包成一个war包,部署在web容器内,系统按照MVC模式分成表示层、模型层、控制层三层。
优点:易于开发、测试、部署,水平扩展。
缺点:随着系统功能越来越多,越来越不便于理解和变更,可扩展性低,难以满足持续集成部署,无法及时响应敏捷开发。
2微服务模式
整个架构由一系列松散耦合的服务组成。每个服务提供一组内部关联的功能,如订单管理、客户管理。服务之间通过HTTP同步通信,通过AMQP异步通信。每个服务可以有自己的数据库,可独立开发、部署。
二、分解
问题:如何把单体分解成多个服务?
1按业务能力
业务能力是业务架构建模的概念。这是企业为了创造价值而做的事情。业务能力通常对应于业务对象,例如柜员管理、机构管理、产品管理、权限管理、参数管理、流水管理、流程管理、贷款管理、客户管理、账号管理、额度管理等。
2按子领域
将服务定义为与领域域驱动设计(DDD)子域对应。DDD指的是应用程序将业务作为领域。一个域由多个子域组成。每个子域对应于业务的不同部分。
分解的核心就是按照业务部门的组织架构找出相应的领域对象。
三、部署
问题:如何部署微服务?
单机多实例
单机单实例
单虚拟机单实例
单容器单实例
Serverless平台
PaaS平台
四、横切关注点
问题:如何让微服务不需修改就能在多种环境运行(开发、测试、生产)?
外部化配置
通过将服务的配置外部化,让微服务在启动的时候从外部环境获取到所有配置信息。
五、通信方式
问题:如何实现微服务之间的通信?
1.RPI远程过程调用
通过基于请求/响应的协议实现服务间、客户端与服务间的通信,如REST、Apache Thrift、gRPC。
优点:
请求/响应的方式简单直接;
没有中间代理,简化了通信过程;
缺点:
不支持请求/异步响应,发布/订阅,发布/异步响应等通信模式;
客户端和服务之间的延时可能会降低可用性;
2.消息通信
通过异步消息实现服务间的通信,如Apache Kafka、RabbitMQ。
优点:
服务之间可以松耦合;
由消息代理缓存消息提高服务可用性;
支持多种通信模式:请求/响应,通知,请求/异步响应,发布/订阅,发布/异步响应。
缺点:
消息代理让通信方式更加复杂,需要保证高可用;
3.特定协议
使用特定协议实现服务间通信,如邮件协议SMTP,IMAP,流媒体协议RTMP,HLS,HDS。
六、外部API
问题:如何对外发布微服务的api给其他客户端调用?
1.API网关
通过对外提供一个统一的API网关入口,负责转发客户端的请求到对应的服务。将前后端分离,避免客户端对微服务直接请求。
也可以是针对不同的客户端提供不同的api网关入口
七、服务发现
问题:如何让客户端找到可用的微服务?
服务注册
由一个服务注册中心来维护可用服务的清单,微服务启动的时候将自己的实例信息、位置发送到注册中心进行登记,关闭的时候向注册中心注销。注册中心如:Apache Zookeeper,Eureka,Consul。
客户端的服务发现
服务端的服务发现
八、可用性
问题:如何防止网络或服务失败从级联到其他服务?
断路器
客户端通过代理方式调用远程服务,从而使其类似电路断路器。当连续故障数超过阈值或超时,断路器被触发,所有调用远程服务的尝试直接失败。超时结束后,断路器允许重试,如果请求成功,断路器恢复正常运行。否则,如果出现故障,重新计算超时时间。
九、数据管理
单服务单数据库
共享数据库
问题:如何维护跨服务之间的数据一致性?
当每个微服务一个数据库时,对于跨服务的交易需要有保证数据一致性的机制,因为不能直接使用本地的ACID事务控制。
1.Saga
将跨多个服务的业务事务使用Saga实现。Saga是本地事务的一个队列。每个本地事务都更新数据库并发布消息或事件来触发该事件中的下一个本地事务。如果本地事务失败,或违反了业务规则,则该事件执行一系列补偿事务,撤消前面本地事务所做的更改。
优点:
它允许应用程序在不使用分布式事务的情况下维护跨服务的数据一致性。 缺点:
程序更加复杂。例如,需要设计补偿事务,用于撤消了先前所做的更改。 服务必须自动更新其数据库并发布事件。因为不能使用传统的分布式事务的机制。Saga依赖下面列出的模式。
问题:如何在状态更改时原子性的发布事件?
2.事件溯源
事件溯源通过一个状态变化事件的队列来保存业务实体的状态。每当业务实体的状态发生变化时,就添加一个新事件到事件队列中,这个动作是原子性的。可以通过重放这些事件来重构业务实体的当前状态。事件保存在一个事件仓库中,提供api用于添加事件和查询业务实体的事件。
优点:
它解决了事件驱动架构中的一个关键问题,即在状态更改时可靠地发布事件;
它提供了100%份可靠的审计日志,记录了对业务实体所做的更改;
它使得能够实现时间查询来确定某个实体在任何时刻的状态;
基于事件驱动的业务实体是松耦合的,这使得更容易从单体应用程序迁移到基于微服务的架构。
缺点:
这是一种不同的编程风格,会有学习曲线;
事件存储很难查询,需要特定的查询方式来重构业务实体的状态,增加了复杂度;
应用程序必须使用命令查询责任隔离(CQRS)来实现查询;
应用程序须处理数据的最终一致性。
3.交易日志追踪
追踪数据库事务日志并将每个更改发布为事件。
优点:
不用2pc;
不需要更改应用程序;
保证准确;
缺点:
很复杂;
针对特定数据库的解决方案;
很难避免重复发布;
低级别db更改难以确定业务级别事件。
4.数据库触发器
通过一个或多个数据库触发将事件插入事件表,由单独的进程轮询该事件表发布事件。
优点:
高级别域事件;
不用2pc
缺点:
需要对应用程序进行更改,易出错;
很难避免重复发布;
很难按顺序发布事件;
只适用于sql型数据库;
5.应用事件
通过应用程序将事件插入事件表作为本地事务的一部分。由单独的进程轮询事件表并将事件发布到消息代理中。
问题:如何在多微服务间实现查询?
6.API组合器
通过定义一个api组合器来实现查询,该api调用拥有数据的服务并在内存实现结果join连接。
7.CQRS
将应用程序拆分为两个部分:命令端和查询端。命令端负责创建、更新和删除,并在数据发生更改时发出事件。查询端通过执行一个或多个物化视图来处理查询,通过订阅数据更改时发出的事件流来保持最新的物化视图。
十、安全
问题:如何将请求者的身份传递给处理请求的服务?
访问Token
由api网关验证请求并传递访问令牌,该令牌标识请求者向服务发送请求。服务可以在请求加入令牌进行对其他服务的请求。
十一、测试
问题:如何测试服务是否提供了客户端想要的api?
合约测试Contract Test
由服务的调用者来提供一个合约,表明该服务应该提供的功能。测试验证服务符合服务消费者的期望。
十二、可监控性
问题:如何观察应用程序的行为并排除问题?
日志集合
收集各个服务的应用日志,用于分析。
应用指标
收集关于个别操作的统计信息和各种指标。有两个用于聚合度量的模型:
推送-服务将度量推到度量服务;
拉取-度量服务从服务中提取度量;
审计日志
把用户活动记录在数据库中。
分布式链路追踪
通过请求id记录请求的交易的链路。
健康检查
服务提供一个健康检查api端点,用于外部查询该服务的可用状态。