SQL Server Service Broker外部激活器检查点错误

时间:2018-07-24 13:43:11

标签: c# sql-server service-broker

我们一段时间以来一直在使用Microsoft的Service Broker外部激活器服务来毫无问题地处理Service Broker队列的外部激活。但是在过去的一周中,错误不断发生,我无法深入探究。

每天至少随机出现一次,该服务将遇到错误并陷入“正在停止”状态。此时,所有可以做的就是终止进程并重新启动服务。检查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日左右开始出现。打开详细日志记录,我可以看到它在检查点上的数量远远超出了我的预期,并且当错误发生时,它总是在上一个检查点的一两秒之内。

在我将头发拔掉的任何帮助或指示物上,接下来的查找将不胜感激。

1 个答案:

答案 0 :(得分:3)

这并非特定于Service broker,但是我以前见过这种情况,尤其是在代码中:

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

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

我可以提出的另一个建议,也是不相关的,是清除Windows temp文件夹。几年前,我遇到了一些问题,其中根据Windows内部文件的命名或跟踪方式,创建多个临时文件导致Windows问题。我没有您的链接,我也不认为这是您的问题,但是您可能想尝试一下。