七、扩展 RESTful 服务——Web 服务的性能

在网络世界中,每个人都在编写或寻找一个网络应用。 随着需求的增加,每个 web 应用都需要能够服务更多的请求——有时一天数千个请求。 因此,应该编写应用来处理这种巨大的请求。

例如,假设您是负责开发公司旗舰产品 FlixOne Store 的开发和支持团队的一员。 该产品很受欢迎,并获得了吸引力,导致您的电子商务网站(FlixOne)被消费者流量淹没。 你系统里的支付服务很慢,几乎导致整个系统瘫痪,导致你失去客户。 虽然这是一个想象的场景,但它可以发生在现实生活中,并可能导致业务损失。 为了避免这种情况,您应该考虑 FlixOne 应用的可伸缩性。

可伸缩性是关键系统最重要的非功能需求之一。 用几百个事务服务几个用户与用几百万个事务服务几百万个用户是不一样的。

在本章中,我们将一般地讨论可伸缩性。 我们还将讨论如何扩展 RESTful 服务,在设计它们时要考虑什么,以及如何使用不同的模式(包括对常规应用也有帮助的技术、库和工具)来避免级联故障。

读完本章,你将会学到:

  • 聚类
  • 负载平衡
  • 可伸缩性简介

聚类

集群是在多个服务器上提供相同服务的一种方法。 通过添加更多的服务器,您可以避免不受控制的情况,例如故障转移、系统崩溃等等。 在数据库上下文中,集群指的是多个服务器实例连接到单个服务器的能力。 容错和负载均衡是集群的两个主要优点。

负载平衡

在集群时,负载平衡器是一个有用的工具。 您可以将负载平衡定义为一种设备,它帮助在集群服务器内或跨集群服务器分发网络或应用流量,并提高应用的响应能力。

在实现中,负载均衡器被放置在客户机和服务器之间。 它有助于在多个服务器上平衡多个应用请求。 换句话说,负载均衡器减少了单个服务器的时间,并防止了应用服务器故障。

它是如何工作的?

负载平衡器的工作是确保应用的服务器可用。 如果一个应用的服务器不可用,负载均衡器会将所有新请求重定向到可用的服务器,如下图所示:

在上面的图中,您可以看到负载均衡器在其典型环境中,其中一个系统接受来自互联网上不同来源的多个请求,然后由负载均衡器从多个服务器管理这些请求。

