软件设计模式是解决软件设计中常见问题的通用、可复用的解决方案。设计模式让咱们能够分享通用词汇并使用经实战检验的方案,以避免重复造轮子。如今,我将介绍一系列设计模式来实现这些最佳实践。html
当一家公司将大型单体系统替换成一组微服务,首先要面临的最重要决策是关于数据库。单体架构会使用大型中央数据库。即便转移到微服务架构许多架构师仍倾向于保持数据库不变。虽然有一些短时间收益,但它倒是反模式的,特别是在大规模系统中,微服务将在数据库层严重耦合,整个迁移到微服务的目标都将面临失败(例如,团队受权、独立开发等问题)。前端
更好的方法是为每一个微服务提供本身的数据存储,这样服务之间在数据库层就不存在强耦合。这里我使用数据库这一术语来表示逻辑上的数据隔离,也就是说微服务能够共享物理数据库,但应该使用分开的数据结构、集合或者表,这还将有助于确保微服务是按照领域驱动设计的方法正确拆分的。java
图片程序员
优势数据库
缺点后端
什么时候使用独享数据库设计模式
什么时候不宜使用独享数据库api
可用技术示例安全
全部 SQL、 NoSQL 数据库都提供数据的逻辑分离(例如,单独的表、集合、结构、数据库)。markdown
延伸阅读
微服务模式:独享数据库 microservices.io/patterns/da…
分布式数据存储 docs.microsoft.com/en-us/dotne…
在微服务架构中,特别使用独享数据库时,微服务之间须要进行数据交换。对于弹性高可伸缩的和可容错的系统,它们应该经过交换事件进行异步通讯。在这种状况,您可能但愿进行相似更新数据库并发送消息这样的原子操做,若是在大数据量的分布式场景使用关系数据库,您将没法使用两阶段锁协议(2PL),由于它没法伸缩。而 NoSQL 数据库由于大多不支持两阶段锁协议甚至没法实现分布式事务。
这里为你们准备了一份小小的礼物,关注公众号【无聊学Java】,输入以下代码,便可得到!
0001:《程序员必读书籍》
0002:《从无到有搭建中小型互联网公司后台服务架构与运维架构》
0003:《互联网企业高并发解决方案》
0004:《Spring Cloud Alibaba实战视频》
0006:《SpringBoot实现点餐系统》
0007:《RabbitMQ最新实战视频》
0008:《Hadoop实战教学视频》
复制代码
在这些场景,能够基于事件的架构使用事件源模式。在传统数据库中,直接存储的是业务实体的当前“状态”,而在事件源中任何“状态”更新事件或其余重要事件都会被存储起来,而不是直接存储实体自己。这意味着业务实体的全部更改将被保存为一系列不可变的事件。由于数据是做为一系列事件存储的,而非直接更新存储,因此各项服务能够经过重放事件存储中的事件来计算出所需的数据状态。
图片
优势
缺点
什么时候使用事件源
什么时候不宜使用事件源
可用技术示例
事件存储:EventStoreDB, Apache Kafka, Confluent Cloud, AWS Kinesis, Azure Event Hub, GCP Pub/Sub, Azure Cosmos DB, MongoDB, Cassandra. Amazon DynamoDB
框架: Lagom, Akka, Spring, akkatecture, Axon,Eventuate
延伸阅读
事件驱动 martinfowler.com/eaaDev/Even…
事件驱动模式-云设计模式 docs.microsoft.com/en-us/azure…
微服务模式:事件驱动 microservices.io/patterns/da…
若是咱们使用事件源,那么从事件存储中读取数据就变得困难了。要从数据存储中获取实体,咱们须要处理全部的实体事件。有时咱们对读写操做还会有不一样的一致性和吞吐量要求。
这种状况,咱们可使用 CQRS 模式。在该模式中,系统的数据修改部分(命令)与数据读取部分(查询)是分离的。而 CQRS 模式有两种容易使人混淆的模式,分别是简单的和高级的。
在其简单形式中,不一样实体或 ORM 模型被用于读写操做,以下所示:
图片
它有助于强化单一职责原则和分离关注点,从而实现更简洁的设计。
在其高级形式中,会有不一样的数据存储用于读写操做。高级的 CQRS 一般结合事件源模式。根据不一样状况,会使用不一样类型的写数据存储和读数据存储。写数据存储是“记录的系统”,也就是整个系统的核心源头。
图片
对于读频繁的应用程序或微服务架构,OLTP 数据库(任何提供 ACID 事务保证的关系或非关系数据库)或分布式消息系统均可以被用做写存储。对于写频繁的应用程序(写操做高可伸缩性和大吞吐量),须要使用写可水平伸缩的数据库(如全球托管的公共云数据库)。标准化的数据则保存在写数据存储中。
对搜索(例如 Apache Solr、Elasticsearch)或读操做(KV 数据库、文档数据库)进行优化的非关系数据库常被用做读存储。许多状况会在须要 SQL 查询的地方使用读可伸缩的关系数据库。非标准化和特殊优化过的数据则保存在读存储中。
数据是从写存储异步复制到读存储中的,因此读存储和写存储之间会有延迟,但最终是一致的。
优势
缺点
什么时候使用 CQRS
什么时候不宜使用 CQRS
可用技术示例
写存储:EventStoreDB, Apache Kafka, Confluent Cloud, AWS Kinesis, Azure Event Hub, GCP Pub/Sub, Azure Cosmos DB, MongoDB, Cassandra. Amazon DynamoDB
读存储: Elastic Search, Solr, Cloud Spanner, Amazon Aurora, Azure Cosmos DB, Neo4j
框架: Lagom, Akka, Spring, akkatecture, Axon, Eventuate
延伸阅读
bliki:CQRS martinfowler.com/bliki/CQRS.…
CQRS模式 - Azure 架构中心 docs.microsoft.com/en-us/azure…
微服务模式:命令和查询职责分离(CQRS) microservices.io/patterns/da…
若是微服务使用独享数据库,那么经过分布式事务管理一致性是一个巨大的挑战。你没法使用传统的两阶段提交协议,由于它要么不可伸缩(关系数据库),要么不被支持(多数非关系数据库)。
但您仍是能够在微服务架构中使用 Saga 模式实现分布式事务。Saga 是 1987 年开发的一种古老模式,是关系数据库中关于大事务的一个替代概念。但这种模式的一种现代变种对分布式事务也很是有效。Saga 模式是一个本地事务序列,其每一个事务在一个单独的微服务内更新数据存储并发布一个事件或消息。Saga 中的首个事务是由外部请求(事件或动做)初始化的,一旦本地事务完成(数据已保存在数据存储且消息或事件已发布),那么发布的消息或事件则会触发 Saga 中的下一个本地事务。
图片
若是本地事务失败,Saga 将执行一系列补偿事务来回滚前面本地事务的更改。
Saga 事务协调管理主要有两种形式:
优势
缺点
什么时候使用 Saga
什么时候不宜使用 Saga
可用技术示例
Axon, Eventuate, Narayana
延伸阅读
Saga分布式事务-Azure设计模式 docs.microsoft.com/en-us/azure…
微服务模式:Sagas microservices.io/patterns/da…
Saga 模式:微服务中的应用程序事务 blog.couchbase.com/saga-patter…
在现代商业应用开发,特别是微服务架构中,先后端应用是分离和独立的服务,它们经过 API 或 GraphQL 链接。若是应用程序还有移动 App 客户端,那么 Web 端和移动客户端使用相同的后端微服务就会出现问题。由于移动客户端和 Web 客户端有不一样的屏幕尺寸、显示屏、性能、能耗和网络带宽,它们的 API 需求不一样。
面向前端的后端模式适用于须要为特殊 UI 定制单独后端的场景。它还提供了其余优点,好比做为下游微服务的封装,从而减小 UI 和下游微服务之间的频繁通讯。此外,在高安全要求的场景中,BFF 为部署在 DMZ 网络中的下游微服务提供了更高的安全性。
图片
优势
缺点
什么时候使用 BFF
什么时候不宜使用 BFF
可用技术示例
任何后端框架(Node.js,Spring,Django,Laravel,Flask,Play,…)都能支持。
延伸阅读
Sam Newman - 面向前端的后端 samnewman.io/patterns/ar…
面向前端的后端模式 - 云设计模式 docs.microsoft.com/en-us/azure…
微服务模式:API 网关模式 microservices.io/patterns/ap…
在微服务架构中,UI 一般链接多个微服务。若是微服务是细粒度的(FaaS) ,那么客户端可能须要链接很是多的微服务,这将变得繁杂和具备挑战性。此外,这些服务包括它们的 API 还将不断进化。大型企业还但愿能有其余横切关注点(SSL 终止、身份验证、受权、节流、日志记录等)。
一个解决这些问题的可行方法是使用 API 网关。API 网关位于客户端 APP 和后端微服务之间充当 facade,它能够是反向代理,将客户端请求路由到适当的后端微服务。它还支持将客户端请求扇出到多个微服务,而后将响应聚合后返回给客户端。它还支持必要的横切关注点。
图片
优势
缺点
什么时候使用 API 网关
什么时候不宜使用 API 网关
可用技术示例
Amazon API 网关, Azure API 管理, Apigee, Kong, WSO2 API 管理器
延伸阅读
微服务模式:API 网关模式 microservices.io/patterns/ap…
API 网关-Azure 架构中心 docs.microsoft.com/en-us/azure…
若是想在运行中的项目中使用微服务架构,咱们须要将遗留的或现有的单体应用迁移到微服务。将现有的大型在线单体应用程序迁移到微服务是至关有挑战性的,由于这可能破坏应用程序的可用性。
一个解决方案是使用 Strangler 模式。Strangler 模式意味着经过使用新的微服务逐步替换特定功能,将单体应用程序增量地迁移到微服务架构。此外,新功能只在微服务中添加,而再也不添加到遗留的单体应用中。而后配置一个 Facade (API 网关)来路由遗留单体应用和微服务间的请求。当某个功能从单体应用迁移到微服务,Facade 就会拦截客户端请求并路由到新的微服务。一旦迁移了全部的功能,遗留单体应用程序就会被“扼杀(Strangler)”,即退役。
优势
缺点
什么时候使用 Strangler
什么时候不宜使用 Strangler
可用技术示例
API 网关后端应用框架。
延伸阅读
bliki:StranglerFig 应用程序 martinfowler.com/bliki/Stran…
Strangler 模式 - 云设计模式 docs.microsoft.com/en-us/azure…
微服务模式:Strangler 应用程序 microservices.io/patterns/re…
在微服务架构中,微服务经过同步调用其余服务来知足业务需求。服务调用会因为瞬时故障(网络链接缓慢、超时或暂时不可用) 致使失败,这种状况重试能够解决问题。然而,若是出现了严重问题(微服务彻底失败),那么微服务将长时间不可用,这时重试没有意义且浪费宝贵的资源(线程被阻塞,CPU 周期被浪费)。此外,一个服务的故障还会引起整个应用系统的级联故障。这时快速失败是一种更好的方法。
在这种状况,可使用断路器模式挽救。一个微服务经过代理请求另外一个微服务,其工做原理相似于电气断路器,代理经过统计最近发生的故障数量,并使用它来决定是继续请求仍是简单的直接返回异常。
断路器能够有如下三种状态:
优势
缺点
什么时候使用断路器
什么时候不宜使用断路器
可用技术示例
API 网关,服务网格,各类断路器库(Hystrix, Reselience4J, Polly)。
延伸阅读
bliki:断路器 martinfowler.com/bliki/Circu…
断路器模式 - 云设计模式 docs.microsoft.com/en-us/azure…
微型服务模式:断路器 microservices.io/patterns/re…
每一个业务应用都有许多用于各类基础设施的配置参数(例如,数据库、网络、链接的服务地址、凭据、证书路径)。此外在企业应用程序一般部署在各类运行环境(Local、 Dev、 Prod)中,实现这些的一个方法是经过内部配置。这是一个致命糟糕实践,它会致使严重的安全风险,由于生产凭证很容易遭到破坏。此外,配置参数的任何更改都须要从新构建应用程序,这在在微服务架构中会更加严峻,由于咱们可能拥有数百个服务。
更好的方法是将全部配置外部化,使得构建过程与运行环境分离,生产的配置文件只在运行时或经过环境变量使用,从而最小化了安全风险。
优势
缺点
什么时候使用外部化配置
什么时候不宜使用外部化配置
可用技术示例
几乎全部企业级的现代框架都支持外部化配置。
延伸阅读
微服务模式:外部化配置 microservices.io/patterns/ex…
一次构建,处处运行:外部化你的配置 reflectoring.io/externalize…
在微服务架构中,一般有许多有不一样团队开发的微服务。这些微型服务协同工做来知足业务需求(例如,客户请求),并相互进行同步或异步通讯。消费端微服务的集成测试具备挑战性,一般用 TestDouble 以得到更快、更低成本的测试运行。可是 TestDouble 一般并不能表明真正的微服务提供者,并且若是微服务提供者更改了它的 API 或 消息,那么 TestDouble 将没法确认这些。另外一种选择是进行端到端测试,尽管它在生产以前是强制性的,但倒是脆弱的、缓慢的、昂贵的且不能替代集成测试(Test Pyramid)。
在这方面消费端驱动的契约测试能够帮助咱们。在这里,负责消费端微服务的团队针对特定的服务端微服务,编写一套包含了其请求和预期响应(同步)或消息(异步)的测试套件,这些测试套件称为显式的约定。对于微服务服务端,将其消费端全部约定的测试套件都添加到其自动化测试中。当特定服务端微服务的自动化测试执行时,它将一块儿运行本身的测试和约定的测试并进行验证。经过这种方式,契约测试能够自动的帮助维护微服务通讯的完整性。
优势
缺点
什么时候使用需求驱动的契约测试
什么时候不宜使用消费端驱动的契约测试
可用技术示例
Pact, Postman, Spring Cloud Contract
延伸阅读
需求驱动契约:一种服务演进模式 martinfowler.com/articles/co…
微服务模式:服务集成契约测试 microservices.io/patterns/te…
什么是消费端驱动的契约测试? pactflow.io/what-is-con…
在现代大规模企业软件开发中,微服务架构可以帮助开发扩展规模并带来不少长期收益。可是微服务架构并非随处可用的银弹,若是应用在错误的应用程序类型,微服务架构将弊大于利。但愿采用微服务架构的开发团队应该遵循最佳实践,并使用一系列可重用的、久经锤炼的设计模式。
微服务架构中相当重要的设计模式是独享数据库。实现这种设计模式具备挑战性,须要其余几种密切相关的设计模式(事件驱动、 CQRS、 Saga)来支持。在具备多个客户端(Web、 Mobile、 Desktop、 Smart Devices)的典型业务应用程序中,客户端和微服务之间的通讯量多是很大的,而且须要统一的安全控制,在这种状况面向前端的后端和 API 网关的设计很是有用。此外,断路器模式能够大大地帮助应对这类应用程序的错误处理场景。迁移遗留的单体应用到微服务是极具挑战性的,而 Strangler 模式能够帮助作到这点。消费端驱动的契约测试是微服务集成测试的基础模式。另外外部化配置是任何现代化应用程序开发中的一种必备模式。
这个系列并不全面,在实际状况中您可能须要其余的设计模式,但这个系列能为您提供一个关于微服务架构设计模式的极好介绍