代码之家  ›  专栏  ›  技术社区  ›  Jader Dias

如何使主动服务高度可用?

  •  6
  • Jader Dias  · 技术社区  · 16 年前

    我知道这一点 Network Load Balancing Failover Clustering 我们可以做 被动服务 高可用性。但是呢 活动应用程序 ?

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

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

    当我在思考解决方案时,我一直在想,什么才是共同的资源。我考虑过在数据库中创建一个表,我们可以用它来获取全局锁。

    这是最好的解决办法吗?人们通常是怎么做的?

    顺便说一下,它是一个运行在WindowsServer2008上的C.NETWCF应用程序

    6 回复  |  直到 12 年前
        1
  •  4
  •   Arjan Tijms Mike Van    13 年前

    对于这样的问题,他们发明了消息队列。想象一下当集群应用程序都监听消息队列(集群本身:-)时的情况。在某个时间点,一个实例获得下载外部资源的初始命令。如果成功,则实例刷新消息,并在稍后的执行时间(等于“运行时”+“间隔”)中发布另一条消息。但如果实例在处理过程中死亡,那就不是问题了。消息在队列中回滚(超时后),其他一些实例可以接收它。一点事务,一点消息队列

    我在世界的爪哇EE方面,所以可以帮助您编码细节

        2
  •  1
  •   Eric Eijkelenboom    16 年前

    我曾经用你的解决方案3实现过类似的东西。

    创建一个名为 resource_lock ,带有一个列(例如 locking_key )里面有一把锁钥匙。

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

    1. 运行类似的查询' update resource_lock set resource_key = 1 where resource_key is null '.(当然,您也可以插入特定于服务器的id、时间戳等。)
    2. 如果更新了0行:不执行任何操作-另一个应用实例已在获取资源。
    3. 如果更新了一行:获取资源并设置 锁定键 回到 null .

    这样做有两个好处:

    • 如果其中一台服务器出现故障,资源仍将由仍在运行的服务器获取。
    • 把锁留给数据库,这样就避免了自己实现它。
        3
  •  1
  •   Randy Levy    16 年前

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

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

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

    下一步要确定的是如何调用wcf应用程序。最简单的选择是触发作业,通过nlb ip地址调用wcf服务。如果数据库服务器(或该区域中的其他服务器)正在调用应用程序区域(当然,总会有诸如msdtc之类的异常),则可以认为这是no no。

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

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

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

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

        4
  •  1
  •   Josh E    16 年前

    从简单的角度来看,最快/最简单的方法是“循环”集群,以便为每个请求选择一台机器(由集群管理服务或其他类似服务)来处理请求。实际的客户机请求不会直接转到处理它的计算机;而是指向一个端点,该端点充当代理,根据可用性和负载将传入的请求分发给计算机。引用下面引用的链接,

    网络负载平衡是一种配置计算机池的方法,以便它们轮流响应请求。它最常见的实现方式是在服务器场中:配置相同的机器来分散web站点的负载,或者可能是终端服务器场。您也可以将它用于防火墙(isa)场、vpn访问点,实际上,任何时候,如果您的tcp/ip通信量对于一台计算机来说太大,但您仍然希望它作为一台计算机显示以供访问。

    至于您的应用程序是“主动”的,这个要求不包括在这个等式中,因为无论是“主动”还是“被动”,应用程序仍然向您的服务器发出请求。

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

    有关如何在Win2K8中配置它的详细信息,请参阅 this 文章。

    this article 更具技术性,并专注于将nlb与exchange结合使用,但原则仍应适用于您的情况。

    see here 对于NLB设置和配置的另一个详细介绍。

    如果失败,您可以通过在serverfault上搜索/发布得到很好的服务,因为您的应用程序代码没有(也不应该)严格意识到nlb甚至存在。

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

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

        5
  •  0
  •   Cine    16 年前

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

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

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

    就你而言,我认为后者对你可能更有用。既然您不能真正依赖另一端的服务,那么在这种情况下,您仍然需要想出一个解决方案。归还过时的数据可能对你有好处,但可能不是。很抱歉不得不说:这要看情况而定。

        6
  •  0
  •   kaustubh    12 年前

    zookeeper是分布式锁的一个很好的用例。ZooKeeper有z节点,它们类似于包含数据的目录。

    即使是netflix的馆长也已经做了很多菜谱并在使用。比如:领导人选举,分配锁等等。

    我想我们的客户是C的动物园管理员。你一定要试试这个选择。第三选择

    推荐文章