【问题标题】:SQL Server Service Broker External Activator Checkpointing ErrorSQL Server Service Broker 外部激活程序检查点错误
【发布时间】:2018-07-24 13:43:11
【问题描述】:

一段时间以来,我们一直在使用 Microsoft 的 Service Broker External Activator Service 来毫无问题地处理 Service Broker 队列的外部激活。但是在上周,一个错误不断发生,我无法深入了解。

每天至少一次,在随机时间,服务会遇到错误并卡在 Stopping 状态。此时所能做的就是终止进程并重新启动服务。检查 EATrace.log 文件发现以下错误:

18/07/2018 09:59:45 EXCEPTION
ERROR = 90, Internal exceptions have occurred when External Activator is runtime checkpointing.
18/07/2018 09:59:45 EXCEPTIONDETAILS Inner Exception:
18/07/2018 09:59:45 EXCEPTIONDETAILS System.IO.IOException: Cannot create a file when that file already exists.
18/07/2018 09:59:45 EXCEPTIONDETAILS 
18/07/2018 09:59:45 EXCEPTIONDETAILS    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
18/07/2018 09:59:45 EXCEPTIONDETAILS    at System.IO.File.Move(String sourceFileName, String destFileName)
18/07/2018 09:59:45 EXCEPTIONDETAILS    at ExternalActivator.LogManager.SaveRecoveryContext(LogRecoveryContext recoveryContext)
18/07/2018 09:59:45 EXCEPTIONDETAILS    at ExternalActivator.LogManager.Checkpoint(LogRecoveryContext recoveryContext)
18/07/2018 09:59:45 EXCEPTIONDETAILS    at ExternalActivator.LogManager.Log(LogRecord recoveryLogRec)
18/07/2018 09:59:45 EXCEPTIONDETAILS    at ExternalActivator.ApplicationMonitor.OnProcessExited(ProcessMonitor processMonitor)
18/07/2018 09:59:45 EXCEPTIONDETAILS    at ExternalActivator.ProcessMonitor.NotifySubscriber()
18/07/2018 09:59:45 EXCEPTIONDETAILS    at ExternalActivator.ProcessMonitor.OnProcessExited(Object a, EventArgs b)

使用 Reflector 我发现了有问题的 SaveRecoveryContext 方法:

private void SaveRecoveryContext(LogRecoveryContext recoveryContext)
    {
      this.m_file = File.Open(this.TempLogFileName, FileMode.Create, FileAccess.Write, FileShare.Read);
      foreach (LogRecord recoveryLogRec in recoveryContext.List)
        this.Write(recoveryLogRec);
      this.CloseFiles();
      File.Delete(this.LogFileName);
      File.Move(this.TempLogFileName, this.LogFileName);
      this.m_file = File.Open(this.LogFileName, FileMode.Append, FileAccess.Write, FileShare.Read);
    }

请注意,LogFileName 是 EARecovery.rlog,而 TempLogFileName 是 EARecovery_temp.rlog。发生错误后检查日志文件夹时,只有临时文件,原始文件已按预期删除。

我的第一个想法是,可能有多个线程同时尝试检查点并相互绊倒,但向上堆栈跟踪会将我们带到以下位置:

public void Log(LogRecord recoveryLogRec)
    {
      lock (this)
      {
        this.Write(recoveryLogRec);
        if (!recoveryLogRec.CanCompress)
          return;
        ++this.m_recordsToCompress;
        if (this.m_recordsToCompress <= 100)
          return;
        LogRecoveryContext local_0 = new LogRecoveryContext();
        string local_1 = Global.GetEaContext();
        Global.SetEaContext(Localized.GL_EaContext_RuntimeCheckpoint);
        this.Checkpoint(local_0);
        Global.SetEaContext(local_1);
      }
    }

我本来希望 lock 语句可以防止这种情况发生。

除了通常的 Windows Udpates 和负载没有增加之外,服务器上没有任何变化,但由于某种原因,这个错误从 7 月 16 日左右才开始发生。打开详细日志记录,我可以看到它的检查点比我预期的要多得多,并且当错误发生时,它总是在前一个检查点的一两秒内。

任何关于下一步看哪里的帮助或指示将不胜感激,因为我正在为此而烦恼。

【问题讨论】:

    标签: c# sql-server service-broker


    【解决方案1】:

    这不是特定于服务代理的,但我以前见过这种情况,尤其是代码:

      File.Delete(this.LogFileName);
      File.Move(this.TempLogFileName, this.LogFileName);
    

    如果后台进程(如防病毒软件)使文件保持打开状态,则文件可能不会立即消失。如果您正在运行防病毒软件,例如 Windows Defender 或其他产品,您可能需要将该文件夹列入白名单,以便它不会尝试扫描文件。

    我能提出的唯一其他建议,同样无关紧要,就是清除 Windows 临时文件夹。几年前,我遇到了一些问题,根据它们在内部命名或跟踪它们的方式,创建许多临时文件会导致 Windows 出现问题。我没有给你的链接,我认为这不是你的问题,但你可能想尝试一下。

    【讨论】:

    • 谢谢迈克,我没有考虑过这种可能性。我已经从 Windows Defender 中排除了相关文件夹,并将检查它是否具有预期的效果。
    • 24 小时后错误没有再次发生,所以我暂时乐观地认为您已经找到了原因。非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2014-05-15
    • 2011-01-14
    • 1970-01-01
    • 1970-01-01
    • 2012-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多