为什么通过微服务的方法生成应用程序?

作为软件开发人员,我们已知道思考如何将应用程序因数分解成组件部分。 这是对象导向、软件抽象和组件化的中心模式。 现在,这种因数分解往往以共享库和技术层之间的类与接口呈现。 后端存储、中间层业务逻辑和前端用户界面 (UI) 通常采用一种分层方法。 过去几年来 变化是身为开发人员的我们开始为业务驱动的云生成分布式应用程序。

不断变化的业务需求包括:

  • 为吸引新地理区域的客户而大规模构建和操作的一项服务(举例)。
  • 更快速地提供特性与功能,灵活应对客户的需求。
  • 提高资源利用率以降低成本。

这些业务需求影响我们生成应用程序的 方式

有关 Azure 实现微服务的方法的详细信息,请阅读 Microservices: An application revolution powered by the cloud(微服务:由云支持的应用程序变革)。

单一式设计方法与微服务设计方法

所有应用程序会随着时间而发展。 成功的应用程序因为有实用性而发展。 失败的应用程序不会发展,最终将被取代。 问题在于现在对要求了解多少,以及未来这些要求有何变化? 例如,如果要为某个部门构建报告应用程序。 可以确定的是,应用程序保留在公司范围内,而且报表的生存期非常短。 那么,选择的方法将不同于构建服务向数千万个客户传送视频内容的方式。

在已知后来可以重新设计应用程序的情况下,有时向外寻求概念证明才是驱动因素。 过度设计永不使用的功能并没有太大意义。 这就是通常所谓的工程取舍。 另一方面,公司谈论生成云时都期望成长和使用量。 问题在于成长和规模不可预测。 我们想要能够快速创建原型,同时还要了解我们正在通往未来成功的路上。 这是简练的启动方法:生成、测量、学习、迭代。

在客户端-服务器时代,我们倾向专注于生成分层式应用程序,每一层采用特定的技术。 已针对这些方法派生出 单一式 应用程序一词。 接口通常存在于各层之间,而在一层内的各组件之间采用更紧密耦合的设计。 开发人员设计并分解已编译为库并链接为一些可执行文件和 DLL 的类。

这类单一式设计方法有一些优点。 设计通常更为简单,组件之间通常通过进程间通信 (IPC) 进行调用,因此调用更快。 此外,每个人都只测试单一产品,人力资源运用更有效率。 缺点是分层之间紧密耦合,无法缩放单独组件。 如果需要执行修复或升级,必须等待其他人完成其测试。 灵活性更难以发挥。

微服务解决了这些缺点,更密切配合上述业务要求,但它们本身也都有优缺点。 微服务的优点是通常各自封装较为简单的业务功能,可独立增加或减少、测试、部署和管理。 微服务方法的一个重要优点是团队倾向于以业务方案为导向,而不是以分层方法建议的技术为导向。 实际上,较小的团队可以根据客户方案开发微服务,采用他们选择的任何技术。

换句话说,组织不需要为了维护微服务应用程序而将技术标准化。 拥有服务的单独团队可以根据团队的专业知识,或什么最适合解决问题,各自发挥所长。 实际上,最好使用一组建议的技术,例如特定的 NoSQL 存储或 Web 应用程序框架。

微服务的缺点包括需要管理越来越多的独立实体、处理更复杂的部署和版本控制。 微服务之间的网络流量以及相应的网络延迟不断增加。 可以通过大量琐碎但却精细的服务来解决性能问题。 如果没有工具帮助查看这些依赖性,很难“看到”整个系统。

若要让微服务方法奏效,必须在以下方面制定标准:在通信方式上达成共识,只注重需要从服务获得什么,不在乎僵化的约定。 必须在设计的初期定义这些约定,因为之后服务将各自独立更新。 在设计微服务方法时出现的另一个描述是“面向服务的精细体系结构 (SOA)”。

简而言之,微服务设计方法是分离的服务联合,各自独立更改,并达成一致的通信标准。

随着越来越多云应用的生成,人们发现这种将整体应用分解成独立、方案焦点式服务的做法,在长期上是较好的方法。

应用程序开发方法的比较

Service Fabric 平台应用程序开发

1) 单一式应用包含域特定的功能,通常按照功能层划分,例如 Web、业务和数据。

