0

问题: 是否有一个很好的工具可以在基于 Web 的 (IIS) SignalR-Core Hub 上监控性能和诊断?专门用于检测可能的死锁或挂起的线程。我看过一些工具,例如LeanSentry,但它们似乎大部分都忽略了 WebSockets。

首先是一些背景信息: 我们有一个 SaaS Web 应用程序,它使用 SignalR 将实时更新推送到 SPA 页面(包括但不限于在直播和/或视频会议期间更改页面上显示的内容)。由于在这些“现场活动”之一期间可能有 10 - 1000 多名并发与会者,我们在中心(通常是静态字典<>)中使用内存中短期缓存(0.5 秒 - 15 秒,具体取决于数据)来防止所有这些都必须同时进行相同的数据库查询(如果字典数据过时,第一个进行查询,其余的从字典缓存中获取新数据)。

为了防止异步读/写错误,我们在从任何字典读取或写入时使用 SemaphoreSlim 类,每个字典都有自己的 Semaphore 实例。

问题: 最近其中一个信号量似乎遭遇了“挂起”,阻止了所有其他线程访问该代码块。我一直无法重现它,我不知道如何继续。从当时的症状来看,这看起来像是一个死锁场景,但这应该是不可能的,因为只涉及一个信号量。我什至无法确认下面的代码片段是发生挂起的地方,只是它是当时最大的症状,而且由于它发生在现场活动期间,我没有时间进行适当的调试,只能快速进行损坏控制(通过手动重启 IIS 应用程序池解决)。

try
{
    await _vonageSessionsSp.WaitAsync();
    if (_activeVonageSessions.ContainsKey($"{eventId}|{channel}") && _activeVonageSessions[$"{eventId}|{channel}"].Fetched > DateTime.Now.AddSeconds(-5))
    {

    }
    else
    {
        if (!_activeVonageSessions.ContainsKey($"{eventId}|{channel}"))
        {
            _activeVonageSessions.Add($"{eventId}|{channel}", new ActiveVonageSession());
        }

        var dbSession = await _context.VonageSession.FirstOrDefaultAsync(x => x.EventId == eventId && x.Channel == channel);
        if (dbSession != null) //would have entered here
        {
            _activeVonageSessions[$"{eventId}|{channel}"].Fetched = DateTime.Now;
            _activeVonageSessions[$"{eventId}|{channel}"].SessionId = dbSession.SessionCode;
            _activeVonageSessions[$"{eventId}|{channel}"].ScreenshareLayout = dbSession.ScreenshareLayout;
            _activeVonageSessions[$"{eventId}|{channel}"].ActiveRecordingId = dbSession.ActiveRecordingId;
        }
        else//this would have been done weeks prior during the event setup process
        {
            var session = _OTClient.CreateSession("", MediaMode.ROUTED, ArchiveMode.MANUAL);
            await _context.VonageSession.AddAsync(new Domain.Entities.VonageSession() { EventId = eventId, Channel = channel, SessionCode = session.Id, Inserted = DateTime.Now, ScreenshareLayout = "singleSpeaker", ActiveRecordingId = null });
            await _context.SaveChangesAsync();
            _activeVonageSessions[$"{eventId}|{channel}"].Fetched = DateTime.Now;
            _activeVonageSessions[$"{eventId}|{channel}"].SessionId = session.Id;
            _activeVonageSessions[$"{eventId}|{channel}"].ScreenshareLayout = "singleSpeaker";
            _activeVonageSessions[$"{eventId}|{channel}"].ActiveRecordingId = null;
        }
    }
    var activeSession = _activeVonageSessions[$"{eventId}|{channel}"];
    return activeSession;
}
finally
{
    _vonageSessionsSp.Release();
}
4

0 回答 0