编排Windows Azure Web角色以应对偶尔的高工作负载

时间:2012-10-15 08:17:19

标签: multithreading azure load-balancing

我正在运行一个Windows Azure Web角色,在大多数情况下,它会收到非常低的流量,但是有一些(可预见的)事件会导致必须完成的大量后台工作。后台工作包括许多数据库调用(Azure SQL)和对外部Web服务的HTTP调用,因此它不是CPU密集型的,但它需要大量等待数据库或Web服务回答的线程。后台工作由对Web角色的正常HTTP请求触发。

我看到两个选项来协调这个,我不确定哪一个更好。

  • 选项1,线程:当后台工作请求进入时,Web角色会根据需要启动尽可能多的线程(或将各个工作项排入队列)。在此选项中,我将在繁重的工作负载期间配置更大的实例,因为这些线程可能需要大量内存。
  • 选项2,自我调用:当后台工作请求进入时,接收它的Web角色会为每个后台工作项生成一个HTTP请求。在此选项中,我可以配置多个Web角色实例,因为Windows Azure的负载平衡器可以跨实例平衡HTTP请求。

选项1稍微简单一点,但它的缺点是只有一个实例可以处理后台工作。如果我想要多个Azure实例参与后台工作,除了从角色向自身发送HTTP请求之外,我没有看到任何其他选项,因此负载均衡器可以将一些工作委托给其他实例。 / p>

也许还有其他选择?

编辑:关于选项2的更多想法:当后台工作请求进入时,接收它的实例将保存要在某种队列中完成的工作(Windows Azure队列或某些作为任务队列的SQL表)。然后,它会为自己生成大量HTTP请求,以便负载均衡器“激活”所有角色实例。然后,每个实例从队列中将任务从队列中出列并执行任务,然后获取下一个任务等,直到完成所有任务。这就像偶尔使用Web角色作为工作者角色

我知道这种方法有空气(滥用Web角色作为工作者角色,对同一Web角色的HTTP请求),但我没有看到真正的缺点。

编辑2:我看到我应该详细说明该应用的具体情况:

该应用程序需要始终执行一些小任务。这些任务通常不会超过1-10秒,并且它们不需要大量的CPU工作。在正常的日子里,我们只有50-100个任务要完成,但在“特殊日子”(新年就是其中之一),他们可以进入几个10'000任务,这些任务必须在1-2内完成小时窗口。这些任务是在Web角色中完成的,我们有一个 Cron作业,可以每分钟启动任务。因此,Web角色每分钟都会收到处理新任务的请求,因此会检查哪些任务必须处理,将它们添加到某种队列中(目前它是带有OUTPUT INSERTED的UPDATE的SQL表,但我们打算切换到某天的Azure队列)。目前,同一个实例在排队后立即处理任务,但这不会扩展,因为几个10'000任务的串行处理需要太长时间。这就是为什么我们正在寻找一种机制来向最初的实例广播事件“任务可用”。

4 个答案:

答案 0 :(得分:3)

您是否考虑过使用队列进行工作分配?您可以将需要处理的“任务”放入队列中,然后将工作分发给许多工作进程。

我在方法1中看到的问题是我将其视为“向上扩展”模式,而不是“向外扩展”模式。通过部署许多小型VM实例而不是一个大型实例,将为您提供更多可扩展性+可用性恕我直言。此外,您提到您的工作不是CPU密集型的。如果考虑X-Small实例,对于1个小实例(每小时0.12美元)的成本,您可以部署6个X-Small实例(每小时0.02美元),同样可以部署1个大型实例(0.48美元)的部署成本24 X-Small实例。

此外,只要添加或删除实例,就可以轻松扩展“向外扩展”模式。如果您在更改VM大小时出现“向上扩展”(或“向下缩放”)模式,则最终会重新部署该程序包。

对不起,如果我有点切局:)希望这有帮助。

答案 1 :(得分:2)

[作为单独的答案添加以避免SO告诉我切换到聊天模式+绕过评论长度限制]&大声思考:)

我明白你的观点。基本上通过HTTP请求,您可以广播要处理到其他实例的新任务的可用性。