2) 单一式应用可通过复制到多个服务器/虚拟机/容器上进行扩展。

3) 微服务应用程序将单独功能分隔成单独的较小服务。

4) 微服务方法可通过独立部署每个服务而扩大,跨服务器/虚拟机/容器创建这些服务的实例。

使用微服务方法进行设计并非适用于所有项目,但确实更符合前面所述的业务目标。 如果确定以后有机会根据微服务设计重写代码,可以从单一式方法入手。 更常见的是,从单一式应用程序入手,分阶段慢慢分解它(从需要提高可缩放性或敏捷性的功能区域开始)。

总而言之,微服务方法是以许多小服务来组成应用程序。 这些服务在部署于计算机群集上的容器中运行。 较小的团队可针对方案来开发服务,且每个服务独立进行测试、版本控制、部署和缩放,因此整个应用程序可以不断改进。

什么是微服务?

微服务有不同的定义。 如果在 Internet 中搜索,可以找到许多有用的资源,了解各种观点和定义。 但在微服务的以下大部分特性上,已广泛达成共识:

  • 封装客户方案或业务方案。 要解决什么问题?
  • 由小型工程团队开发。
  • 使用任何编程语言编写并使用任何框架。
  • 由独立控制版本、部署及缩放的代码和(可选)状态组成。
  • 通过定义完善的接口和协议与其他微服务交互。
  • 具有用来解析位置的唯一名称 (URL)。
  • 在出现故障时可保持一致且可用。

一言以蔽之:

微服务应用程序由独立控制版本和可缩放的、以客户为中心的服务组成,这些服务通过标准协议和定义完善的接口彼此通信。

我们在上一部分已介绍了前两点,接下来进一步澄清其他各要点。

使用任何编程语言编写并使用任何框架

开发人员应根据本身的技能或服务需求,自由选择所需的语言或框架。 在某些服务中,可能会认为 C++ 的性能优点胜于一切。 而在其他服务中,C# 或 Java 的简易管理开发可能才是最重要的。 在某些情况下,可能需要使用特定合作伙伴库、数据存储技术,或向客户端公开服务的方式。

选择技术之后,接下来的课题就是服务的操作或生命周期管理和缩放。

允许独立控制版本、部署及缩放的代码和状态

无论选择何种方式编写微服务,代码和(可选)状态都应该独立部署、升级和缩放。 这确实是难以解决的问题之一,因为这涉及到所选的技术。 在缩放方面,难以了解如何分区(或分片)代码和状态。 当代码和状态使用不同的技术时(目前的普遍情况),微服务的部署脚本必须能够妥善缩放两者。 这也关乎到灵活性和弹性,以便可以升级某些微服务,而无需一次性全部升级。

暂时回到单一式方法和微服务方法的比较,下图显示了状态存储方法的差异。

应用程序样式之间的状态存储

Service Fabric 平台状态存储

左侧的单一式方法具有单一数据库和多层的特定技术。

右侧的微服务方法显示互连的微服务图,其中状态通常以微服务为范围,并使用各种技术。

在单一式方法中,应用程序通常使用单一数据库。 优点是这是单一位置,很容易部署。 每个组件可以通过单个表存储其状态。 困难之处在于团队必须严格区分状态。 无可避免地就想将新的列添加到现有客户表、在表之间执行联接,并且对存储层形成依赖性。 发生这种情况后,无法缩放各个组件。

在微服务方法中,每个服务都管理并存储自己的状态。 每个服务将负责同时缩放代码和状态,以满足服务的需求。 不足的是,需要创建应用程序数据的视图或查询时,必须跨不同的状态存储进行查询。 为了解决此问题,通常由一个独立的微服务生成一个跨许多微服务的视图。 如果需要对数据执行多个即席查询,每个微服务应该考虑将其数据写入数据仓库服务以供脱机分析。

版本控制特定于部署的微服务版本,以便能够部署和并行运行多个不同的版本。 当较新版的微服务在升级期间失败,因而需要回滚到旧版时,版本控制可以解决这种情况。 版本控制的另一种情况是执行 A/B 式测试,其中不同的用户将体验到不同版本的服务。 例如,在更广泛推出新功能之前,通常先对一组特定的客户升级微服务以测试新功能。 在微服务的生命周期管理之后,便可以在微服务之间进行通信。

通过定义完善的接口和协议与其他微服务交互

