我们应该使用Windows服务还是线程池?

4
我们正在开发一个Asp.Net MVC 4的Web应用程序,旨在为数百个用户服务。
我们需要有一个后台服务来处理几分钟内的每个用户。
我们不确定是否使用Windows服务(多个Windows服务)还是使用进程池。我们考虑使用Windows服务,因为它们可以通过Windows服务器轻松维护,并且可以节省编写UI和管理线程的开销。它也可以轻松地在一段时间间隔内运行。
一个Windows服务是否可以自动为刚注册的新用户启动一个新实例(因此我们拥有多个后台Windows服务实例,每个用户一个)?如果不能,则选项“Windows服务”将无效。
如果上述情况可行,我们应该选择“Windows服务”方法还是制作我们自己的托管“进程池”?

2
“线程池的进程”并没有什么实际意义。您能澄清一下吗? - Daniel Kelley
@YuvalItzchakov 很有趣,你首先问为什么每个用户需要自己的服务(因为不清楚),然后声称这是一个没有理由的重大开销,但他甚至还没有告诉你原因 ;) - DGibbs
@YuvalItzchakov - 每个客户都有自己的数据库,我们的支持团队需要对每个客户拥有控制权。这样我们就可以停止它特定的后台服务或其他操作。 - ilans
1
@DGibbs 你让我笑了 :) - ilans
嗯,你说得对。我应该用“似乎”而不是“是”:)不管怎样,你们预计会有多少客户? - Yuval Itzchakov
显示剩余3条评论
3个回答

3
当然,为每个用户启动一个进程会导致高内存开销和不可扩展性,当你进入1000的时候。我不知道启动进程(而不是线程)可能节省什么,因为新进程将包含至少一个线程。此外,Windows服务与“已登录用户”无关。它们不适用于多实例。
请注意,您似乎想在ASP.NET MVC中运行后台工作。要知道,这很困难。在这里使用一个Windows服务可能是有意义的。
后台工作的难点在于工作进程可能因许多原因退出。你必须容忍这种情况。服务也有同样的问题:你需要部署新版本并定期重新启动服务器。你还需要一种HA策略,所以你需要多个服务器。
即使对于长时间运行的后台工作,我也不确定Windows服务会是更好的选择。
如果有数百个并发的后台工作者,你应该使用异步IO,以免有数百个专用线程。
我假设你的后台工作大部分时间都在等待。您可以使用计时器使等待变为异步,而将所有其他操作变为同步。这样可以给您带来简单的实现和大量的内存节省。

当你说“为每个用户启动一个进程可以保证高内存开销”时,你指的是特定于Windows服务的“进程”,对吗?另外,您能否详细说明如何使用等待异步?您所说的“其余所有内容都是同步的”是什么意思?非常感谢。 - ilans
这适用于任何进程。服务启动新进程(和CLR!)时没有太多额外的开销。 - usr

0
我们编写了一个开源项目Revalee,用于处理这种类型的工作负载。它使用Windows服务来管理任务调度,但利用现有的ASP.NET MVC应用程序来处理异步操作。任务数量可以达到数十万,并且会一直保留,直到成功分派。
以下是一个简单的工作流程图:
user initiated action
        |
        |           ......................
        |           :  future callback   :
        V           V                    :
======================       ===========================
|   Your web app     |       | Revalee Windows Service |
|                    |       |                         |
======================       ===========================
        |                                ^
        |    registers a callback now    |
        |________________________________|

0

使用单独的服务执行后台任务可能会增加额外的负担:

  1. 拥有两个独立的应用程序肯定会增加项目的复杂性:如果您需要在Web应用程序和服务之间进行任何通信,它将比将整个内容放在Web应用程序中更加复杂(并且更慢)。您还需要部署两个独立的项目,因此会有一些管道开销,这样会使开销加倍。

  2. 从性能方面来看,这种方法没有任何好处。相反,在Web应用程序内部拥有自己的托管池将允许更好地调度这些线程,并且很可能允许您比简单地让Windows处理更有效地运行它们。您真的不想在同一台机器上同时生成数百个进程(或线程),它们将竞争资源。

  3. 如果没有其他选择,将整个功能保留在Web应用程序中可能会简化您的托管选项。安装和管理Windows服务可能需要比便宜的托管提供商准备给您的权限更多。

话虽如此,在ASP.NET中运行后台任务意味着您需要准备好随时面对线程被异常、回收或IIS可以想到的任何其他原因突然中止的情况。在单独的进程中运行这些后台任务肯定会更不容易受到这些ASP.NET怪癖的影响,因此最终归结为一个折衷:确保这些任务永远不会被中断对您有多重要,以及是否值得额外的编程和维护工作。

[编辑]

如果您关心的是如何在服务内安排这些任务,请查看一些针对.NET的调度库,例如Quartz。它允许更好地控制调度,而不仅仅是使用计时器,并且(如果您需要)提供一些高级功能,如持久化作业(如果您希望确保作业在重新启动后完成)和大规模应用程序的集群。

使用简单的计时器将起作用,但请确保您了解每个.NET计时器如何分派其事件。


谢谢@Groo。我想我会选择一个管理线程的Windows服务。我应该在Windows服务中使用线程池还是手动启动线程?至于你提到的“数百个数据库连接”,我有什么选择?请考虑每个客户都有自己的数据库...但你知道吗,这将是一个问题,因为我需要我们的支持团队能够停止/启动特定客户的后台任务。 - ilans
如果你在谈论.NET的ThreadPool和创建一个新的Thread,那么通常取决于你的任务持续时间。CLR的ThreadPoolTask默认也使用它)适用于短期工作,因为它被整个运行时使用。另一方面,你可能正在谈论自己的托管线程池,这也是有意义的。这全部取决于这些任务的性质。它们是否很快完成?在这种情况下,使用ThreadPoolTask,因为它们已经被优化以减少争用。 - vgru
不行。这些服务需要一直工作。它们是实时的 XML 服务,一直在客户数据库上运行。 - ilans
我决定采用这个:https://dev59.com/713Va4cB1Zd3GeqPFfz8?rq=1 - ilans
可能会使用WCF,但您应该提出一个新问题(或者简单地搜索StackOverflow以寻找类似的问题,因为您的问题很可能会被关闭为重复)。 - vgru
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接