8

我知道我们可以使被动服务Network Load Balancing高度可用。但是活跃的应用程序呢?Failover Clustering

示例:我的一个应用程序以固定的时间间隔从外部资源中检索一些内容。我想象过以下场景:

  1. 在一台机器上运行它。问题:如果这个实例下降,内容将不会被检索
  2. 在集群的每台机器上运行它。问题:内容将被多次检索
  3. 在集群的每台机器上都有它,但只在其中一台机器上运行它。每个实例都必须检查某种公共资源来决定是否轮到它来执行任务。

当我考虑解决方案#3 时,我想知道什么应该是公共资源。我曾想过在数据库中创建一个表,我们可以使用它来获取全局锁。

这是最好的解决方案吗?人们通常如何做到这一点?

顺便说一句,它是在 Windows Server 2008 上运行的 C# .NET WCF 应用程序

4

6 回答 6

4

对于此类问题,他们发明了消息队列。想象一下,当您的集群应用程序都侦听消息队列(集群自身:-))时的情况。在某个时间点,一个实例会收到您的初始命令来下载您的外部资源。如果成功,您的实例会刷新消息,而是发布另一条消息,以便稍后执行时间等于“运行时间”+“间隔”。但万一实例在处理过程中死亡,这不是问题。消息在队列中回滚(超时后),其他实例可以拾取它。一点事务,一点消息队列

我在世界的 Java EE 方面,因此可以帮助您了解编码细节

于 2010-04-20T00:54:09.597 回答
1

我曾经使用您的解决方案#3 实现了类似的东西。

创建一个名为 的表,其中包含一个包含锁定键resource_lock的列(例如)。locking_key

然后在每个时间间隔,您的应用程序的所有实例都将:

  1. 运行类似“ update resource_lock set resource_key = 1 where resource_key is null”的查询。(您当然也可以插入服务器特定的 id、时间戳等)
  2. 如果更新了 0 行:什么都不做 - 另一个应用程序实例已经在获取资源。
  3. 如果更新了 1 行:获取资源并设置locking_keynull.

这样做有两个好处:

  • 如果您的其中一台服务器发生故障,则仍在运行的服务器仍将获取该资源。
  • 您将锁定留给数据库,这样可以避免您自己实现它。
于 2010-04-23T07:34:26.020 回答
1

从简单的角度来看,完成您正在寻找的最快/最简单的方法是“循环”您的集群,以便为每个请求选择一台机器(通过集群管理服务等)处理请求。实际的客户端请求不会直接发送到处理它的机器;相反,它们指向单个端点,该端点充当代理,根据可用性和负载将传入请求分发到机器。要引用以下引用的链接,

网络负载平衡是一种配置机器池的方法,以便它们轮流响应请求。它最常见于服务器群中实现:配置相同的机器,为网站分散负载,或者可能是终端服务器群。您也可以将它用于防火墙 (ISA) 场、vpn 接入点,实际上,任何时候您的 TCP/IP 流量对于单台机器来说已经成为过多负载,但您仍然希望它显示为单台机器访问目的。

至于您的应用程序处于“主动”状态,该要求不会影响此等式,因为无论是“主动”还是“被动”,应用程序仍会向您的服务器发出请求。

商业负载平衡器用于服务 HTTP 样式的请求,因此可能值得研究,但使用 W2k8 的负载平衡功能,您可能最好利用这些功能。

有关如何在 Win2k8 中配置的更多信息,请参阅本文

本文技术性更强,重点介绍将 NLB 与 Exchange 结合使用,但这些原则仍应适用于您的情况。

有关 NLB 设置和配置的另一个详细演练,请参见此处

如果做不到这一点,您可能会通过在 ServerFault 上搜索/发布得到很好的服务,因为您的应用程序代码没有(也不应该)严格意识到 NLB 甚至存在。

编辑:添加了另一个链接。

编辑(第 2 次): OP 纠正了我在“主动”与“被动”概念中的错误结论。我对此的回答与我最初的回答非常相似,除了“活动”服务(由于您使用的是 WCF,很容易成为 Windows 服务)可以分为两部分:实际处理部分和管理部分。管理部分将在单个服务器上运行,并充当其他服务器执行实际处理的循环负载平衡器。它比原始场景稍微复杂一些,但我相信它会提供很大的灵活性,并在处理和管理逻辑之间提供清晰的分离。

