微服务扩展:以 99% 的处理效率来应对不断增长的需求

原文链接(请科学上网):https://blog.stackademic.com/scaling-microservices-strategies-for-handling-increased-demand-with-99-efficiency-1ce47dd02490

image_credit — uber.com

朋友们大家好,很多朋友都曾建议我写一篇如何在实际工作中实现微服务可扩展性的文章?这就是我写这篇文章的初衷,在这篇文章中我将会分享我对实现微服务可扩展性的一些理解,并为大家提供一个将微服务扩展至百万服务的案例,同时能够保障 99% 的时间正常提供服务,而这正是 Uber.com(我最喜欢的出租车叫车服务)的应用程序。

创建一个能够正常运行的微服务是一回事,而创建一个每天与数百万用户完成数十亿次交互的微服务则完全不同。

近年来,微服务架构因其模块化、独立且高度可扩展的软件架构能力而受到广泛欢迎。然而,随着应用系统用户数量和访问量的增长,如何实现微服务的高效扩展也成为一项极具挑战的任务。

在前面的几篇文章中,我一直在分享我在微服务和 Spring Cloud 方面的经验,例如微服务最佳实践微服务设计模式50 个微服务常见面试题Spring Cloud 所具备的 10 个微服务特性,我之前还分享过关于SAGA 设计模式单体与微服务架构等文章。

在本文中,我们将深入探讨如何应对微服务架构中不断增长的流量和不断变化的需求,重点关注负载平衡、弹性扩展和性能优化,同时我们还将通过一个真实的案例来理解如何在实际工作中运用这些概念。


1. 微服务扩展方面的挑战

微服务架构将单一应用程序拆分成多个较小的、互连的服务,这些服务通过网络进行通信。

这种设计非常地灵活,可以更充分的实现资源利用以及服务的独立开发和部署。然而随着用户流量的增长,个别的服务可能会出现瓶颈,遇到性能问题。

如何实现微服务扩展,软件开发团队会面临几个挑战,来应对微服务架构中不断增长的流量和不断变化的需求。主要挑战包括:

  1. 服务依赖:微服务通常依赖其他服务来实现特定功能;随着流量的增加,服务之间的互相依赖可能会导致瓶颈和性能问题,从而影响整个系统的可扩展性;
  2. 数据管理:跨分布式微服务场景中协调和管理数据可能会变得复杂,尤其是在处理海量数据时,确保跨多个服务的数据一致性、可用性和完整性是一个需要面对的挑战;
  3. 网络通信开销:微服务通过网络进行通信,随着服务数量的增长,网络通信可能会产生巨大的开销,这可能会导致系统延迟和响应时间变长,从而影响用户体验;
  4. 维护复杂性:维护和监控大量微服务需要强大的基础设施、部署和监控工具,随着系统的扩展,管理工作会变得越来越复杂;
  5. 动态可扩展性:虽然自动扩展是一项关键策略,但根据实际需要动态添加或删除实例可能会导致资源争用,尤其是在操作不当的情况下;
  6. 一致性和事务:确保分布式微服务之间的事务一致性是一项具有挑战性的任务,多个服务的变更操作全部完成或在发生故障时全部回滚是很复杂的工作;
  7. 状态管理:管理微服务的状态,尤其是在需要状态的应用场景中,可能会很困难,处理有状态服务的故障转移和主从复制增加了整个扩展过程的复杂性;
  8. 安全和授权:在处理增长的流量的同时确保微服务的安全性需要强大的身份验证和授权机制,随着请求数量的增长,安全性管理变得非常重要。

应对这些挑战需要仔细进行系统规划、架构设计以及采用一些在微服务开发、部署和运维方面的最佳实践。微服务的自动扩展需要专业技术知识、监控工具和持续优化工作相结合。

但是不用担心,我们将会学习一些可以遵循的最佳实践,将微服务扩展到数百万级用户量,并保证 99% 的效率。


2. 理解负载均衡

负载均衡是在微服务的多个实例之间分配传入请求流量的关键策略,来确保资源被充分利用并防止某个实例流量过载。

有多种负载均衡算法,每种算法都有其优缺点和使用场景:

  1. 轮询算法:请求按顺序循环均匀分布在多个实例之间;
  2. 最少连接算法:流量会被路由到活动连接最少的服务器;
  3. 加权轮询算法:根据容量为服务器分配不同的权重。

我们还可以使用 API 网关 等模式作为微服务架构中的负载均衡器,以在微服务的多个实例之间分配请求流量。

API 网关充当客户端访问各种微服务的单一入口点,提供负载均衡、流量路由、安全性等能力,我在之前的文章中也深入探讨了 API 网关的工作原理


3. 弹性扩容:适应需求变化

这是我们用来将微服务扩展到百万级的另一种策略,弹性扩容允许微服务应用根据流量波动动态调整资源数量。

弹性扩容允许系统无需手动增加或者删除实例,而是持续监控流量负载并根据实际需要自动添加或删除实例。

