65.9K
CodeProject 正在变化。 阅读更多。
Home

Web Farm/Web Garden 场景下的状态管理和缓存处理方式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (57投票s)

2011年4月12日

CPOL

12分钟阅读

viewsIcon

229604

本文简要介绍了状态管理,并讨论了在 Web Farm/Web Garden 场景下处理状态管理的各种方法。

目录

引言

在本文中,我将讨论状态管理,但主要侧重于 Web Farm 和 Web Garden 场景,因为 CodeProject 上已经有很多关于此主题的优秀文章。此外,我之前已经写过几篇关于状态管理的文章。为了方便新读者,我将从我之前的文章中摘录前几部分,以简要介绍状态管理。在本文中,我将讨论 Web Farms/Web Gardens,之后将讨论在 Web Farm/Web Garden 场景下处理缓存的各种方法。

状态管理基础知识

众所周知,Web 是无状态的。每次将网页回发到服务器时,网页都会重新创建。在传统的 Web 编程中,页面和控件中的所有信息在每次回发时都会被清除。为了克服这个问题,ASP.NET 框架提供了多种方法来在各个阶段保存状态,例如控件状态、视图状态、Cookie、Session 等。这些可以在客户端和服务器端进行状态管理。请参见下图。

State Management in ASP.NET

维护状态的各种选项

在本文中,我将讨论服务器端状态管理技术。首先,让我们来谈谈 .NET 2.0 中引入的一个非常基本且关键的概念——AppDomain。

什么是 AppDomain

AppDomain 可以定义为一个轻量级进程,用于安全隔离和可用性。AppDomain 托管在某个进程中,一个进程可以托管多个 AppDomain。因此,一个 AppDomain 崩溃/重启不会影响同一进程中的其他 AppDomain。

AppDomain 在 ASP.NET 中的作用

AppDomain 在 ASP.NET 中起着关键作用。当 ASP.NET 收到第一个请求时,应用程序管理器会为其创建一个应用程序域。应用程序域非常重要,因为它们提供了 Web 服务器上各种应用程序之间的隔离,并且每个应用程序域都是独立加载和卸载的,在应用程序域中会创建一个 `HostingEnvironment` 类的实例,该实例提供对所有应用程序资源的访问。以下是示意图。

ASP.NET page processing

ASP.NET 处理第一个请求

AppDomain 负责所有服务器端状态管理,这意味着所有数据会话(InProc 模式)、应用程序对象/变量缓存,都驻留在 AppDomain 本身中。如果 AppDomain 崩溃,Web 服务器中的所有数据都将被清除。让我们来看看。

AppDomaincontains.PNG

所有服务器端状态管理数据都驻留在 AppDomain 中

现在让我们来谈谈 Web Farm 和 Web Garden。

什么是 Web Farm

Web Farm 用于高可用性应用程序,并且拥有大量无法由单个服务器处理的用户。它们提供了更好的性能并且易于扩展。这意味着我们将在网络负载均衡器 (NLB) 后面放置多个 Web 服务器。每当有请求进来时,它首先到达负载均衡器,负载均衡器会检查所有可用的 Web 服务器,找到请求相对较少的 Web 服务器,然后将请求传递给该 Web 服务器。以下是示意图。

Web Farm

Web Farm

大多数大型应用程序都部署在 Web Farm 场景下。单个服务器可能无法处理每天数百万的请求,我们为负载均衡器提供一个虚拟 IP,并将 URL 映射到负载均衡器;负载均衡器决定将请求传递给特定的 Web 服务器。

在此场景下,`InProc` 会话模式无效。我们需要使用 `OutProc` 模式,因为如果第一个请求由服务器 1 处理并存储了会话数据,但稍后另一个请求时,负载均衡器发现服务器 1 正在忙于处理其他请求,它可能会将请求传递给另一台服务器,而另一台服务器显然没有会话数据,这可能导致输出异常。

在 `OutProc` 模式下,会话数据不存储在 Web 服务器的 AppDomain 中。我们将数据存储在另一台服务器上。我们稍后会讨论。

亲和性

