我们在带有 SQL Server 2016 的 ASP.NET Web 项目中使用 Hangfire 1.7.2。我们的服务器上有大约 150 个站点,每个站点都使用 Hangfire 1.7.2。我们注意到,当我们将这些站点升级为使用 Hangfire 时,数据库服务器崩溃了。检查数据库日志,我们发现有多个锁定查询。我们在所有阻塞 session 中确定了一个 RPC 事件“sys.sp_getapplock;1”。似乎 Hangfire 正在锁定我们的数据库,使整个数据库无法使用。由于 Hangfire,我们注意到将近 670 多个锁定查询。
这可能是由于我们设置了这些属性:
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(30),
QueuePollInterval = TimeSpan.FromHours(5)
每个站点有大约 20 个后台作业,其中一些每分钟运行一次,而其他每小时、每 6 小时运行一次,有些每天运行一次。
我搜索了文档,但找不到任何可以解释这两个属性或如何设置它们以避免 DB 锁的内容。
寻求这方面的帮助。
编辑:每秒执行以下查询:
exec sp_executesql N'select count(*) from [HangFire].[Set] with (readcommittedlock, forceseek) where [Key] = @key',N'@key nvarchar(4000)',@key=N'retries'
select distinct(Queue) from [HangFire].JobQueue with (nolock)
exec sp_executesql N'select count(*) from [HangFire].[Set] with (readcommittedlock, forceseek) where [Key] = @key',N'@key nvarchar(4000)',@key=N'retries'
与我们设置的时间跨度值的各种组合无关。这是我们使用的 GetHangfirServers 的代码:
public static IEnumerable<IDisposable> GetHangfireServers()
{
// Reference for GlobalConfiguration.Configuration: http://docs.hangfire.io/en/latest/getting-started/index.html
// Reference for UseSqlServerStorage: http://docs.hangfire.io/en/latest/configuration/using-sql-server.html#configuring-the-polling-interval
GlobalConfiguration.Configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(ConfigurationManager.ConnectionStrings["abc"]
.ConnectionString, new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(30),
QueuePollInterval = TimeSpan.FromHours(5), // Hangfire will poll after 5 hrs to check failed jobs.
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
});
// Reference: https://docs.hangfire.io/en/latest/background-processing/configuring-degree-of-parallelism.html
var options = new BackgroundJobServerOptions
{
WorkerCount = 5
};
var server = new BackgroundJobServer(options);
yield return server;
}
worker 数量仅设置为 5。
只有 4 个作业,甚至这些作业都已完成(SELECT * FROM [HangFire].[State]):
您知道为什么 Hangfire 每秒会遇到如此多的查询吗?
最佳答案
我们在我们的一个项目中遇到了这个问题。 hangfire 仪表板的读取量非常大,它非常频繁地轮询 hangfire 数据库以刷新作业状态。
对我们有用的最佳解决方案是拥有一个专用的 hangfire 数据库。
这样,您将应用程序查询与 hangfire 查询隔离开来,并且您的应用程序查询不会受到 hangfire 服务器和仪表板查询的影响。
关于c# - Hangfire 导致 SQL Server 中的锁定,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56321781/