2、微服务入门与挑战应对
微服务入门与挑战应对
1. 走进微服务
早在2014年了解微服务概念时,我才意识到自己在2009年参与的一个项目中,其实已经在不知不觉中开发类似微服务的东西了。当时我们开发了一个基于一系列独立功能的平台,为了方便客户挑选使用平台功能,每个功能都被开发成一个自主软件组件,拥有自己的持久数据,并且仅通过定义良好的API与其他组件通信。
平台组件从A到F进行了泛化命名,每个组件都有自己的持久数据存储,不与其他组件共享数据库。组件使用Java和Spring框架开发,打包成WAR文件,部署在Java EE Web容器(如Apache Tomcat)中。根据客户需求,平台可部署在单台或多台服务器上,比如两节点部署场景。
2. 自主软件组件的好处
将平台功能分解为一组自主软件组件带来了诸多好处:
- 部分部署 :客户可以使用定义良好的API,将平台的部分组件部署到自己的系统环境中,并与现有系统集成。例如,某客户选择部署组件A、B、D和E,并与系统A和系统B集成。
- 功能替换 :客户可以用自己系统中已有的实现替换平台的部分功能,可能需要对平台API中的现有功能进行一些调整。比如,某客户用自己的实现替换了平台中的组件C和F。
- 独立升级 :平台中的每个组件都可以独立交付和升级。由于使用了定义良好的API,一个组件升级到新版本时,不依赖其他组件的生命周期。例如,组件A从v1.1升级到v1.2,调用组件A的组件B无需升级。
- 独立扩展 :借助定义良好的API,平台中的每个组件都可以独立扩展到多个服务器。可以通过手动在运行Java EE Web容器的服务器前设置负载均衡器来实现扩展,以满足高可用性要求或处理更高的请求量。例如,组件A扩展到三个实例。
3. 自主软件组件带来的挑战
将平台分解为多个组件也带来了一些新挑战,这些挑战在开发传统单体应用时并未遇到(至少程度没这么严重):
|挑战|详情|
| ---- | ---- |
|实例添加困难|添加新实例需要手动配置负载均衡器和设置新节点,既耗时又容易出错。|
|易受外部影响|平台最初容易受到与其通信的其他系统的错误影响。如果某个系统不能及时响应平台发送的请求,平台会很快耗尽关键资源,导致组件挂起甚至崩溃。由于大部分通信是同步的,一个组件崩溃可能导致级联故障。|
|配置管理复杂|保持所有组件实例的配置一致和最新是个难题,会导致大量手动和重复工作,还会不时出现质量问题。|
|监控难度大|监控平台的延迟问题和硬件使用情况(如CPU、内存、磁盘和网络使用)比监控单体应用的单个实例更复杂。|
|日志收集和关联困难|从多个分布式组件收集日志文件并关联相关日志事件很困难,但由于组件数量固定且已知,仍具有一定可行性。|
随着时间推移,我们通过内部开发的工具和详细的手动处理说明,解决了大部分上述挑战。虽然手动发布组件新版本和处理运行时问题的流程不太理想,但在当时的操作规模下是可以接受的。
4. 微服务的兴起
2014年了解基于微服务的架构后,我发现其他项目也在面临类似挑战(部分原因与我前面描述的不同,例如大型云服务提供商要满足网络规模的需求)。许多微服务先驱分享了他们的经验教训,这些经验很有学习价值。
很多先驱最初开发的单体应用在业务上取得了成功,但随着时间推移,这些单体应用变得越来越难以维护和演进,也难以进行垂直扩展。于是,他们开始将单体应用拆分成更小的组件,这些组件可以独立发布和扩展。水平扩展可以通过在多台较小的服务器上部署组件,并在前面放置负载均衡器来实现。在云端进行扩展时,理论上扩展能力是无限的,只取决于引入的虚拟服务器数量。
与此同时,我还了解到一些新的开源项目,它们提供了简化微服务开发的工具和框架,可用于应对基于微服务架构带来的挑战:
- Spring Cloud :Pivotal发布的Spring Cloud封装了部分Netflix OSS,提供动态服务发现、配置管理、分布式跟踪、断路器等功能。
- Docker :Docker和容器革命极大地缩小了开发和生产之间的差距。可以将组件打包成完整的镜像,在运行Docker的服务器上作为容器启动,这对开发和测试是一个巨大的进步。
- 容器编排器 :仅靠Docker这样的容器引擎不足以在生产环境中使用容器,还需要能确保所有容器正常运行并能在多台服务器上扩展容器的产品,即容器编排器。近年来出现了许多容器编排器,如Apache Mesos、Docker Swarm模式、Amazon ECS、HashiCorp Nomad和Kubernetes。Kubernetes最初由Google开发,2015年发布v1.0版本,并捐赠给了CNCF。到2018年,Kubernetes成为了事实上的标准,既可以预装用于本地使用,也可以作为大多数主要云服务提供商的服务使用。
- 服务网格 :2018年,我开始了解服务网格的概念,它可以与容器编排器配合使用,进一步减轻微服务的管理和弹性方面的负担。
5. 示例微服务架构
由于无法涵盖上述所有技术的各个方面,后续将重点关注自2014年以来在客户项目中被证明有用的部分,描述如何将它们结合起来创建可管理、可扩展和有弹性的协作微服务。后续会使用一组协作微服务来演示如何将这些技术整合在一起,目前只需知道其架构大致如下:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(Microservice A):::process --> B(Microservice B):::process
A --> C(Microservice C):::process
B --> D(Microservice D):::process
C --> D
需要注意的是,这只是一个非常小的协作微服务系统环境。后续章节中添加的周边支持服务,对于这几个微服务来说可能看起来过于复杂,但本书提出的解决方案旨在支持更大规模的系统环境。
6. 微服务的定义
微服务架构是将单体应用拆分成更小的组件,主要实现两个目标:
- 实现更快的开发,支持持续部署。
- 更易于手动或自动扩展。
微服务本质上是一个自主软件组件,可独立升级、替换和扩展。要成为自主组件,必须满足以下标准:
- 无共享架构 :微服务之间不共享数据库中的数据。
- 接口通信 :仅通过定义良好的接口进行通信,可以使用API和同步服务,或者更优选地通过异步发送消息。使用的API和消息格式必须稳定、文档完善,并遵循定义好的版本控制策略。
- 独立部署 :作为独立的运行时进程进行部署。每个微服务实例在单独的运行时进程(如Docker容器)中运行。
- 无状态实例 :微服务实例是无状态的,因此微服务的任何实例都可以处理传入的请求。
使用一组协作微服务,可以将应用部署到多台较小的服务器上,而不是像部署单体应用那样只能部署到一台大型服务器上。满足上述标准后,与扩展大型单体应用相比,将单个微服务扩展到更多实例(例如使用更多虚拟服务器)更加容易。利用云端的自动扩展功能也是可行的,但对于大型单体应用来说通常不可行。而且,与升级大型单体应用相比,升级甚至替换单个微服务也更加容易。
关于微服务的大小,有以下经验法则:
- 足够小,让开发人员能够全面理解。
- 足够大,不会影响性能(即延迟)和/或数据一致性(不同微服务中存储的数据之间的SQL外键不再是理所当然的)。
综上所述,微服务架构本质上是一种将单体应用分解为一组协作自主软件组件的架构风格,目的是实现更快的开发和更轻松的扩展。
7. 微服务面临的挑战
除了前面提到的自主软件组件带来的挑战外,将应用分解为一组自主组件还形成了一个分布式系统,而分布式系统天生就很难处理。Peter Deutsch在1994年提出的“分布式计算的8大谬误”很好地说明了这一点:
1. 网络是可靠的。
2. 延迟为零。
3. 带宽是无限的。
4. 网络是安全的。
5. 网络拓扑不会改变。
6. 只有一个管理员。
7. 传输成本为零。
8. 网络是同质的。
通常,基于这些错误假设构建的微服务解决方案,容易受到临时网络故障和其他微服务实例中出现的问题的影响。随着系统环境中微服务数量的增加,出现问题的可能性也会增加。一个好的经验法则是,在设计微服务架构时,假设系统环境中总会出现问题。微服务架构需要设计成能够检测问题并重启失败的组件。在客户端,要确保请求不会发送到失败的微服务实例。问题解决后,应恢复对之前失败的微服务的请求,即微服务客户端需要具备弹性。当然,所有这些都需要完全自动化,因为对于大量微服务,操作人员手动处理是不可行的。
8. 微服务设计模式
为了应对微服务带来的挑战,可以使用设计模式。设计模式的概念由来已久,它描述了在特定上下文中解决问题的可重用解决方案。使用经过验证的设计模式解决方案,比自己花时间发明解决方案可以节省大量时间,并提高实现的质量。
我们将涵盖的设计模式包括:
- 服务发现
- 边缘服务器
- 响应式微服务
- 中央配置
- 集中式日志分析
- 分布式跟踪
- 断路器
- 控制循环
- 集中式监控和警报
这个列表并非详尽无遗,而是处理前面所述挑战所需的最小设计模式列表。我们将采用轻量级的方法来描述设计模式,重点关注以下方面:
- 问题
- 解决方案
- 解决方案的要求
后续将深入探讨如何应用这些设计模式。这些设计模式的应用场景是一个协作微服务的系统环境,其中微服务之间通过同步请求(例如使用HTTP)或异步消息(例如使用消息代理)进行通信。
以服务发现模式为例,其面临的问题是:客户端如何找到微服务及其实例?后续会针对每个设计模式详细探讨其解决方案和要求。
微服务入门与挑战应对
9. 服务发现模式详解
服务发现模式旨在解决客户端如何找到微服务及其实例的问题。以下是对该模式的详细解析:
|方面|详情|
| ---- | ---- |
|问题|客户端在复杂的微服务环境中,难以直接定位所需的微服务及其实例。例如,在一个包含众多微服务的系统中,客户端需要调用某个特定微服务时,无法知晓该微服务具体部署在哪些服务器上。|
|解决方案|可以采用集中式服务注册表,微服务在启动时将自身的信息(如IP地址、端口、服务名称等)注册到注册表中,客户端通过查询注册表来获取所需微服务的信息。也可以使用基于DNS的服务发现,将微服务的名称映射到对应的IP地址。|
|解决方案要求|服务注册表需要具备高可用性和一致性,确保客户端能获取到准确的微服务信息。同时,注册和查询操作要高效,以减少客户端的等待时间。
10. 其他设计模式介绍
除了服务发现模式,其他设计模式也在应对微服务挑战中发挥着重要作用:
- 边缘服务器
- 问题 :如何统一管理外部对微服务系统的访问,确保安全性和性能。
- 解决方案 :在系统边缘设置服务器,作为所有外部请求的入口。边缘服务器可以进行请求路由、负载均衡、安全认证等操作。
- 解决方案要求 :具备高性能和高并发处理能力,能够快速响应大量外部请求。同时,要提供完善的安全机制,防止外部攻击。
- 响应式微服务
- 问题 :在高负载情况下,如何保证微服务的响应性能和弹性。
- 解决方案 :采用响应式编程模型,使微服务能够异步、非阻塞地处理请求。通过事件驱动和流处理,提高系统的吞吐量和响应速度。
- 解决方案要求 :微服务需要具备良好的异步处理能力,能够处理大量并发请求而不出现阻塞。同时,要能够根据负载情况自动调整资源分配。
- 中央配置
- 问题 :如何统一管理众多微服务的配置信息,确保配置的一致性和可维护性。
- 解决方案 :建立中央配置服务器,所有微服务从该服务器获取配置信息。当配置发生变化时,服务器可以实时通知相关微服务进行更新。
- 解决方案要求 :中央配置服务器需要具备高可用性和数据一致性,确保微服务获取到的配置信息准确无误。同时,要提供方便的配置管理界面,便于管理员进行配置修改和发布。
- 集中式日志分析
- 问题 :如何从多个分布式微服务中收集和分析日志,以便进行故障排查和性能优化。
- 解决方案 :使用日志收集工具(如ELK Stack)将各个微服务的日志集中收集到一个日志存储系统中,然后通过日志分析工具进行分析和可视化展示。
- 解决方案要求 :日志收集工具要具备高效的数据采集和传输能力,能够实时收集微服务的日志信息。日志存储系统要具备大容量和高可靠性,能够存储大量的日志数据。
- 分布式跟踪
- 问题 :在微服务系统中,如何跟踪一个请求在多个组件之间的处理过程,以便进行性能分析和故障定位。
- 解决方案 :为每个请求分配一个唯一的跟踪ID,在请求经过的各个微服务中传递该ID,并记录相关的处理信息。通过分布式跟踪系统(如Zipkin)对这些信息进行收集和分析。
- 解决方案要求 :分布式跟踪系统要具备低侵入性,对微服务的性能影响要小。同时,要能够准确地跟踪请求的处理路径和时间消耗。
- 断路器
- 问题 :当某个微服务出现故障时,如何避免级联故障,保护整个系统的稳定性。
- 解决方案 :在调用微服务的客户端引入断路器机制。当某个微服务的失败率超过一定阈值时,断路器打开,直接返回错误信息,避免继续调用故障服务。一段时间后,断路器尝试半开状态,重新调用服务,如果服务恢复正常,则关闭断路器。
- 解决方案要求 :断路器要能够实时监测微服务的调用情况,准确判断服务是否出现故障。同时,要具备合理的阈值设置和状态转换机制。
- 控制循环
- 问题 :如何动态调整微服务的资源分配和行为,以适应不同的负载和环境变化。
- 解决方案 :建立控制循环机制,通过监控微服务的性能指标(如CPU使用率、响应时间等),根据预设的规则自动调整微服务的资源配置(如增加或减少实例数量)。
- 解决方案要求 :控制循环要具备实时性和准确性,能够及时响应系统的变化。同时,要提供灵活的规则配置界面,便于管理员根据实际情况进行调整。
- 集中式监控和警报
- 问题 :如何实时监控微服务系统的运行状态,及时发现并处理潜在的问题。
- 解决方案 :使用监控工具(如Prometheus、Grafana)对微服务的各项指标进行监控,并设置相应的警报规则。当指标超过阈值时,系统自动发出警报通知管理员。
- 解决方案要求 :监控工具要具备全面的指标采集能力,能够监控微服务的各个方面。警报规则要合理设置,避免误报和漏报。
11. 设计模式应用流程
下面通过一个mermaid流程图展示设计模式在微服务系统中的应用流程:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(客户端请求):::process --> B(边缘服务器):::process
B --> C{服务发现}:::process
C -->|找到微服务| D(调用微服务):::process
D --> E{是否出现故障}:::process
E -->|是| F(断路器打开):::process
F --> G(返回错误信息):::process
E -->|否| H(处理请求):::process
H --> I(记录日志):::process
I --> J(分布式跟踪):::process
J --> K(集中式日志分析):::process
L(中央配置):::process --> D
M(控制循环):::process --> D
N(集中式监控和警报):::process -->|监控指标| D
N -->|触发警报| O(通知管理员):::process
12. 总结
微服务架构在带来更快开发和更易扩展等优势的同时,也带来了一系列挑战。通过合理应用服务发现、边缘服务器、响应式微服务等设计模式,可以有效地应对这些挑战,构建出可管理、可扩展和有弹性的微服务系统。在实际应用中,需要根据具体的业务需求和系统环境,选择合适的设计模式,并进行合理的配置和优化。同时,要持续关注微服务技术的发展,不断学习和引入新的工具和方法,以提升微服务系统的性能和稳定性。
更多推荐


所有评论(0)