有一个称为亲和性参数设置的设置,可以进行设置,以便负载均衡器将来自同一客户端 IP 地址的所有请求定向到同一台计算机。这允许我们在 Web Farm 场景下无缝使用会话(InProc 模式)、应用程序数据和缓存。这意味着应用程序就像部署在单台服务器上一样运行。但这有一些限制,例如:

  • 如果在处理请求过程中服务器发生故障,则所有服务器数据都将丢失。
  • 这限制了 Web Farm 的使用,因为负载均衡器将被限制为仅将同一客户端的请求重定向到单个 Web 服务器。

请点击此链接详细了解:点击此处

什么是 Web Garden

当我们部署应用程序到 IIS(6 及以上版本)时,我们会为应用程序分配一个应用程序池。应用程序池用于与其他部署在同一 Web 服务器上的应用程序进行隔离。通常,一个应用程序池有一个工作进程(w3wp.exe)。在此工作进程之上创建一个 AppDomain,该 AppDomain 处理/响应客户端计算机发送的请求。所有服务器数据(会话、缓存、静态变量、应用程序变量)都存储在 AppDomain 边界内。但是,为了提高性能,我们可以在同一个应用程序池中拥有多个工作进程。这允许更好地处理客户端计算机发送的 Web 请求。但是,这些工作进程不共享内存,并且会为同一个应用程序创建新的 AppDomain,每个 AppDomain 都有自己的数据副本。这意味着如果某些会话存储在一个 AppDomain 的内存中,而下一个请求由另一台 Web 服务器处理,它将不会有之前存储的会话数据。

以下是示意图。

Application pools

前两个应用程序池显示 Web Garden 场景

Web Garden 利用多核处理器系统,从其他 CPU 中获益,从而提供性能优势。

亲和性

现在的问题是:在 Web Garden 场景下,我们是否有任何亲和性设置?是的。

存在一个硬编码的客户端连接亲和性到工作进程实例。因此,对于给定的客户端 TCP 连接,所有 HTTP 请求都将由同一实例的工作进程处理。

因此,正如我们所见,在设置亲和性参数的情况下,我们可以在 Web Farm/Web Garden 场景下托管我们的应用程序,而无需担心 Web 服务器数据的存储和管理方式。它将像我们的应用程序托管在单台服务器上一样无缝运行。

正如我们讨论过的亲和性参数的局限性,可以理解的是,不建议设置亲和性参数。

更多关于会话管理

让我们稍微讨论一下 Session。我们知道,Session 存储在 Web 服务器上。首先,让我们快速了解一下 Session 的存储方式。

存储 Session 有两种模式

  • InProc
  • OutProc

InProc:在此模式下,Session 值存储在应用程序正在运行的 Web 服务器的 AppDomain 中。由于存储在服务器内存中,因此从性能角度来看效率很高。但这并不具备很好的可伸缩性和健壮性,因为随着应用程序用户数的增加,您的应用程序在处理多个请求时可能会遇到困难,甚至可能崩溃。而且,对于需要高可用性的网站,这种方式不可行。

OutProc:Session 中的数据不存储在 Web 服务器内存的 AppDomain 中。每当您的数据离开 Web 服务器内存时,您都需要在再次使用之前对其进行序列化和反序列化。这也会带来性能开销。Session 存储在三种方式中:

  • StateServer:会话信息存储在一个状态服务器中,该服务器是一个名为 ASP.NET 状态服务的进程,与 ASP.NET 工作进程分开。这是一个单点故障。如果此服务/服务器发生故障,您的应用程序将突然停止工作。
  • SQL Server:我们将会话存储在 SQL Server 中。.NET 提供了一些默认脚本,可用于安装 SQL Server,使其准备好存储会话数据。此外,我们可以通过维护多台机器上的会话来构建集群。因此,如果一台机器发生故障,用户请求可以从另一台机器提供服务。
  • Custom aproach:ASP.NET 为我们提供了灵活性,可以编写自己的自定义提供程序来维护和存储 Session 数据。这允许我们根据需要随意存储会话数据。

我们已经对这些内容进行了大量讨论。其他状态管理方法,如 Cache、Application State、静态变量,情况如何?我们可以在 Web Farm/Web Garden 场景下使用 Application State 吗?我发现很多人对 Application 和 Cache 等其他状态管理技术知之甚少。

现在让我们来讨论 Cache。

如何在 Web Farm/Web Garden 场景下处理缓存

