首页 > 解决方案 > 当 Azure 应用服务横向扩展我的 Web API 时,SemaphoreSlim 会保护代码不同时运行两次吗?

问题描述

我有一个在 Azure App Service 上运行的 ASP .Net Core 5 Web API。它包含一个每天运行一次的服务,大约在午夜。所以我有一个每小时运行一次的 System.Threading.Tasks.Timer。如果是在午夜和凌晨 1 点之间,它将启动服务。该服务大约需要一分钟才能完成,并且是一个执行一些数据库操作的循环。

前几天,由于某种原因,它运行了两次。因此,在它运行的同时,在它完成之前,它同时运行了第二个实例。

我不明白它为什么这样做。然后我记得我最近将 Azure 应用服务设置为在 CPU 或内存利用率增加到 70% 以上时横向扩展至 3 个实例。然后我想,这可能是它运行两次的原因吗?在运行时,CPU 或内存利用率超过了 70%,因此 Azure 应用服务创建了我的 Web API 的第二个实例,然后触发了计时器,它看到它是在午夜和凌晨 1 点之间,然后运行服务?

我想,好吧,我想这是可能的。因此,我认为该服务需要对此进行保护。它不应该允许它的两个实例同时运行(或者实际上,在任何给定的 24 小时内)。

起初我考虑使用 Lock/Monitor。但是我的服务是异步的,并且在一些地方使用了 await 关键字,因此不能与 Lock/Monitor 一起使用。所以我最终使用了 SemaphoreSlim。然而,根据我的研究,SemaphoreSlim 只能防止内部线程两次执行相同的代码。它不能防止外部线程(我相信 Semaphore 或 Mutex 的方式)。

因此,为了结束这篇相当长的文章,我想知道当 Azure App Service 增加我的 Web API 的实例数时,SemaphoreSlim 是否真的会保护我的服务不同时执行两次。由于它本质上是我的 API 运行的两个独立实例(据我所知),第二个实例是否会被视为外部线程,因此不受 SemaphoreSlim 监控?

谢谢

标签: asp.net-core.net-coreasp.net-core-webapimutexsemaphore

解决方案


SemaphoreSlim 不会保护您的过程免于跨服务的多个实例同时运行。SemaphoreSlim 确实会将您的代码锁定在应用程序的域中,但向外扩展会创建一个具有自己进程的 Web 应用程序的全新实例。

您可以通过创建分布式锁(可能通过数据库或缓存查找)来解决此问题,或者您可以重新设计您的应用程序,以通过单独的进程运行可能不会同时运行的代码。考虑它是否可以实现为Azure 函数,或标记为单例的webjob


推荐阅读