In .NET, this arrangement is also known as a web farm (https://www.codeproject.com/Articles/114910/What-is-the-difference-between-Web-Farm-and-Web-Ga).

负载均衡器使用各种算法,也称为负载均衡器方法:最小连接法、轮询法、最小响应时间法、最小带宽法、最小数据包法、自定义负载法等等。

负载均衡器在应用的可伸缩性中扮演着重要的角色,因为它确保应用的服务器对服务器请求可用。 请注意,您将需要在不更改代码的情况下安排硬件基础设施,以满足负载平衡器的需求(然而,有些场景需要更改代码)。 市场上有很多负载平衡器,如 Incapsula (https://www.incapsula.com/),F5 (https://www.f5.com/),Citrix Netscaler (https://www.citrix.com/),直流发电机(https://dyn.com/),亚马逊弹性负载平衡,和亚马逊 ELB(【显示】https://aws.amazon.com/)。

在接下来的章节中,我们将研究扩展系统的不同方法。

介绍了可伸缩性

每个应用都有自己的服务请求的能力。 应用的能力是指它的性能以及在负载增加时它如何满足其目标。

许多 web 应用将此称为在规定时间内的请求数。

在设计 web 应用时,做出正确的设计决策是非常重要的; 设计决策会影响服务的可伸缩性。 一定要达到适当的平衡,以便您的方法考虑服务及其基础设施以及任何伸缩需求。

性能和可伸缩性是系统的两个不同特征。 性能处理的是系统的吞吐量,而可伸缩性处理的是为更多的用户或更多的事务提供所需的吞吐量。

缩放(垂直缩放)

向上扩展(也称为垂直扩展)是通过向同一台机器添加更多资源(如内存或更快的处理器)来实现可伸缩性的一种方法。 这并不总是适用于所有应用,因为成本也是考虑垂直扩展时的一个因素。

您还可以升级资源或硬件,而不是向您的机器添加新资源。 例如,如果您有 8gb 的 RAM,您可以将其升级到 16gb,同样的事情也适用于处理器和其他资源。 不幸的是,随着硬件的升级,您可以对机器进行多大的扩展是有限制的。 这可能导致简单地转移瓶颈,而不是解决提高可伸缩性的真正问题。

您还可以将应用迁移到完全不同的机器上,例如简单地将应用迁移到更强大的 MacOS 上。

垂直扩展不涉及任何代码更改,所以它是一项简单的任务,但它涉及额外的成本,因为它是一项相当昂贵的技术。 Stack Overflow 是那些基于. net 的垂直伸缩系统中罕见的例子之一。

向外缩放(水平缩放)

向上扩展、向外扩展或水平扩展会向服务请求添加更多的服务器或节点,而不是资源。 如果不想扩展应用,总有办法向外扩展。

当应用代码不依赖于它所运行的服务器时,向外扩展是一种成功的策略。 但是,如果请求需要在特定的服务器上执行,也就是说,如果应用代码具有服务器亲和性,则很难向外扩展。 对于无状态代码,它更容易在任何服务器上执行。 因此,当无状态代码在水平伸缩的机器或集群上运行时,可伸缩性得到了提高。由于横向缩放的性质,它是整个行业常用的方法。 有许多用这种方式管理大型可伸缩系统的例子,如谷歌、Amazon 和 Microsoft。

线性可伸缩性

线性可伸缩性是指应用 Amdahl 定律(https://en.wikipedia.org/wiki/Amdahl%27s_law)垂直扩展应用。 在这里,您还可以考虑并行计算。

并行计算是一种计算体系结构,它表示多个处理器同时执行处理。

在你的应用中线性可伸缩性的好处包括:

  • 不需要更改代码
  • 可以很容易地添加额外的资源
  • 有物理可用性

分布式缓存

在分布式缓存技术的帮助下,我们可以提高 RESTful web 服务(web API)的可伸缩性。 分布式缓存可以存储在集群的多个节点上。 分布式缓存提高了 web 服务的吞吐量,因为缓存不再需要对任何外部资源进行 I/O 访问。

这种方法有以下优点:

  • 客户得到相同的结果
  • 分布式缓存由持久性存储进行备份,并作为不同的远程进程运行; 即使应用服务器重新启动或出现任何问题,也不会影响缓存
  • 源数据存储所发出的请求较少

缓存持久化数据(数据层缓存)

与应用性能类似,您还应该考虑数据库性能。 通过缓存持久化数据,在向数据库添加缓存层后,您将获得更好的性能。 当应用中大量使用读请求时,这一点也很重要。 现在我们将以 EF Core 的缓存级别为例。

一级缓存

这是 EF Core 启用的内建会话缓存。 从服务的第一个请求开始,从数据库中检索对象并存储在 EF Core 会话中。 换句话说,EF Object Context 和 DbContext 维护它们所管理的实体的状态信息。 一旦上下文不再可用,它的状态信息也就消失了。

第二级缓存

对于以分布式方式开发的应用,或者需要持久化数据的长时间运行的请求,如 web 应用,二级缓存是很重要的。 二级缓存存在于事务或应用的范围之外,并且这些缓存可用于任何上下文或实例。 您可以使用应用可用的缓存机制,而不用编写自己的代码,比如 Memcached。

应用缓存

应用缓存或应用层缓存有助于缓存应用中的任何对象。 这进一步提高了应用的可伸缩性。 在下一节中,我们将讨论各种可用的缓存机制。

CacheCow

当你想在客户端和服务器上都实现 HTTP 缓存时,就会用到 CacheCow。 这是一个轻量级的库.NET web API 支持目前是可用的。 CacheCow 是开源的,并带有一个 MIT 许可,可以在 GitHub 上获得(https://github.com/aliostad/CacheCow)。

要开始使用 CacheCow,你需要通过以下步骤为服务器和客户端做好准备:

  1. 在你的 ASP 中安装Install-Package CacheCow.ServerNuGet 包.NET Web API 项目; 这将是您的服务器。
  2. 在客户端项目中安装Install-Package CacheCow.ClientNuGet 包; 客户端应用将是 WPF、Windows 窗体、控制台或任何其他 web 应用。

  3. 创建一个缓存存储。 您需要创建一个缓存

    store

    在服务器端,需要一个数据库来存储缓存元数据(https://github.com/aliostad/CacheCow/wiki/Getting-started#cache-store)。

Memcached

Memcached 是一个可定制的开源项目; 您可以使用源代码,并根据您的需求添加和更新它。 Memcached 的官方页面(https://memcached.org/)定义为:

"An in-memory key-value store for small chunks of arbitrary data (strings, objects) from results of database calls, API calls, or page rendering." Refer to https://www.deanhume.com/memcached-for-c-a-walkthrough/ for a complete walkthrough.

Azure 复述,缓存

Azure Redis Cache 是建立在一个叫做 Redis(https://github.com/antirez/redis)的开源存储之上的,它是一个内存中的数据库,并在磁盘上持久化。 根据微软的描述(https://azure.microsoft.com/en-in/services/cache/):

"Azure Redis Cache is based on the popular open source Redis cache. It gives you access to a secure, dedicated Redis cache, managed by Microsoft and accessible from any application within Azure."

开始 Azure Redis 缓存是非常简单的,如果你采取以下步骤:

  1. 创建一个 web API 项目。 参考前面章节中的代码示例。
  2. 实现复述。 转诊点请使用https://github.com/StackExchange/StackExchange.Redis。 另外,安装Install-Package StackExchange.RedisNuGet 包。

  3. 更新 CacheConnection 的配置文件(https://docs.microsoft.com/en-us/azure/redis-cache/cache-dotnet-how-to-use-azure-redis-cache#NuGet)。

  4. 然后,在 Azure(https://docs.microsoft.com/en-us/azure/redis-cache/cache-web-app-howto#publish-and-run-in-azure)上发布。

通信(异步)

沟通这个术语是不言自明的; 它是服务之间的交互行为。 这方面的例子包括如下:

  • 在同一应用中与另一个服务通信的服务
  • 与应用外部的另一个服务通信的服务(外部服务)
  • 与组件(内部或外部)通信的服务

当消息或数据通过线路时,该通信通过 HTTP 协议进行。

应用的性能会影响服务之间的通信方式。

异步通信是帮助扩展应用的方法之一。 在 ASP。 . NET Core,我们可以通过使用异步 HTTP 调用(异步编程):https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/

在处理异步通信时,您应该小心操作,例如,在添加带有映像的新产品时。 设计了一个系统,可以创建不同大小的图像的缩略图。 这是一项耗时的任务,如果处理不当,可能会导致性能下降。 从设计的角度来看,异步操作在此场景中不起作用。 在这里,您应该实现类似于带有回调的任务之类的东西,它告诉系统作业何时完成。 有时,您可能还需要中间件来处理请求。

实现异步通信的最佳方法是使用异步 RESTful API。

在创建可伸缩系统时,必须始终考虑异步通信。

总结

在本章中,我们讨论了可伸缩性,包括可用的库、工具等等。 然后,我们讨论了如何扩展 RESTful 服务,在设计它们时要考虑什么,以及如何使用不同的模式避免级联失败。

在接下来的章节中,我们将讨论并构建一个 web 客户机来调用和使用 RESTful 服务。