首先,您必须对 ASP.NET 中的缓存管理有一些基本了解。您可以访问以下链接,该链接对缓存管理进行了非常好的介绍:探索 ASP.NET 中的缓存

如何在 Web Farm 或 Web Garden 场景下处理存在于 AppDomain 中的缓存?最佳方法是在 Web Farm 或 Web Garden 场景下避免使用 Cache。这完全取决于需求以及您要在 Cache 中存储的数据类型。

如果您拥有非常静态的数据,例如国家名称,这些数据不会经常更改。在这种情况下,无论是在 Web Farm/Web Garden 场景下,都不会有太大影响。如果 AppDomain 中没有数据,它将从数据库加载。显然,一旦加载,它就不会改变,所以不用担心了。

现在我将讨论一些具体场景。

场景 1

您在文件系统中存储了一些数据。您的配置文件中有大量经常使用的数据。反复从配置文件读取不是一个好方法。最好将其放入 Cache 中,并在需要时从中检索。

方法

这是一个非常基本的情况:您可以在 Cache 中没有数据时初始加载数据,并设置文件依赖项。这意味着只要文件发生更改,缓存就会失效并更新,这将对 Web Farm/Web Garden 中的所有 AppDomain 有效。

Dependency on File System

带有文件依赖项的缓存

场景 2

假设我们有一些由整个应用程序频繁使用的母版数据。每次需要时都从数据库获取数据可能不是一个好方法。最好将其放入 Cache 中。还有一点,这个母版数据可以由管理员通过一个界面进行更新。

方法

我认为这是一个非常基本的需求,也是使用 Cache 的最佳候选。数据几乎是静态的,并且更新频率非常低。有一些母版数据,我们可以在第一次缓存中没有数据时加载它们。有一个管理员界面可以单独输入母版数据并更新数据库。此时,需要更新所有 Web 服务器上所有 AppDomain 的缓存。在 Web Farm 场景下,您的数据来自数据库,您可以设置数据库依赖项,以便一旦数据库中的数据更新,所有 Web 服务器上的缓存就会失效,并从数据库重新加载更新后的数据。这是一个常见场景,您无需担心数据同步。这是示意图。

dbdependency.PNG

带有数据库依赖项的缓存

场景 3

这是一个常见场景:我们将一些数据存储在服务器的 Cache 中,并且它可以随时更新。如何在 Web Farm 或 Web Garden 场景下处理这种情况?

方法 1

一旦任何一个缓存中的数据更新,它将调用 Web Service 调用到所有 Web 服务器,这些调用将更新负载均衡器后面的所有相关 Web 服务器中的缓存。因此,在这里我们可以有一个数据库表,其中包含 Web Farm 中连接的 Web 服务器的 IP(IP 将是 Web 服务器的直接 IP,而不是负载均衡器的虚拟 IP)。让我们分步来看。

  • 数据库中将有一个表,其中包含负载均衡器下所有 Web 服务器的 IP。
  • 将有一个 Web Service,它将获取所有 Web 服务器的 IP 并更新缓存。
  • Web Service 将被负载均衡器后面的任何一台 Web 服务器调用,在该服务器上缓存将被更新。

为满足新需求添加新的 Web 服务器到负载均衡器下也是一个好主意。只需向表中添加所有 Web 服务器的 IP。

Cache handling with web service approach

Web Farm 场景下使用 Web Service 方法处理缓存

方法 2

在这种情况下,您的缓存不在 Web 服务器上,而可以将其存储在其他服务器上。每个 Web 服务器都将连接到这台机器以获取缓存数据。您可能会问,如果缓存存储在另一台机器上,性能成本是多少?我建议您建立一个 Remoting (TCP) 连接到该缓存服务器,从那里获取数据会非常快,以至于与将数据保存在同一 Web 服务器内存中或缓存服务器中的性能差异不大。

Remoting Approach

Web Farm 场景下使用 Remoting 方法处理缓存

方法 3

这非常简单,但会花钱。有大量的第三方工具可用于处理 Web Farm 或 Web Garden 场景下的缓存问题。您可以通过 Google 找到它们。

反馈与建议

反馈对任何作者都非常重要。我请求大家分享您的反馈并给我建议,这将鼓励我并帮助我写更多文章。

© . All rights reserved.