代码之家  ›  专栏  ›  技术社区  ›  B.Porter

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

  •  2
  • B.Porter  · 技术社区  · 6 年前

    我们已经使用Microsoft的ServiceBrokerExternalActivator服务一段时间了,可以毫无问题地处理ServiceBroker队列的外部激活。但在过去的一个星期里,一个错误不断发生,我无法弄清到底是怎么回事。

    每天至少一次,在随机时间,服务将遇到错误,并陷入停止状态。此时,所能做的就是终止进程并重新启动服务。检查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.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更新和加载之外,服务器上没有任何变化,但出于某种原因,此错误从7月16日左右开始出现。打开详细的日志记录,我可以看到它比我预期的检查点要多得多,当发生错误时,它总是在前一个检查点的一两秒钟内。

    任何关于下一步该往哪里看的帮助或指示都将非常感谢,因为我正在为这一个撕我的头发。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Mike    6 年前

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

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

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

    我唯一能做的其他建议,也是无关的,是清除Windows临时文件夹。几年前,我遇到过这样的情况:根据Windows内部的命名或跟踪方式,创建大量临时文件会导致Windows出现问题。我没有你的链接,我不认为这是你的问题,但你可能想尝试一下。