于 2010-04-23T16:34:23.760 回答
1

有一些您可能知道但未在问题中描述的要求使得给出明智的答案具有挑战性。其中一些问题是:

  • 任务必须成功完成吗?
  • 如果任务成功/未成功完成,“谁”需要知道以及需要执行什么类型的操作?
  • 如果再次运行任务时任务还没有完成,会有什么行为?它应该运行还是不运行?
  • 作业以指定的时间间隔运行有多重要?如果间隔是每 5 分钟一次,是否必须每 5 分钟一次,或者任务是否可以在 5 分 10 秒后运行?

第一步是回答如何安排定期任务运行。一个选项是 Windows 计划任务,但它本质上不是高度可用的,但可能可以解决这个问题。如果您使用的是 SQL Server,另一种选择是使用 SQL Server 代理作为调度程序,因为它将作为 SQL Server 的一部分进行故障转移。

下一步要确定的是如何调用 WCF 应用程序。最简单的选项是触发作业以通过 NLB IP 地址调用 WCF 服务。如果数据库服务器(或该区域中的其他服务器)正在调用应用程序区域(当然,总是有例外,例如 MSDTC),这可能被认为是禁止的。

另一种选择是使用队列模型。在大多数情况下,这将是最可靠的。例如,SQL Server 代理可以执行存储过程以在队列表中输入记录。然后在每个应用程序服务器上,服务可以轮询以查找要处理的排队记录。对队列中记录的访问将由数据库序列化,以便第一个服务器运行该作业(并且该作业只会运行一次)。

根据此答案中开放问题的答案,您可能需要添加更多错误处理。如果外部资源的检索通常很短,您可能希望简单地使用 a 锁定队列记录,select for update并在任务完成时更新状态(或者如果您愿意,可以删除记录)。这将阻止其他服务实例在另一台服务器上处理记录时处理该记录,如果在处理期间发生崩溃,则应回滚事务,并且集群中的另一个服务可以获取该记录。(不过,您可以将事务超时增加到您认为需要的时间。)

如果长时间保持数据库锁定不可行,那么您可以更改逻辑并为服务添加一些监控。现在,当一个作业开始处理时,它的状态将从排队变为运行,并且正在处理记录的服务器将在记录上更新。可以创建某种服务状态表,每个服务实例每次轮询时都会更新当前时间。这将允许集群中的其他服务重新处理显示为正在运行但它们应该在其上运行的服务在一定时间内没有“签入”的作业。

这种方法也有局限性:如果任务确实完成但不知何故数据库连接丢失了怎么办——该作业可能会再次运行。当然,我不认为将原子数据库操作与其他非事务性资源(例如 Web 请求、文件系统)结合起来的问题会很容易解决。我假设您正在编写文件或其他东西——如果外部内容也被放入数据库中,那么单个事务将保证一切都是一致的。

于 2010-04-26T05:53:13.427 回答
0

在某些情况下,人们发现让 3 台机器处理所有请求很有用,然后在最后比较结果,以确保结果绝对正确,并且在处理它时没有硬件故障导致任何问题。这就是他们在飞机上所做的事情。

在其他时候,你可以忍受一个糟糕的结果和一个小的停机时间来切换到一个新的服务,但只希望下一个没问题。在这种情况下,带有心跳监视器的解决方案 3 是一个很好的设置。

其他时候,人们只需要通过 SMS 通知他们的服务已关闭,并且应用程序只会使用一些过时的数据,直到您手动执行某种故障转移。

在您的情况下,我会说后者可能对您更有用。由于您不能真正依赖另一端可用的服务,因此您仍然必须提出解决方案来解决这种情况。回馈过时的数据可能对您有好处,也可能不是。很抱歉不得不说:这取决于。

于 2010-04-22T09:34:18.410 回答
0

Zookeeper 是分布式锁的一个很好的用例。Zookeeper 有 z 节点,它们就像带有数据的目录。

甚至 netflix 策展人也有很多已经完成和使用的食谱。比如:领导选举,分布式锁等等。

我想我们有 Zookeeper 的 C# 客户端。您绝对应该尝试此选项。#选项3

于 2013-07-30T06:51:55.107 回答