在构建基于Web的应用程序时,状态服务器的稳定性至关重要。如果状态服务器发生故障,整个Web应用程序可能会受到影响。本文提出了一种故障转移解决方案,该方案能够在一个状态服务器发生故障时自动切换到另一个状态服务器,同时通过在可用状态服务器之间分配请求来实现负载均衡。
所提出的故障转移系统监控一组指定的状态服务器,以确定哪些服务器正在运行。然后,Web应用程序可以决定使用哪一个状态服务器。监控状态服务器的过程成本较高,因此由一个专门的外部服务来处理。当状态服务器上线或下线时,该服务会通知Web应用程序(以及其他Web应用程序)。
故障转移系统由两部分组成。
第一部分是监控服务,它通过不断地连接和断开连接来轮询给定列表中服务器的状态。如果服务器的可用性发生变化,例如,之前不可用的服务器变得可用,或者反之,则会更新一个或多个状态文件以反映变化。状态文件包含有关正在使用的状态服务器及其在线状态的信息。ASP.NET应用程序可以检测到这些状态文件的变化,并相应地做出反应。
监控服务有一个可配置的时间周期,在这段时间内,上线的监控服务器必须保持在线状态,服务才会更新状态文件以反映该服务器的状态变化。这有助于减少对连续上线和下线的服务器的连接——所谓的“抖动服务器”现象。这段时间的长度由ServerWarmUpTime配置设置确定。
值得注意的是,监控服务可以检测到其他类型的服务器的可用性,而不仅仅是ASP.NET状态服务器,因此也可以用于其他目的。
第二部分包括Web应用程序中的配置设置和代码,这些设置和代码扩展了Martin Bartimolew关于状态服务器分区和负载均衡的系列文章。Web应用程序配置为将配置文件扩展到外部状态文件。状态文件的更改会导致应用程序配置设置重新读取并更新为新值。因此,Web应用程序始终具有最新的服务器可用性信息,并使用这些信息将请求分配给可用的状态服务器——实现负载均衡和故障转移支持。
例如,如果使用五个状态服务器,并且它们都在运行,状态文件将指示这五个服务器可用;然后Web应用程序将状态服务器请求均匀地分配到这五个服务器上。如果两个状态服务器突然下线,状态文件将更新为只指示有三个状态服务器可用;然后Web应用程序将重新分配状态服务器请求,只分配给这三个服务器。总体效果是在状态服务器停机期间,用户能够继续使用应用程序。一些会话可能会丢失,但与整个应用程序长时间停机相比,这只是一个小问题。
要设置服务器监控服务,请按照以下步骤操作:
<Servers>
<!-- List of servers to poll -->
<add key="Server1" value="localhost:42424" />
<add key="Server2" value="appserver1:42424" />
<add key="Server3" value="72.27.255.9:42424" />
</Servers>
<StatusFilePaths>
<!-- List of file paths where status files are saved/updated -->
<add key="Web1" value="C:\Inetpub\wwwroot\MyWeb1\server_status.config.xml" />
<add key="Web2" value="C:\Inetpub\wwwroot\SuperWeb2\server_status.config.xml" />
</StatusFilePaths>
<configSections>
<section name="SessionStateServers" type="ServerListSectionHandler" restartOnExternalChanges="false" />
</configSections>
<SessionStateServers configSource="server_status.config.xml" />
<system.web>
<sessionState mode="StateServer" partitionResolverType="PartitionResolver" />
...
</system.web>
最初,希望监控服务更新一个单一的状态文件,多个Web应用程序可以共享。由于ASP.NET只与位于应用程序文件夹或其子文件夹中的外部配置文件一起工作,因此这个计划没有奏效。由于这个限制,不同的Web应用程序不能共享一个外部配置文件。
没有必要将web.config文件中的section元素的restartOnExternalChanges属性设置为true。将此属性设置为true会导致Web应用程序在外部config文件更新时重新启动,这将导致存储在Application对象中的任何数据丢失。
即使将属性值设置为false,Web应用程序也会读取外部config文件中的最新数据,而不会重新启动应用程序。