这种策略确保了最佳性能和成本效率。

触发弹性扩容的关键指标包括CPU利用率内存使用率系统响应时间。主流的云平台服务商,像 AWSGoogle CloudAzure 都提供与微服务部署集成的弹性扩容服务。

下图是在 AWS 云服务中设置自动扩容的示例:


4. 性能优化:确保高效执行

性能优化是实现应用程序扩展并保障其响应能力的非常传统的策略。性能优化涉及对微服务功能进行微调以最大限度地提高效率并最大限度地缩短请求响应时间。性能优化的技术包括:

  1. 缓存:将经常访问的数据存储在内存中,来减少数据库查询操作;
  2. 异步处理:将资源密集型任务放到后台任务或队列中执行;
  3. 数据库分片:将数据分布到多个数据库实例以提高读写性能。

下图是 AWS 无服务器架构中使用缓存的另一个非常好的示例:

image — https://aws.amazon.com/blogs/architecture/data-caching-across-microservices-in-a-serverless-architecture/


5. 现实中真实案例:Uber 系统的可扩展性之旅

没有什么是比研究一个真实的案例更好的方法来理解某个事情了,让我们看一个现实世界的真实案例来理解这些扩展策略的实际应用:约车服务巨头 Uber

Uber 的微服务架构使其能够在全球众多城市中高效运营,每天为数百万用户提供服务。随着 Uber 的受欢迎程度不断飙升,有效扩展系统微服务变得至关重要。

这里还要顺便说一句,对于软件开发人员我还有另外一个建议是阅读 UberNetFlix 等科技巨头的工程博客,学习他们如何应对软件开发中的挑战,这能够提高大家的知识和理解力。

Uber 公司的微服务架构如下所示:

通过这幅图大家可以了解到他们正在使用 API 网关、缓存代理以及更多大家可以学习借鉴的东西,方便将我们的微服务扩展到数百万级。

6. Uber 系统架构中的负载均衡

为了应对大流量,Uber 在系统中使用了强大的负载均衡机制;当用户打开 Uber 应用程序时,他们的请求将被重定向到用户附近的数据中心。

在数据中心内部,负载均衡器使用最少连接算法将请求分发到负载最低的微服务实例。

这种机制确保了用户请求的均匀分布,防止某个微服务实例变得不堪重负。我们可以在此处学习有关 Uber 实时负载均衡机制的更多信息。


7. 弹性扩容以满足系统需要

在流量高峰时段或特殊活动期间,Uber 系统的用户请求会激增;为了应对这些高峰,Uber 广泛使用了弹性扩容机制。

例如,负责匹配乘客和司机的“乘车约车”微服务会根据传入请求数量和平均响应时间等指标动态扩容服务实例数量。

Uber 的弹性扩容系统会监控这些指标并自动调整实例数量,以确保系统保持较短的响应时间和快速的完成乘车匹配。当流量减少时,微服务的实例就会减少,从而节约资源使用和成本。


8. 性能优化,打造无缝体验

Uber 的应用程序提供实时位置跟踪,这对微服务应用的性能要求非常高。为了优化性能,Uber 系统广泛使用缓存。

驾驶员和乘客数据以及乘车状态变更都缓存在内存中,从而减少了频繁的数据库查询操作。

此外 Uber 采用异步机制计算乘客乘车费用、发送通知等任务。

通过将这些任务转移到后台任务或队列中执行,微服务系统可以快速处理用户乘车数据,减少对用户体验的影响。

结论

这就是将一个微服务扩展到数百万级用户所需要做的重要工作,虽然这些工作看起来并不难,但是当我们真正去做时,我们还是需要对系统进行仔细的计划。

随着用户数量不断增加,实现微服务的高效扩展是现代应用程序开发中一个很关键方面。负载均衡、弹性扩容和性能优化是确保基于微服务的应用程序实现最佳性能、可靠性和成本效益的根本策略。

Uber 等现实中真实的案例展示如何在实际工作实施这些策略,也展示了它们在处理大流量和多样化需求方面的高效性。

通过使用负载均衡算法、弹性扩容机制和性能优化技术,我们可以创建具备弹性且响应迅速的微服务生态系统,即使在高峰使用期间也能提供无缝的用户体验。

总之,面对不断增长的用户期望和流量,掌握扩展微服务的艺术对于旨在提供高质量数字服务的企业来说是至关重要。

顺便说一句,如果大家正在准备微服务面试,那么还应该准备一些其它问题,比如API网关和负载均衡之间的差异SAGA模式如何管理微服务中的事务SAGA 和 CQRS模式之间的差异,这些问题在面试中也很常见。

感谢您的阅读,本文由 董宗磊的博客 版权所有。如若转载,请注明出处:董宗磊的博客(https://dongzl.github.io/2023/09/23/24-Scaling-Microservices-Strategies-Handling-Increased-Demand-Efficiency/
微服务中 SAGA 和 CQRS 设计模式的差异?
系统设计中正向代理和反向代理的差异