本主题无需花费太多时间,因为过去 10 年来发布了大量关于面向服务的体系结构的文献,其中对通信模式进行了介绍。 一般而言,服务通信使用 REST 方法,并配合 HTTP 与 TCP 协议及 XML 或 JSON 作为序列化格式。 从接口观点来看,这涉及到采用 Web 设计方法。 但是,用户仍然可以使用二进制协议或自己的数据格式。 如果这些协议和格式非公开可用,微服务使用起来就很难,因此要有心理准备。

具有用来解析位置的唯一名称 (URL)

记得我们一直在说,微服务与 Web 有点类似吗? 就像 Web 一样,微服务无论在何处运行,都必须可寻址。 若要在计算机上运行特定微服务,很快就会陷入困境。

就像 DNS 解析特定计算机的特定 URL 一样,微服务需要有唯一的名称来发现它目前所在的位置。 微服务需要有可寻址的名称才能独立于它们运行所在的基础结构之外。 这意味着服务的部署和发现方式之间互相影响,因为需要有服务注册表。 同样地,当计算机发生故障时,注册服务必须指出服务现在的运行位置。

接下来的主题:复原能力和一致性。

在出现故障时可保持一致且可用

处理意外的故障是最难解决的问题之一,特别是在分布式系统中。 开发人员编写的代码大多是在处理异常,这也是测试时花费最多时间的地方。 问题比编写代码来处理故障更复杂。 当运行微服务的计算机发生故障时,该怎么办? 不仅需要检测这种微服务故障(本身就是棘手的问题),还需要设法重启微服务。

微服务必须能够从故障复原,出于可用性理由,通常还必须能够在另一台计算机上重新启动。 这也涉及到代表微服务所保存的状态、微服务可从何处恢复此状态,以及微服务是否能够成功地重新启动。 换句话说,需要能够复原计算(也就是重启进程)以及状态或数据(不丢失任何数据,数据保持一致)。

在其他情况下,复原能力的问题更难处理,例如应用程序升级期间失败。 在配合部署系统一起运行时,微服务不需要恢复。 它还需要确定是要继续升级到更新版本,还是回滚到旧版以维持一致的状态。 需要考虑一些问题,例如,是否有足够的计算机用于继续升级,以及如何恢复旧版的微服务。 需要微服务发出运行状况信息才能做出这些决定。

报告运行状况和诊断

微服务必须报告其运行状况和诊断,这一点看似明显,但却经常被忽视。 否则,难以从操作观点上深入了解。 面临的难题是关联一组独立服务的诊断事件并修正计算机时钟偏差以识别事件顺序。 同样地,通过议定的协议和数据格式来与微服务交互时,需要将运行状况和诊断事件的记录方式标准化,这些事件最终将写入可供查询和查看的事件存储。 在微服务方法中,关键在于不同团队同意采用单一的日志记录格式。 需要通过一致的方法查看整个应用程序中的诊断事件。

运行状况与诊断不同。 运行状况是指微服务报告其当前状态,以便采取适当的措施。 一个很好的例子便是使用升级和部署机制保持可用性。 当前服务可能由于进程崩溃或计算机重新启动而状况不正常,但仍可运行。 不应该执行升级而让情况恶化。 最好是先进行调查,或让微服务有时间恢复。 微服务的运行状况事件有助于我们做出明智的决策,实际上有助于创建自我修复的服务。

Service Fabric 作为微服务平台

Azure 从提供盒装产品(通常是单一式)转换到提供服务后,Azure Service Fabric 横空问世。 构建和运营 Azure SQL 数据库和 Azure Cosmos DB 等大型服务的经验造就了 Service Fabric。 该平台随着越来越多服务采用它而不断发展变化。 重要的是,Service Fabric 不仅必须在 Azure 中运行,还必须在独立的 Windows Server 部署中运行。

Service Fabric 旨在解决构建和运行服务方面的难题,并有效地利用基础结构资源,使团队可以使用微服务方法来解决业务问题。

