限制并发还是不限制并发?(在单个ASP.NET请求中)

8

有很多方法可以限制异步I/O操作和/或它们的继续执行,比如使用自定义调度程序、SemaphorSlim等。我的问题是:在标准的ASP.NET MVC/WebAPI场景中这样做是否有意义

我们有一个典型的企业API,作为面向客户的SPA的后端。许多API请求涉及调用许多下游Web服务,我们现在大多数情况下都已经转换为使用TAP(async/await)进行异步I/O。其中许多远程服务调用是并行启动的,没有等待,然后使用Task.WhenAll批量等待。有时候,WhenAll是在固定数量的任务上完成的,有时候我们会针对集合中的每个项目启动一个远程调用——这会导致产生未知(但通常较少,少于十个)数量的任务,然后使用WhenAll等待它们。

据我理解,这会导致这些任务的连续性(即反序列化其响应的逻辑)在线程池上计划。这引出了我的问题:在并行运行这些CPU密集型连续性时,是否会对线程池施加过多压力?我们是否应该开发某种中间件,通过将它们调度到自定义调度程序来限制单个请求内启动的异步I/O任务的连续性并发性?

这样做是否可以通过减少任何给定请求分配的ThreadPool线程数量来提高应用程序的可扩展性,从而在我们开始耗尽ThreadPool线程(或被ThreadPool增长限制)之前,允许更多的并发请求得到服务?

还是说这样做没有什么用,我们应该信任默认的ThreadScheduler+ThreadPool将所有任务安排到可用的CPU核心上,并跨越任意数量的并发请求?

供大家参考:

这是一个非常成熟的系统,在一家大型公司中得到了数十位专家(包括我自己)的深入审查,已在一个美国州投入生产,并即将进入全国范围的生产。像“先测量”,“了解您是IO还是CPU限制”,“尝试AppInsights”和“不要试图比微软更聪明”等建议是我们自己显然已经考虑过的第一步。我们正在寻求的指导水平更像是:这里是否有人在美国全国范围内实施了全异步ASP.NET Web API系统,并具有异步/WhenAll并发的实际经验?

2
很难以一般化的方式回答。最好的方法是运行异步的最大IO绑定(或非CPU绑定)操作和最小的CPU上下文(线程)切换,这样可以最大化所有处理器(不仅仅是CPU)的使用率。在尝试变得“过于聪明”之前,您应该先测量您已经拥有的东西。此外,绝对性能不存在。如果您使用默认(体面)机制达到了目标,为什么要冒任何风险,我个人认为? - Simon Mourier
这不需要你使用类似GraphQL服务器的东西吗? - Tarun Lalwani
@tarunlalwani 我不太清楚它们之间的联系。我们只是在进行大量的下游Web服务调用,其中许多是并行的。GraphQL能帮上忙吗? - Andriy Volkov
1
是的,它可以帮助你。简化你的.NET代码,你应该一定要探索它。此外,在你当前的设置中,你应该写下所有的用例,并找出你想要优先处理的调用。另外,当你说你在循环中获取项目时,你应该始终限制并行调用的数量。否则,一个重要的记录可能会降低服务器上其他调用的性能。这方面没有基于#的答案,你需要设定限制、压力测试系统并进行微调。但是肯定不要无限制地并行运行所有内容。 - Tarun Lalwani
我认为编写限制并发的代码会在CPU上引入更多的性能开销,以实现任何好处。.NET已经有了良好的机制。但是用自定义机制替换它将耗费时间,并且测试也将是另一个噩梦。相反,您可以引入一些中间件,并带有某种缓存来减少对远程或数据库服务器的调用次数。缓存比限制并发更有效。尝试使用Microsoft Application Insights来监视依赖项调用,它会告诉您哪些调用可以进行缓存以改进性能。 - Akash Kava
显示剩余3条评论
1个回答

6

@tarun-lalwani在评论中提出了一些很好的观点。

但是我想强调的是,永远不要进行过度优化。今天的中档台式机可以轻松处理16个线程池(通常可以处理数百个等待任务),良好的服务器可以处理比这更大的线程池,你的时间成本与替换或新服务器的成本相比如何,可能少于6个月,很可能少于3个月。

任何性能问题都归结为瓶颈,系统只能以最慢的瓶颈速度运行。因此,在实际系统中改进这些特定的瓶颈是如何提高性能的。如何扩展这些瓶颈组是如何提高可扩展性的。台式机和服务器硬件之间仍然存在许多差异,因此我再次强调,在将几周/几个月的精力投入到修复可能不存在的“问题”之前,您需要查看这些事物的真实世界而不是体外指标。

如上所述,GraphQL允许您重新排列瓶颈发生的位置,使您能够更均匀地分配它们,以更好地利用您已经拥有的硬件。这也适用于许多现代设计模式。

总之,只有当某个过程成为问题时才限制它才有意义。


谢谢,我们是一家大公司,已经考虑过所有这些基本事项。话虽如此,还是感谢您的回答。“早起的鸟儿有虫吃” :) - Andriy Volkov
1
谢谢。我刚看到你的更新。我认为你只需要使用JMeter或类似工具来模拟预期的流量,并在perfmon中监视CPU队列,看看会发生什么。这也很大程度上取决于您想要什么样的SLA,您是想确保99%的请求(其中有合理数量的任务)比有大量任务的1%更快地返回,还是将它们全部视为相同的,当发生那1%时可能会减慢其他请求。如果前者是所需的,我建议尝试编写限制中间件并进行测试,以确保它不会使其他任何事情变得更糟。 - Thymine

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