我知道,Network Load Balancing
和Failover Clustering
我们可以使被动服务高度可用。但是有效应用呢?
示例:我的一个应用程序以固定间隔从外部资源检索一些内容。我想象了以下场景:
当我考虑解决方案#3时,我想知道应该是什么共同资源。我曾想过在数据库中创建一个表,我们可以用它来获取全局锁。
这是最好的解决方案吗?人们通常如何做到这一点?
顺便说一句,它是在Windows Server 2008上运行的C#.NET WCF应用程序
答案 0 :(得分:4)
对于这些问题,他们发明了消息队列。想象一下,当您的群集应用程序都收听消息队列时(群集本身:-))。在某个时间点,一个实例会获取您下载外部资源的初始命令。如果成功,您的实例会刷新消息,而是发布另一个消息,以便稍后执行时间等于“运行时间”+“间隔”。但是如果实例在处理期间死亡,那不是问题。消息将在队列中回滚(超时后),其他一些实例可以将其拾取。一些事务,一些消息队列
我在世界的Java EE方面,所以可以帮助您编写详细信息
答案 1 :(得分:1)
我曾经使用你的解决方案#3实现了类似的东西。
创建一个名为resource_lock
的表格,其中包含一个包含锁定键的列(例如locking_key
)。
然后,在每个时间间隔,您的应用的所有实例都将:
update resource_lock set resource_key = 1 where resource_key is null
”之类的查询。 (当然,您也可以插入特定于服务器的ID,时间戳等)。locking_key
设置回null
。 这有两个好处:
答案 2 :(得分:1)
从简单的角度来看,实现您正在寻找的最快捷/最简单的方法是“循环”您的群集,以便为每个请求选择一台机器(通过群集管理服务或一些这样的)处理请求。实际的客户端请求不会直接进入处理它的机器;它们指向单个端点,该端点充当代理,根据可用性和负载将传入请求分发到计算机。引用以下引用的链接,
网络负载平衡是一种配置计算机池的方法,以便它们轮流响应请求。它最常见于服务器场中实现:配置相同的计算机,可以分散网站或终端服务器场的负载。您也可以将它用于防火墙(ISA)服务器场,vpn访问点,实际上,只要您的TCP / IP流量对于单个计算机而言负载过大,您仍然希望它显示为单个计算机访问目的。
至于您的应用程序处于“活动状态”,该要求不会影响此等式,因为无论是“活动”还是“被动”,应用程序仍会向您的服务器发出请求。
存在用于提供HTTP样式请求的商业负载均衡器,因此可能值得研究,但借助W2k8的负载均衡功能,您最好能够利用这些功能。
有关如何在Win2k8中配置该信息的详细信息,请参阅this文章。
this article更具技术性,专注于将NLB与Exchange一起使用,但原则仍应适用于您的情况。
see here进一步详细介绍了NLB的设置和配置。
如果不这样做,您可以通过在ServerFault上搜索/发布来获得良好的服务,因为您的应用程序代码不是(也不应该)严格意识到NLB甚至存在。
编辑:添加了另一个链接。
编辑(第二):OP已经纠正了我在“主动”与“被动”概念中的错误结论。我对此的回答与我原来的答案非常相似,除了“主动”服务(因为你使用的是WCF,很容易就是一个Windows服务)可以分成两部分:实际的处理部分和管理部分。管理部分将在单个服务器上运行,并作为执行实际处理的其他服务器的循环负载平衡器。它比原始场景稍微复杂一点,但我相信它会提供很大的灵活性,并在处理和管理逻辑之间提供清晰的分离。答案 3 :(得分:1)
您可能知道一些要求但未在问题中进行描述,这些要求使得明智的答案具有挑战性。其中一些问题是:
第一步是回答如何安排定期任务的运行。一个选项是Windows计划任务,但它本身并不具备高可用性,但可以解决这个问题。如果您使用的是SQL Server,另一种方法是使用SQL Server代理作为调度程序,因为它将作为SQL Server的一部分进行故障转移。
确定的下一步是如何调用WCF应用程序。最简单的选择是触发作业通过NLB IP地址调用WCF服务。如果数据库服务器(或该区域中的其他服务器)正在调用应用程序区域(当然总是存在诸如MSDTC之类的异常),则可以将其视为禁止。
另一种选择是使用队列模型。在大多数情况下,这将是最可靠的。例如SQL Server代理可以执行存储过程以在队列表中输入记录。然后在每个应用程序服务器上,服务可以轮询查找要处理的排队记录。对数据库中的记录的访问将由数据库序列化,以便第一个服务器将运行该作业(该作业将只运行一次)。
根据本答案中对开场问题的回答,您可能需要添加更多错误处理。如果外部资源的检索通常很短,您可能希望简单地使用select for update
锁定队列记录,并在任务完成时更新状态(或者如果您愿意,则删除记录)。这将阻止其他服务实例在另一台服务器上处理记录时处理记录,如果在处理过程中发生崩溃,则应回滚事务,并且群集中的另一个服务可以获取记录。 (尽管如此,只要您认为需要,就可以将事务超时增加。)
如果长时间保持数据库锁定不可行,那么您可以更改逻辑并向服务添加一些监视。现在,当作业开始处理时,其状态将从排队更改为正在运行,并且正在处理该记录的服务器将在记录上更新。可以创建某种服务状态表,每个服务实例每次轮询时都会更新当前时间。这将允许群集中的其他服务重新处理显示为正在运行的作业,但是他们应该运行的服务在一段时间内没有“签入”。
这种方法也有局限性:如果任务实际完成但数据库连接丢失,那么该工作可能会再次运行。当然,我不认为将原子数据库动作与其他非事务性资源(例如Web请求,文件系统)结合起来的问题很容易解决。我假设您正在编写文件或其他内容 - 如果外部内容也放入数据库中,那么单个事务将保证一切都是一致的。
答案 4 :(得分:0)
在某些情况下,人们发现让3台机器完成所有请求是有用的,然后在最后比较结果,以确保结果绝对正确,并且在处理时没有硬件故障导致任何问题。这就是他们在飞机上所做的事情。
在其他时候,你可以忍受一个不好的结果和一个小的停机时间来切换到一个新的服务,但只是希望下一个服务没问题。在这种情况下,带有心跳监测器的3号解决方案是一个很好的设置。
其他时候,人们只需要通过短信通知他们的服务已关闭,应用程序将只使用一些过时的数据,直到您手动执行某种故障转移。
在你的情况下,我会说后者可能对你更有用。由于您无法真正依赖可用的另一端服务,因此您仍然需要提供一个解决方案,以便在这种情况下执行操作。回馈过时的数据可能对您有利,也可能不是。很抱歉不得不说:这取决于。
答案 5 :(得分:0)
Zookeeper是分布式锁的一个很好的用例。 Zookeeper有z节点,就像数据目录一样。
即使是netflix策展人已经完成并使用了很多食谱。喜欢:领导者选举,分布式锁定等等。
我认为我们有C#的zookeeper客户端。你一定要尝试这个选项。 #2选项