在本文中, 我计划介绍微服务架构 (MSA) 的关键架构概念, 以及如何在实践中使用这些架构原理.
微服务是软件体系结构领域最流行的流行语之一. 关于微服务的基础知识和好处的学习材料很多, 但是关于如何在现实的企业场景中使用微服务的资源很少.
在本文中, 我将介绍微服务架构 (MSA) 的关键架构概念, 以及如何在实践中使用这些架构原理.
整体架构
企业软件应用程序旨在满足众多业务需求; 给定的软件应用程序提供数百种功能, 所有这些功能都堆积在单个整体应用程序中. 例如, ERP,CRM 和其他各种软件系统被构建为具有数百种功能的整体. 如此庞大的软件应用程序的部署, 故障排除, 扩展和升级是一场噩梦.
面向服务的体系结构 (SOA) 旨在通过引入服务的概念, 应用程序提供的相似功能的聚集和分组来克服某些上述限制. 使用 SOA, 可以将软件应用程序设计为粗粒度服务的组合. 但是, 在 SOA 中, 服务范围非常广泛. 这导致具有数十种操作 (功能) 的复杂而庞大的服务, 以及复杂的消息格式和标准(例如: 所有 WS * 标准).
整体架构
在大多数情况下, SOA 中的服务彼此独立. 但是它们与所有其他服务一起部署在同一运行时中 (考虑一下将多个 web 应用程序部署到同一 Tomcat 实例中). 与单片软件应用程序相似, 这些服务具有通过累积各种功能随着时间而增长的习惯. 从字面上看, 这将这些应用程序变成了与通用整体应用程序(如 ERP) 没有区别的整体结构. 该图显示了包含多个服务的零售软件应用程序. 所有这些服务都部署到同一应用程序运行时中. 因此, 这是一个整体架构的很好的例子. 这是基于整体架构的应用程序的一些特征.
. 整体应用程序是作为一个单元进行设计, 开发和部署的.
. 整体应用极为复杂; 这导致维护, 升级和添加新功能的噩梦.
. 很难使用 Monolithic 体系结构来实践敏捷开发和交付方法.
. 需要重新部署整个应用程序以更新其中的一部分.
. 该应用程序必须按单个单元进行扩展, 从而难以管理相互冲突的资源需求(例如, 一项服务需要更多的 CPU, 而另一项则需要更多的内存)
. 一项不稳定的服务可能会导致整个应用程序崩溃.
. 采用新技术和框架真的很困难, 因为所有功能都必须基于同类技术 / 框架.
微服务架构
微服务架构 (MSA) 的基础是将单个应用程序开发为一组小型独立服务, 这些独立服务在其自己的流程中运行, 独立开发和部署.
在微服务架构的大多数定义中, 将其解释为将整体中可用的服务隔离为一组独立服务的过程. 但是, 在我看来, 微服务不仅仅是将整体中可用的服务拆分为独立的服务.
关键思想是, 通过查看整体提供的功能, 我们可以确定所需的业务能力. 然后, 可以将那些业务功能实现为完全独立, 细粒度且自包含的 (微) 服务. 它们可能在不同的技术堆栈之上实现, 并且每种服务都针对非常特定且有限的业务范围.
因此, 我们上面解释的在线零售系统场景可以通过微服务架构实现, 如下图所示. 通过微服务体系结构, 零售软件应用程序被实现为一组微服务. 因此, 正如你在下面看到的那样, 根据业务需求, 还有一个整体服务是根据整体中存在的原始服务集创建的. 因此, 很明显, 使用微服务体系结构是超出了整体中服务拆分的范围.
微服务架构
让我们深入研究微服务的关键体系结构原理, 更重要的是, 让我们集中讨论如何在实践中使用它们.
设计微服务: 大小, 范围和功能
你可能正在使用 Microservices Architecture 从头开始构建软件应用程序, 或者可能将现有的应用程序 / 服务转换为微服务. 无论哪种方式, 正确决定微服务的大小, 范围和功能都是非常重要的. 这可能是你在实践中实现微服务架构时最初遇到的最困难的事情.
让我们讨论与微服务的大小, 范围和功能有关的一些关键的实际问题和误解.
. 代码行 / 团队规模是糟糕的指标: 关于基于实现的代码行或团队规模 (即两个比萨饼团队) 确定微服务规模的讨论很多. 但是, 这些指标被认为是非常不切实际和糟糕的指标, 因为我们仍然可以使用更少的代码 / 具有两个比萨饼的团队来开发服务, 但完全违反了微服务架构的原则.
."微" 是一个误导性术语: 大多数开发人员倾向于认为他们应该尝试使服务尽可能小. 这是一个误解.
.SOA 上下文: 在 SOA 上下文中, 服务通常实现为整体, 并支持数十种操作 / 功能. 因此, 拥有类似于 SOA 的服务并将其重新命名为微服务并不会给你带来微服务架构的任何好处.
那么, 我们应该如何在微服务架构中正确设计服务?
设计微服务准则
."单一责任原则"(SRP): 微服务的业务范围有限且重点突出, 可以帮助我们满足服务开发和交付中的敏捷性.
. 在微服务的设计阶段, 我们应该找到它们的边界并将其与业务功能 (在域驱动设计中也称为受限上下文) 保持一致.
. 确保微服务设计可确保服务的敏捷 / 独立开发和部署.
. 我们的重点应该放在微服务的范围上, 而不是缩小服务范围. 服务的 (正确) 大小应该是促进给定业务能力所需的大小.
. 与 SOA 中的服务不同, 给定的微服务应具有很少的操作 / 功能和简单的消息格式.
. 通常, 从较长的服务边界开始, 然后随着时间的流逝而重构为较小的服务边界 (根据业务需求) 通常是一个好习惯.
在我们的零售用例中, 你可以发现我们已经将整体的功能分为四个不同的微服务, 即 "库存","会计","运输" 和 "商店". 他们正在解决一个有限但集中的业务范围, 以便每个服务彼此完全分离, 并确保开发和部署的敏捷性.
微服务中的消息传递
在单片应用程序中, 使用功能调用或语言级方法调用来调用不同处理器 / 组件的业务功能. 在 SOA 中, 这已转向更加松散耦合的 Web 服务级别消息传递, 该消息传递主要基于 SOAP 并基于 HTTP,JMS 等不同协议. 具有数十种操作和复杂消息模式的 Web 服务是 Web 服务普及的主要阻力. 对于微服务架构, 要求具有简单轻量的消息传递机制.
同步消息传递 - REST, 节流
对于 Microservices Architecture 中的同步消息传递(客户端希望服务及时响应并等待它获得响应),REST 是一致的选择, 因为它提供了一种简单的消息传递样式, 该消息传递样式基于资源 API 样式通过 HTTP 请求响应实现. 因此, 大多数微服务实现都使用 HTTP 以及基于资源 API 的样式(每种功能都由一种资源表示, 并且在这些资源之上执行操作).
使用 REST 接口公开微服务
使用 Thrift(你可以在其中定义微服务的接口定义), 作为 REST / HTTP 同步消息传递的替代方法.
异步消息传递 - AMQP,STOMP,MQTT
对于某些微服务场景, 要求使用异步消息传递技术(客户端不希望立即响应, 或者根本不接受响应). 在这种情况下, 异步消息传递协议如 AMQP,STOMP 或 MQTT 被广泛使用.
消息格式 - JSON,xml,Thrift,ProtoBuf,Avro
roservices 是另一个关键因素. 传统的单片应用程序使用复杂的二进制格式, 基于 SOA / Web 服务的应用程序使用基于复杂消息格式 (SOAP) 和架构 (xsd) 的文本消息. 在大多数基于微服务的应用程序中, 它们使用简单的基于文本的消息格式, 例如 HTTP 资源 API 样式之上的 JSON 和 xml. 在我们需要二进制消息格式的情况下(文本消息在某些用例中可能变得冗长), 微服务可以利用二进制消息格式, 例如二进制 Thrift,ProtoBuf 或 Avro.
服务合同 - 定义服务接口 - Swagger,RAML, 节俭
当你将业务功能实现为服务时, 你需要定义和发布服务合同. 在传统的整体应用程序中, 我们几乎找不到用于定义应用程序业务功能的功能. 在 SOA / Web 服务世界中, WSDL 用于定义服务协定, 但是, 众所周知, WSDL 并不是复杂的且与 SOAP 紧密耦合, 因此不是定义微服务协定的理想解决方案.
由于我们是基于 REST 架构样式构建微服务的, 因此我们可以使用相同的 REST API 定义技术来定义微服务的契约. 因此, 微服务使用标准的 REST API 定义语言 (例如 Swagger 和 RAML) 来定义服务合同.
对于其他不基于 HTTP / REST 的微服务实现(例如 Thrift), 我们可以使用协议级别的接口定义语言(IDL)(例如: Thrift IDL).
集成微服务(服务间 / 流程通信)
在微服务体系结构中, 软件应用程序被构建为一套独立的服务. 因此, 为了实现业务用例, 需要在不同的微服务 / 流程之间具有通信结构. 这就是微服务之间的服务间 / 流程通信如此重要的原因.
在 SOA 实现中, 使用企业服务总线 (ESB) 可以促进服务之间的服务间通信, 并且大多数业务逻辑位于中间层(消息路由, 转换和编排). 但是, 微服务体系结构促进消除中央消息总线 / ESB, 并将 "智能性" 或业务逻辑转移到服务和客户端(称为智能端点).
由于微服务使用诸如 HTTP,JSON 等标准协议, 因此在微服务?? 之间进行通信时, 与不同协议集成的要求极小. 微服务通信中的另一种替代方法是使用轻量级消息总线或网关, 路由功能最少, 并充当 `` 哑管道'', 而网关上未实现任何业务逻辑. 基于这些样式, 微服务体系结构中出现了几种通信模式.
点对点样式 - 直接调用服务
在点对点样式中, 整个消息路由逻辑都驻留在每个端点上, 并且服务可以直接进行通信. 每个微服务都公开一个 REST API, 给定的微服务或外部客户端可以通过其 REST API 调用另一个微服务.
具有点对点连接的服务间通信
显然, 该模型适用于相对简单的基于微服务的应用程序, 但是随着服务数量的增加, 这将变得极为复杂. 毕竟, 这就是在传统 SOA 实现中使用 ESB 的确切原因: 摆脱凌乱的点对点集成链接. 让我们尝试总结微服务通信的点对点样式的主要缺点.
. 必须在每个微服务级别实现最终用户身份验证, 限制, 监视等非功能性要求.
. 由于复制了通用功能, 因此每个微服务实现都可能变得复杂.
. 服务与客户端之间的所有通信都无法控制(即使用于监视, 跟踪或筛选)
. 对于大规模微服务实现, 通常将直接通信样式视为微服务反模式.
因此, 对于复杂的微服务用例, 我们可以使用轻量级的中央消息传递总线, 而不是使用点对点连接或中央 ESB, 它可以为微服务提供抽象层, 并可以用于实现各种非功能性 能力. 此样式称为 API 网关样式.
API 网关样式
API 网关样式背后的关键思想是使用轻量级消息网关作为所有客户端 / 消费者的主要入口点, 并在网关级别实现常见的非功能性要求. 通常, API 网关允许你通过 REST / HTTP 使用托管 API. 因此, 在这里, 我们可以将通过 API-GW 作为托管服务实现为微服务的业务功能公开. 实际上, 这是微服务架构和 API 管理的结合, 可为你提供两全其美的体验.
所有微服务都通过 API-GW 公开在我们的零售业务场景中, 如上图所示, 所有微服务都通过 API-GW 公开, 这是所有客户端的单一入口点. 如果微服务想要使用另一个微服务, 则也需要通过 API-GW 来完成.
API-GW 样式具有以下优点:
. 能够在网关级别为现有微服务提供所需的抽象. 例如, API 网关可以提供每个客户端不同的 API, 而不是提供一种千篇一律的样式 API.
. 网关级别的轻量级消息路由 / 转换.
. 应用非功能性功能 (例如安全性, 监视和限制) 的中心位置.
. 通过使用 API-GW 模式, 由于所有非功能性需求都在网关级别实现, 因此微服务变得更加轻量级.
API-GW 样式很可能是大多数微服务实现中使用最广泛的模式.
消息代理样式
微服务可以与异步消息传递场景集成, 例如单向请求和使用队列或主题的发布 - 订阅消息传递. 给定的微服务可以是消息生产者, 并且可以异步将消息发送到队列或主题. 然后, 消费微服务可以消费来自队列或主题的消息. 这种样式使消息生产者与消息使用者分离, 中间消息代理将缓冲消息, 直到使用者能够处理它们为止. 生产者微服务完全不了解消费者微服务.
使用 pub-sub 的基于异步消息传递的集成
消费者 / 生产者之间的通信通过基于异步消息传递标准 (例如 AMQP,MQTT 等) 的消息代理来促进.
分散数据管理
在整体架构中, 应用程序将数据存储在单个集中式数据库中, 以实现应用程序的各种功能.
单一应用程序使用中央数据库来实现其所有功能. 在微服务体系结构中, 功能分散在多个微服务之间, 如果我们使用相同的中央数据库, 则微服务将不再彼此独立(例如, 如果 数据库架构已从给定的微服务更改, 这将破坏其他几个服务). 因此, 每个微服务都必须具有自己的数据库.
每个微服务都有自己的私有数据库
这是在微服务架构中实施分散数据管理的关键方面.
. 每个微服务都可以有一个私有数据库来保留实现其提供的业务功能所需的数据.
. 给定的微服务只能访问专用私有数据库, 而不能访问其他微服务的数据库.
. 在某些业务场景中, 你可能必须为单个事务更新多个数据库. 在这种情况下, 其他微服务的数据库应仅通过其服务 API 进行更新(不允许直接访问该数据库)
分散的数据管理为你提供了完全解耦的微服务, 并且可以自由选择不同的数据管理技术 (SQL 或 NoSQL 等, 每种服务使用不同的数据库管理系统). 但是, 对于涉及多个微服务的复杂事务用例, 必须使用每个服务提供的 API 来实现事务行为, 并且逻辑位于客户端或中介(GW) 级别.
分散治理
微服务架构支持分散式治理.
通常,"治理" 是指建立和加强人员和解决方案如何共同协作以实现组织目标. 在 SOA 的背景下, SOA 治理指导可重用服务的开发, 确定如何设计和开发服务以及这些服务将随着时间的变化而变化. 它在服务的提供者和这些服务的消费者之间建立协议, 告诉消费者他们可以期望什么以及提供者他们有义务提供什么. 在 SOA 治理中, 有两种常用的治理类型:
那么, 微服务环境中的治理到底意味着什么? 在微服务架构中, 微服务被构建为具有各种技术和平台的完全独立和解耦的服务. 因此, 无需为服务设计和开发定义通用标准. 因此, 我们可以将微服务的去中心化治理功能总结如下:
. 在微服务架构中, 不需要进行集中的设计时治理.
. 微服务可以自行决定其设计和实现.
. 微服务架构促进了公共 / 可重用服务的共享.
. 某些运行时治理方面, 例如 SLA, 节流, 监视, 通用安全要求和服务发现, 可以在 API-GW 级别上实现.
服务注册和服务发现
在微服务架构中, 你需要处理的微服务数量非常多. 而且, 由于微服务的快速和敏捷开发 / 部署性质, 它们的位置会动态变化. 因此, 你需要在运行时找到微服务的位置. 解决此问题的方法是使用服务注册表.
服务注册
服务注册表包含微服务实例及其位置. 微服务实例在启动时在服务注册表中注册, 并在关机时注销. 消费者可以通过服务注册表找到可用的微服务及其位置.
服务发现
为了找到可用的微服务及其位置, 我们需要一种服务发现机制. 服务发现机制有两种类型, 客户端发现和服务器端发现. 让我们仔细看看那些服务发现机制.
客户端发现 - 通过这种方法, 客户端或 API-GW 通过查询服务注册表来获取服务实例的位置.
在微服务架构中, 你需要处理的微服务数量非常多. 而且, 由于微服务的快速和敏捷开发 / 部署性质, 它们的位置会动态变化. 因此, 你需要在运行时找到微服务的位置. 解决此问题的方法是使用服务注册表.
服务注册
服务注册表包含微服务实例及其位置. 微服务实例在启动时在服务注册表中注册, 并在关机时注销. 消费者可以通过服务注册表找到可用的微服务及其位置.
服务发现
为了找到可用的微服务及其位置, 我们需要一种服务发现机制. 服务发现机制有两种类型, 客户端发现和服务器端发现. 让我们仔细看看那些服务发现机制.
客户端发现 - 通过这种方法, 客户端或 API-GW 通过查询服务注册表来获取服务实例的位置.
客户端发现
服务器端发现 - 使用这种方法, 客户端 / API-GW 将请求发送到在已知位置运行的组件(例如负载均衡器). 该组件调用服务注册表并确定微服务的绝对位置.
客户端发现
诸如 Kubernetes(http://kubernetes.io/v1.1/docs/user-guide/services.html)之类的微服务部署解决方案提供了服务端发现机制.
部署方式
在微服务架构方面, 微服务的部署起着至关重要的作用, 并且具有以下关键要求:
能够独立于其他微服务进行部署 / 取消部署.
必须能够在每个微服务级别进行扩展(给定的服务可能比其他服务获得更多的流量).
快速构建和部署微服务.
一个微服务中的故障不得影响任何其他服务.
Docker(一种开放源代码引擎, 可让开发人员和系统管理员在 Linux 环境中部署自给自足的应用程序容器)提供了一种很好的方式来部署微服务以满足上述要求. 涉及的关键步骤如下:
. 将微服务打包为 (Docker) 容器映像.
. 将每个服务实例部署为一个容器.
. 缩放是根据更改容器实例的数量完成的.
. 随着我们使用 Docker 容器, 构建, 部署和启动微服务的速度将大大提高(比常规 VM 快得多)
Kubernetes 通过允许将 Linux 容器集群作为一个系统进行管理, 跨多个主机管理和运行 Docker 容器, 提供容器的共置, 服务发现和复制控制功能, 扩展了 Docker 的功能. 如你所见, 大多数这些功能在我们的微服务环境中也是必不可少的. 因此, 使用 Kubernetes(在 Docker 之上)进行微服务部署已成为一种极其强大的方法, 尤其是对于大规模微服务部署.
将微服务构建和部署为容器.
在上图中, 它显示了零售应用程序的微服务部署的概述. 每个微服务实例都作为一个容器部署, 每个主机有两个容器. 你可以任意更改在给定主机上运行的容器的数量.
安全
在实际场景中使用微服务时, 保护微服务是非常普遍的要求. 在进入微服务安全性之前, 让我们快速看一下我们通常如何在整体应用程序级别上实现安全性.
在典型的整体应用程序中, 安全性是要找到 "谁是呼叫者","呼叫者能做什么" 和 "我们如何传播该信息".
这通常是在请求处理链的开始处的通用安全组件上实现的, 并且该组件使用基础用户存储库 (或用户存储) 填充所需的信息.
那么, 我们可以直接将此模式转换为微服务架构吗? 是的, 但这需要在每个微服务级别实现的安全组件, 该组件正在与集中式 / 共享用户存储库进行对话并检索所需的信息. 这是解决微服务安全性问题的非常乏味的方法. 相反, 我们可以利用广泛使用的 API 安全标准 (例如 OAuth2 和 OpenID Connect) 为我们的微服务安全问题找到更好的解决方案. 在深入探讨这一点之前, 让我概述一下每个标准的目的以及如何使用它们
.OAuth2 - 是访问委派协议. 客户端通过授权服务器进行身份验证, 并获得一个不透明的令牌, 称为 "访问令牌". 访问令牌的用户 / 客户端信息为零. 它仅具有对只能由授权服务器检索的用户信息的引用. 因此, 这被称为 "参考令牌", 即使在公共网络 / 互联网中也可以安全地使用此令牌.
.OpenIDConnect 的行为类似于 OAuth, 但除了访问令牌外, 授权服务器还会发布一个 ID 令牌, 其中包含有关用户的信息. 这通常由 JWT(JSON Web 令牌)实现, 并由授权服务器签名. 因此, 这确保了授权服务器和客户端之间的信任. 因此, JWT 令牌被称为 "按值令牌", 因为它包含用户的信息, 并且显然在内部网络之外使用它是不安全的.
具有 OAuth2 和 OpenID Connect 的微服务安全性
如上图所示, 这些是实现微服务安全性涉及的关键步骤:
. 将身份验证留给 OAuth 和 OpenID Connect 服务器(授权服务器), 以便在有人有权使用数据的情况下, 微服务成功提供访问权限.
. 使用 API??-GW 样式, 在该样式中, 所有客户端请求都有一个入口点.
客户端连接到授权服务器并获得访问令牌(按引用令牌). 然后将访问令牌与请求一起发送到 API-GW.
网关上的令牌转换 - API-GW 提取访问令牌并将其发送到授权服务器以检索 JWT(按值令牌).
. 然后, GW 将这个 JWT 与请求一起传递给微服务层.
.JWT 包含必要的信息, 以帮助存储用户会话等. 如果每个服务都可以理解 JSON Web 令牌, 则你已经分发了身份识别机制, 该机制允许你在整个系统中传输身份.
在每个微服务层, 我们可以有一个处理 JWT 的组件, 这是一个非常简单的实现.
交易次数
微服务中的交易支持如何? 实际上, 支持跨多个微服务的分布式事务是非常复杂的任务. 微服务架构本身鼓励服务之间的无事务协调.
想法是, 给定的服务是完全独立的, 并且基于单一责任原则. 跨多个微服务进行分布式事务的需求通常是微服务体系结构中设计缺陷的征兆, 通常可以通过重构微服务的范围来解决. 但是, 如果必须在多个服务之间分配事务, 则可以通过在每个微服务级别引入 "补偿操作" 来实现这种情况. 关键思想是, 给定的微服务基于单一职责原则, 如果给定的微服务无法执行给定的操作, 我们可以认为这是整个微服务的失败. 然后, 必须通过调用这些微服务的相应补偿操作来撤消所有其他 (上游) 操作.
失败的设计
微服务架构引入了一组分散的服务, 并且与单片设计相比, 增加了在每个服务级别出现故障的可能性. 给定的微服务可能会由于网络问题, 基础资源的不可用等原因而失败. 不可用或无响应的微服务不应导致整个基于微服务的应用程序崩溃. 因此, 微服务应该是容错的, 能够在可能的情况下恢复, 并且客户端必须妥善处理它.
另外, 由于服务随时可能发生故障, 因此能够快速检测 (实时监视) 故障并在可能的情况下自动恢复服务也很重要.
在微服务上下文中, 有几种常用的模式来处理错误. context.
断路器
当你对微服务进行外部调用时, 你需要为每次调用配置一个故障监视器组件, 并且当故障达到某个阈值时, 该组件将停止对该服务的任何进一步调用 (使电路跳闸). 在一定数量的请求处于打开状态(你可以配置) 之后, 将电路更改回关闭状态.
这种模式非常有用, 可避免不必要的资源消耗, 由于超时而导致的请求延迟, 并且还使我们有机会监视系统(基于活动的开路状态).
隔板
由于微服务应用程序包含微服务的数量, 因此基于微服务的应用程序一部分的故障不应影响其余的应用程序. 隔板模式是关于隔离应用程序的不同部分的, 因此应用程序中服务的故障不会影响任何其他服务.
暂停
超时模式是一种机制, 当你认为微服务不会响应时, 它可以让你停止等待微服务的响应. 你可以在此处配置希望等待的时间间隔.
那么, 我们在哪里以及如何在微服务中使用这些模式? 在大多数情况下, 这些模式中的大多数都适用于网关级别. 这意味着当微服务不可用或没有响应时, 在网关级别, 我们可以决定是否使用断路器或超时模式将请求发送到微服务. 同样, 在网关级别实现诸如隔板等模式也是非常重要的, 因为它是所有客户端请求的单个入口点, 因此赠与服务的失败不应影响其他微服务的调用.
另外, 网关可以用作中心点, 当通过网关调用每个微服务时, 我们可以获得状态并监视每个微服务.
微服务, 企业集成, API 管理等
我们已经讨论了微服务架构的各种特征, 以及如何在现代企业 IT 环境中实现它们. 但是, 我们应该记住, 微服务不是万能药. 流行语概念的盲目适应将无法解决你的 "实际" 企业 IT 问题. 正如你在整个博客文章中所看到的那样, 微服务具有很多优势, 我们应该加以利用. 但是, 我们还必须记住, 用微服务解决所有企业 IT 问题是不现实的. 例如, 微服务架构促进了消除 ESB 作为中央总线的发展, 但是在现实世界中, 有很多不基于微服务的现有应用程序 / 服务. 因此, 要与它们集成, 我们需要某种集成总线. 因此, 理想情况下, 微服务和其他企业体系结构概念 (例如集成) 的混合方法将更为现实. 我将在另一篇博客文章中进一步讨论它们.
本文灵感源于优锐课 java 架构学习分享, 希望这使你对如何在企业中使用微服务有了更清晰的认识.
来源: http://www.bubuko.com/infodetail-3354439.html