因此,如果我理解正确,当一个实例收到要处理的任务的请求时,它会将该请求推送到某种队列中(就像你提到的那样,它可能是Windows Azure Queues [我个人真的更喜欢]或者SQL Azure数据库[不喜欢这样,因为您必须实现自己的消息锁定算法])然后向所有需要完成某些工作的实例广播消息。剩下的实例(或者可能是正在广播它的实例)可以看看他们是否可以自由地处理该任务。然后,根据其可用性,一个实例可以从队列中获取任务并开始处理该任务。

假设您使用了Windows Azure队列,当实例获取邮件时,它会在一段时间内(Azure队列的可见性超时时间)立即对其他实例不可用,从而避免重复处理任务。如果成功处理任务,则处理该任务的实例可以删除该消息。

如果由于某种原因,未处理任务,则在可见性超时期限到期后,它将自动重新出现在队列中。然而,这导致另一个问题。由于您的实例基于触发器(生成HTTP请求)而不是轮询来查找任务,您将如何确保完成所有任务?假设您只处理一个任务和一个任务,并且由于您没有收到处理第二个任务的请求而失败,则第一个任务将永远不会再次处理。显然,在实际情况下不会发生这种情况,而是你可能想要考虑的事情。

这有意义吗?

答案 2 :(得分:2)

我同意Gaurav和其他人考虑使用Azure Queue选项之一。这实际上是一种方便的模式,可以清晰地分离问题,同时平滑负载。

这个基本的以队列为中心的工作流(QCW)模式在处理Web角色的HTTP请求(触发工作的机制,显然是通过调用wget的cron作业完成)时将工作请求置于队列中。然后,Web角色中的IIS Web服务器继续执行它最擅长的操作:处理HTTP请求。它不需要负载均衡器的任何支持。

Web角色需要尽快接受请求(然后为每个请求排队),但出列部分是 pull ,因此可以轻松调整负载以获取可用容量(或容量调整为负载!这是云!)。您可以选择一次处理一个,一次处理两个,或者一次处理N个:无论您的测试(调整练习)告诉您哪个适合您部署的VM大小。

您可能也知道,Web角色上的RoleEntryPoint :: Run方法也可以实现,以便不断地工作。 Web角色的默认实现基本上只是永远睡眠,但您可以实现一个无限循环来查询队列以删除工作并对其进行处理(并且在队列中没有消息可用时不要忘记睡眠!未能这样做会导致金钱泄漏,并可能让你受到限制)。正如Gaurav所提到的,在强有力地实现这个QCW模式时还有一些其他的考虑因素(如果我的节点出现故障,或者有一个坏的(“毒药”)消息,我的代码中的错误等等会发生什么),但是你的用例没有似乎过于担心这个问题,因为cron工作的下一次启动显然会解释基础设施中的任何(罕见的,但可能的)故障,并且可能假设没有致命的错误(因此你不会被毒药消息困住)等等。 / p>

将队列中的项目与队列中的处理项目分离实际上是一个逻辑设计点。我的意思是你可以随时更改它,并将处理方(从队列拉出的代码)移动到另一个应用程序层(服务层),而不会破坏基本设计的任何部分。这提供了很大的灵活性。您甚至可以在单个Web角色节点上运行所有内容(如果您需要SLA,则可以运行两个 - 不确定是否基于某些注释执行)大多数情况下(两层),然后根据需要通过添加来运行三层一堆处理虚拟机,例如新年。

还可以根据来自环境的信号动态调整处理节点的数量 - 例如,如果队列长度增长或超过某个阈值,则添加更多处理节点。这就是云,这种机器可以完全自动化。

现在变得更加投机,因为我对你的应用并不是很了解......

通过使用前面提到的Run方法,您也可以消除cron作业,并在无限循环中执行该操作;这当然取决于cron调度的复杂性。或者您甚至可以通过让您的cron作业直接将工作请求项放在队列上(可能使用one of the SDKs)来消除整个Web层(Web角色)。您仍然需要代码来处理请求,这当然仍然是您的Web角色,但此时可以轻松使用工作者角色。

答案 3 :(得分:1)

我肯定会采用横向扩展解决方案:更简单,更易于管理和更好的定价。此外,如果部署失败,您的停机风险也会降低(当然,故障和升级域的机制应该涵盖这一点,但仍然如此)。所以就此而言,我完全支持Gaurav!