【发布时间】: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