Service Fabric 提供三大广泛领域,有助于用户使用微服务方法生成应用程序:

  • 提供系统服务的平台,用于部署、升级、检测和重启失败的服务、发现服务、路由消息、管理状态和监视运行状况。 这些系统服务实际上具备上述微服务的许多特性。
  • 能够部署在容器中运行或作为进程运行的应用程序。 Service Fabric 是容器和进程 Orchestrator。
  • 有助于以微服务形式生成应用程序的生产编程 API:ASP.NET Core、Reliable Actors 和 Reliable Services。 可以选择使用任意代码来生成微服务。 但使用这些 API 不仅可让作业变得更简单,也能更深入地与平台集成。 例如,可以获取运行状况和诊断信息,或利用内置的高可用性。

Service Fabric 与服务生成方式无关,可以使用任意技术。不过,它确实提供内置编程 API,以便用户可以更轻松地生成微服务。

将现有应用程序迁移到 Service Fabric

Service Fabric 的关键方法是重用现有代码,可以通过新的微服务对现有代码进行现代化。 应用程序现代化分为五个阶段,可以在任意阶段开始和停止操作。 其中包括:

1) 从传统单一式应用程序入手。
2) 直接迁移 - 使用容器或来宾可执行文件在 Service Fabric 中托管现有代码。
3) 现代化 - 将新微服务与现有容器化代码一起添加。
4) 创新 - 完全根据需求,将单一式应用程序分解成微服务。
5) 转换为微服务 - 转换现有的单一式应用程序,或生成新领域应用程序。

迁移到微服务

有必要再次强调,可以在其中任一阶段启动和停止。 不会强迫你继续前进到下一阶段。 现在,让我们来看看每个阶段的示例。

直接迁移 - 许多公司都出于两个原因,将现有单一式应用程序直接迁移到容器中:

  • 由于整合和移除现有硬件或以较高密度运行的应用程序,因此成本降低。
  • 开发和运营遵循一致的部署协定。

成本降低可以理解,在 Azure 内部,大量现有应用程序正在进行容器化,节省的成本就高达数百万美元。 虽然部署一致性难以评估,但同样很重要。 这意味着,开发者仍可以自由选择适合自己的技术;不过,运营人员只接受使用一种方法来部署和管理这些应用程序。 这样可以减轻运营压力,不必处理许多不同的复杂技术,也不用强制开发者只选择特定技术。 实质上,每个应用程序都容器化到独立式部署映像中。

许多组织止步于这一阶段。 它们已享受到容器带来的优势,Service Fabric 能够提供完整的管理体验,包括部署、升级、版本控制、回滚、运行状况监视等。

现代化 - 将新服务与现有容器化代码一起添加。 若要编写新代码,最好决定在微服务之旅上略进几步。 可以是添加新的 REST API 终结点,也可以是添加新的业务逻辑。 这样,便可以开始生成新的微服务,并进行开发和部署。

创新 - 还记得本文开头提及的推动微服务方法发展且不断变化的原始业务需求吗? 在此阶段,需要确定当前应用程序是否存在这种情况。如果存在,需要开始将单一式应用程序分解为服务或进行创新。 例如,被用作工作流队列时,数据库在处理方面成为瓶颈。 随着工作流请求数量不断增加,需要分布工作,以实现缩放。 因此,对于不缩放或需要频繁更新的特定应用程序部分,将其分解为微服务,并进行创新。

转换为微服务 - 在此阶段,应用程序完全由微服务组成或分解为微服务。 到此,已完成微服务之旅。 虽然可以从此阶段开始,但如果没有微服务平台提供帮助,这会是一项巨额投资。

微服务适合我的应用程序吗?

也许。 根据我们的经验,随着 Azure 中越来越多团队开始出于商业理由而以云为目标来生成,有许多团队都了解到采用类似微服务的方法所带来的优点。 例如,多年以来,必应一直在搜索方面开发微服务。 微服务方法对于其他团队而言相当新颖。 团队发现需要解决一些疑难问题,但这并非他们的强项。 这就是为什么 Service Fabric 受到重视而成为生成服务的最佳技术。

Service Fabric 的目标是将使用微服务方法生成应用程序时的复杂性降低,使你不需要经历许多耗费成本的重新设计工作。 方法是:从小规模开始,按需缩放,淘汰过时服务,添加新服务,根据客户使用情况而不断改进。 我们也知道,还需要解决许多其他问题,才能让微服务更易为大部分开发人员所接受。 容器和执行组件编程模型都是朝此目标前进的一小步,我们确信将涌现出更多的创新来轻松实现目标。

后续步骤