译自 Dapr as the Ultimate Microservices Patterns Framework 。
在软件开发界,微服务架构已成为行业标准。这种架构风格将应用拆分为多个服务,每个服务可独立部署,并围绕具体业务能力组织。这样的设计保证了灵活性、可扩展性和弹性,每个服务通常由专门的团队来监管。然而,这种方法虽带来诸多好处,也引入了复杂性。为应对这些挑战,开发者采用各种模式,借鉴传统软件开发中的经典设计模式,以提供构建健壮分布式系统的解决方案。对于那些渴望全面指南的人来说,Chris Richardson 的微服务知识库 microservices.io 提供了丰富的行业专家见解和最佳实践。
Chris Richardson 的微服务模式语言,配以 Dapr 的匹配功能
但是,仅了解这些模式是不够的。要在实际场景中实现它们,还需要工具和框架的支持。作为一流的微服务框架,Dapr 专为创建安全、弹性、可扩展和可观测的分布式应用而设计。它不仅与微服务模式一致;还放大了它们的潜力,简化和完善了实际实现。
下面我将逐一介绍 microservices.io 中概述的各种模式,阐明 Dapr 如何帮助实现每一种模式。尽管许多框架旨在解决微服务中固有的横切关注点,但 Dapr 有所不同。它的语言无关性、边车运行模式和对应用架构不加限制的立场,使其成为微服务工具箱中独特且无与伦比的资产。
启动开发应用时,开发者往往要投入大量时间处理诸如安全性、外部配置、日志、健康检查、指标和分布式追踪等横切关注点。虽然这些看似简单,但为将在数十个或数百个服务中使用的一组精心策划的依赖进行配置,可能是一项复杂的努力。采用微服务架构后,这种挑战将进一步加剧,因为服务的数量众多,且经常新增服务。微服务底盘模式提供了一个解决方案,建议创建一个框架作为微服务开发的基础。该框架提供了可重用的构建逻辑和机制来处理这些横切关注点,简化了开发流程。
作为一个跨语言的框架,Dapr 完美地处理了横切关注点,使开发者能集中精力开发核心功能,而不被复杂性所困扰。它内置了安全性、配置管理、日志等多种机制。通过诸如访问控制、配置 API、健康检查 API 等功能,Dapr 确保这些基础关注点得以无缝集成,使开发者能专注于核心业务逻辑,而不必陷入这些关注点的细节。与其他框架不同,Dapr 不对应用施加约束,使开发者有自由选择首选语言、运行时和编程范式。简而言之,Dapr 将微服务底盘模式的理论优势转化为实际应用的有形成果。
在微服务中,常需要在不修改核心服务逻辑的情况下为服务增强功能。边车模式正是为此而生。它将应用的组件部署到单独的进程或容器中,提供模块化和可扩展的架构。主服务在一个容器中运行,而扩展或增强主服务的边车服务则在同一网络命名空间的独立容器中运行。这确保主服务和边车可像在同一进程中一样通信,同时相互隔离。这种模式的主要优势是能够解耦关注点,使应用程序模块化,确保每个组件专注于特定的职责。
Dapr 是边车模式最受欢迎的实现之一。集成到微服务环境后,Dapr 作为服务的边车运行,提供大量额外功能,无需修改主服务。这包括状态管理、服务调用、发布/订阅等功能。利用 Dapr 的边车架构,开发者可以增强服务功能,打造一个强大、可扩展、功能丰富的微服务生态系统。
随着服务数量的增长,管理服务间通信、安全性和可观测性变得愈发复杂。服务网格是一个专门的基础设施层,用于以透明的技术中立方式处理服务间通信。它提供诸如负载均衡、服务发现、可观测性和安全性等功能,无需更改应用代码。通过将这些职责卸载到服务网格,开发者可以专注于构建业务逻辑,而网格确保服务可以安全高效地相互通信。
Dapr 与服务网格比较
Dapr 运行于轻量级服务网格之上,提供了促进服务发现并确保安全服务间通信的网络层。尽管 Dapr 和传统服务网格具有重叠的功能,但 Dapr 区别于后者的是面向开发者,关注简化微服务开发的构建块。与主要面向基础设施且处理 IP 和 DNS 等网络概念的服务网格不同,Dapr 通过名称提供服务发现和调用,这对开发者更友好。除了诸如 mTLS 加密、指标收集和分布式追踪等常见功能,Dapr 还引入了状态管理、发布/订阅等应用级构建块。这确保开发者获得全面的工具集,不仅用于网络,还用于整体微服务开发。
在微服务世界,跨服务保持数据一致是一个挑战,特别是每个服务都有自己的数据库时。Saga 模式为此提供了解决方案。它不依赖传统的分布式事务,而是将事务分解为一系列本地事务,每个在其服务和数据库内执行。这些本地事务以特定顺序协调,以保证整体数据一致性。如果一个本地事务失败,将执行补偿事务来撤销之前事务的更改。这种方法实现了维护数据一致性,无需分布式事务,后者在微服务架构中往往不可行。
Dapr 工作流概述
Dapr 通过其工作流 API 实现了 Saga 模式。该 API 使开发者可以对本地事务进行编排,或实现其他有状态的工作流模式,以保证服务间的数据一致性。Dapr 的工作流 API 在这方面发挥着基础工具的作用,简化了流程并确保可靠性。
在微服务架构中,一个常见挑战是服务命令既要更新数据库中的聚合,又要向消息代理发送消息或事件。目标是保证原子性——如果数据库事务提交,必须发送消息;如果数据库回滚,不得发送消息。由于各种限制,传统的分布式事务不可行或不可取。事务输出箱模式解决了这个问题。它建议服务将消息存储在数据库事务中,作为更新业务实体的一部分。然后,独立进程检索并发送这些消息到消息代理。这保证只有数据库事务提交时才发送消息,维护数据一致性和操作顺序。
Dapr 通过其 StateStore API 中的 Outbox 功能为此提供了健壮的解决方案。该功能实现了原子更新数据库的同时向指定代理发送消息。利用 StateStore API,开发者可以无缝集成事务输出箱模式到微服务中,确保跨大量数据库和消息代理实现数据一致性和可靠的消息传递。
在微服务领域,服务间可靠的异步通信至关重要。与服务直接同步调用不同,服务通过消息信道交换消息。这种异步通信方式解耦了服务,使其可以独立运行。即使一个服务速度慢或者不可用,其他服务也可以继续运行而不受直接影响。这提高了系统的弹性、可扩展性和灵活性。
Dapr 的发布/订阅 API 专为利用异步消息进行服务间通信而设计。利用该 API,开发者可以轻松在微服务架构中实现消息传递模式。发布/订阅 API 确保可靠消息传递,支持多个消息代理,并抽象出与代理直接交互的复杂性。
远程过程调用(RPI)使微服务架构中的服务可以通过调用远程服务中的方法相互通信。远程过程调用的主要优点是直接明了,允许服务间点对点通信。但是,管理相关的挑战如服务发现、可靠性、加密等仍非常重要,以确保系统的弹性和安全。
Dapr 通过其服务调用 API 解决了这些挑战。该 API 提供了一种针对微服务的基于远程过程调用的协议。通过抽象底层复杂性,Dapr 确保服务可以进行同步通信,而不会陷入直接服务调用的复杂性。此外,Dapr 的服务调用 API 内置重试、错误处理和流量控制等功能,保证通信的可靠性和安全性。
在微服务架构中,服务通常协作处理请求。但是,当一个服务同步调用另一个服务时,所调用的服务可能不可用或延迟很高,失去响应能力。这可能导致调用服务资源耗尽,无法处理其他请求。这种故障可能进一步蔓延到应用中的其他服务。断路器模式解决了这个问题。它的工作方式类似电路断路器。当连续故障超过一定阈值时,断路器“跳闸”。在设定的超时期间,对有问题的服务的所有调用将立即失败。超时结束后,断路器允许少量测试请求。如果成功,则恢复正常;如果不成功,则重新启动超时周期。
Dapr 通过其故障转移策略提供了具体的解决方案。该策略确保当调用失败率超过阈值时,调用将立即失败,防止资源耗尽和故障蔓延。利用 Dapr 的故障转移策略,开发者可以轻松实现断路器模式,使微服务架构具备健壮性和弹性,能应对服务故障或延迟。
在复杂的微服务环境中,确保服务间安全通信和访问至关重要。访问令牌模式采用向客户端颁发令牌的方式,授予对服务的受限访问权限。这些令牌封装了确定客户端是否被授权执行给定操作所需的信息。使用访问令牌的主要优点是只有经过身份验证和授权的客户端才能访问服务或服务中的特定操作。
Dapr 加密通讯架构
Dapr 通过基于 SPIFFE Ids 的访问控制为实现此模式提供了强大支持。利用 Dapr 的访问控制,开发者可以定义和实施策略,限制调用方对被调用应用的操作。这确保了对服务交互的细粒度控制,使系统更加安全,能够抵御潜在威胁。
每个容器一个服务实例的部署模式是将每个服务实例放置在独立的容器中。作为轻量级和隔离的容器为服务提供了运行环境,使其可以携带依赖一致地在不同部署阶段运行。这种方法带来了几个好处:确保了隔离,使每个服务实例相互独立;提供了可扩展性,因为新实例可以快速启动;增强了可移植性,因为每个服务包含其自身依赖。
Dapr 与这种部署模型完美匹配,因为它是为容器化环境设计的。当一个服务与 Dapr 一起部署时,一个 Dapr 边车容器随服务容器运行,增强其功能而不影响服务运作。Dapr 的部署模型确保每个服务实例及其 Dapr 边车保持隔离,从而获得每个容器一个服务实例模式的固有优势,如可扩展和弹性的微服务部署。
在某些部署场景下,特别是处理大规模应用或容器不是最佳方案时,在单独虚拟机上部署每个服务实例是一个可行的策略。每个虚拟机一个服务实例模式强调这种方法。通过为每个服务实例分配专用虚拟机,可以确保服务拥有专属的资源,实现可预测的性能。这种隔离意味着一个服务的故障或资源争用不会直接影响其他服务。此外,与容器相比,虚拟机提供了更高级别的隔离,对某些安全或合规要求至关重要。
Dapr 具备通用性,可以无缝部署在基于虚拟机的环境中。无论在专用虚拟机上部署 Dapr,还是使用 Dapr Ambient 在多个 Pod 之间共享功能,Dapr 都可以确保微服务能够高效通信和运作。这种灵活性意味着开发者不受容器化环境的限制,并且可以在基于虚拟机的部署中利用 Dapr 的功能,以保证状态管理、服务调用、发布/订阅等功能的可用性,无论采用何种部署策略。Dapr 的部署文档提供了如何将其集成到各种环境的指导,包括虚拟机或真实边缘环境。
在动态的微服务环境中,服务实例及其位置频繁变更,特别是在容器化环境中,这带来一个挑战:客户端如何发现服务实例的位置?两种流行的模式解决了这个问题:客户端发现和服务器端发现。前者涉及客户端查询服务注册中心以发现当前服务实例的位置,确保它们连接的是可用和健康的实例。而后者通过知情的路由器(通常是负载均衡器)简化了客户端代码,该路由器与服务注册中心交互。
Dapr的边车架构巧妙地解决了这两种模式。虽然边车与服务一起运行,类似客户端,但它不嵌入应用程序内。这种独特的定位使其可以查询服务注册中心,发现其他服务实例的位置,同时也可以作为服务调用的路由器。通过将服务发现的复杂性卸载到Dapr服务调用API,开发者可以实现可靠的服务间通信,即使在服务位置频繁变更的环境中。
在动态的微服务环境下,服务实例的位置和数量经常变化。如何让客户端或路由器获知当前可用的服务实例?服务注册中心模式提供了解决方案。它提出一个中心化注册中心,服务实例在启动时注册,关闭时取消注册。注册中心充当服务数据库,存储其实例及位置信息。然后客户端或路由器可以查询注册中心以发现服务实例的当前位置。
Dapr 与服务注册中心概念实现了无缝集成,为各种注册中心实现提供了统一接口。Dapr 服务调用 API 中的可插拔名称解析组件支持各种托管平台,从使用内置 DNS服 务的 Kubernetes,到使用 mDNS 的自托管机器,甚至 HashiCorp Consul 等多种环境。
自注册模式确保服务可以在服务间通信中相互发现。当服务实例启动时,它负责自主注册到服务注册中心,而不依赖外部代理或系统。这确保注册中心始终拥有最新的可用服务实例信息。通过自动化注册流程,自注册模式减少了手动操作、潜在错误,并保证注册中心信息的实时性。
当带Dapr边车的服务被部署时,Dapr边车主动向注册中心注册自己。这个自动化过程确保服务可以被生态系统中的其他服务立即发现,不仅简化了部署流程,也提高了Dapr构建的架构中的服务间通信的可靠性和效率。
在某些微服务架构中,并非所有服务或端点都是由同一团队或实体创建或管理的,存在需要集成到系统的第三方服务或端点。这些第三方服务可能不遵循内部服务的相同注册模式。第三方注册模式下,注册服务的责任不再由服务自身承担(如自注册),而是由外部代理或系统负责。这可以确保第三方服务即使没有注册功能或权限,也能被发现和无缝集成到系统中。
Dapr 在这方面也具备灵活性。即使是非 Dapr 的第三方端点也可以在 Dapr 运行时注册,享受 Dapr 提供的服务发现、弹性和可观测性等功能。这意味着开发者可以将第三方服务无缝集成到基于Dapr的微服务架构中,而无需第三方服务本身支持Dapr。这样可以构建更加内聚和弹性的微服务生态系统,不受服务来源的影响。
在微服务世界,应用往往需要和基础设施、第三方服务等进行交互,例如注册中心、消息代理、数据库、支付处理器等。一个重大挑战是确保服务可以在多个环境(开发、测试、暂存、生产)间不修改代码即可运行。外部配置模式建议全部外部化应用配置,确保服务与环境无关,可以在不同设置下无代码变更地适应和切换。
Dapr 密钥存储概览
Dapr 通过其密钥存储和配置 API 为此提供了完善的解决方案。这些 API 允许开发者外部化配置,包括数据库凭证等敏感信息。开发者不必硬编码配置或将其置于容易访问的文件中,Dapr 会安全存储并在需要时动态获取。
在微服务架构中,确保服务实例的健康、可用性和自我修复至关重要。健康检查 API 模式建议每个服务公开一个 API 端点(如HTTP /health),报告服务运行状况。此端点执行各种检查,如基础设施连接状态、主机健康(如磁盘空间)以及应用特定逻辑。监控系统、注册中心或负载均衡器可以通过周期检查此端点来判断服务实例健康状况,对不健康实例发出警报,并仅向健康实例路由请求,以提高系统可靠性和效率。
Dapr 通过定期检查应用运行状况提升了健康检查模式,确保其顺利运行。一旦启用应用运行状况检查,Dapr 边车会定期轮询应用。如果检测到问题,Dapr 将采取措施:取消订阅、停止输入绑定和短路服务调用,确保请求不会转发到应用。这种综合方法可以快速识别和缓解任何潜在问题,培育一个健壮和弹性的系统。
在复杂的微服务架构中,理解请求在多个服务间的流动是一个挑战。分布式追踪模式通过在服务中植入代码来为每个外部请求分配一个唯一标识符。此标识符随后被传递给处理该请求的所有服务。这样就可以跟踪请求在各服务间的流动,记录诸如开始时间、结束时间和其他相关指标,洞察系统行为。
Dapr 分布式追踪概述
Dapr 会自动创建并适当捕获和传递追踪标头。利用 Dapr 的可观测性能力,开发者无需手动检测代码进行追踪,Dapr 会自动完成。此外,Dapr 与主流追踪系统集成,确保跟踪可以统一进行可视化和分析。
应用指标是一组定量数据,可以洞察应用或服务的性能、行为和健康状况。通过收集和分析这些指标,开发和运维团队可以识别瓶颈、检测异常并优化服务性能,实现主动监控和确保系统运行最佳。
Dapr 会自动收集广泛的网络指标,捕获诸如请求率、错误率和延迟等数据。Dapr 确保这些指标被传递到集中指标服务,用于全面监控和分析。这意味着开发和运维团队可以获得对系统性能的统一视图,不受服务数量或复杂度的影响。
在软件开发不断变化的环境中,可扩展和经济高效的部署解决方案需求日益增长。无服务器部署抽象了任何服务器的概念,无论是物理的还是虚拟机或容器。最大的优点是开发者可以完全关注代码,而不必操心底层基础设施。无服务器平台会根据负载自动扩展服务,确保资源利用最优。
Dapr 也正在为无服务器时代做准备。很快,开发者可以以无服务器 API 的形式访问 Dapr 提供的丰富能力。这意味着 Dapr 提供的众多功能,从状态管理到消息传递,都将在无服务器环境下可用,确保开发者获得双重优势。通过将 Dapr 集成到无服务器环境,开发者可以构建更强大、可扩展和功能更丰富的应用,而无需处理 Dapr 基础设施的复杂性。有关此模式的更新,请关注 @diagridio 并成为第一个体验者。
模式在软件开发中发挥着重要作用,作为共享语言来传达常见的挑战和最佳实践。它们总结了对反复出现的问题的可验证解决方案,确保开发者不必在每个新项目中重头学习。但是,尽管模式提供了概念蓝图,它们仍然只是抽象的想法。从历史上看,应用服务器、服务总线和诸如 Spring Cloud 等微服务框架用来应对构建可靠应用和实现模式的挑战。但是,为了在现代将这些模式实现,我们需要云原生框架和基座如 Dapr。Dapr 通过以跨语言 API 的形式实现模式来解决这些常见的工程难题,契合云原生理念,使整个组织受益。这确保开发者可以跨多种语言和平台复用最佳实践,简化开发过程并提高应用的弹性和可扩展性。