帮助排除SqlException故障:在非负载情况下,连接超时

Dan*_*ola 31 connection timeout sql-server-2008 connection-timeout

我有一个托管我的网站的服务器几乎没有流量.
一些人(<20)每天进入该网站,一些RSS阅读器订阅了我们推出的一些提要.

几乎每天晚上,一个RSS阅读器都会在半夜打电话给我们,并且由于连接中的超时而导致网站无法连接到SQL Server.细节非常奇怪,所以我正在寻找一些可能出现问题的帮助,因为我不知道从哪里开始寻找.

我们在Windows Server 2008上使用ASP.Net MVC,实体框架和SQL Server 2008.这台机器是我们从一个不完全顶级的提供商那里获得的专用盒子,所以事情可能是非最佳配置,或者谁知道什么其他.
盒子也很小,只有1Gb的RAM,但它应该承担我们现在的那种负载......

我正在复制下面的完整调用堆栈,但首先,我们知道的一些事情:

  • 当iTunes查询我们的网站时,总会发生错误.我相信这应该与任何事情无关,但事实是我们只能从iTunes获得它.我最好的猜测是,这种情况发生是因为只有iTunes在当晚没有其他人打我们的时候询问我们.
  • 我们的一个理论是,SQL Server和IIS正在为内存而战,其中一个是从未被使用中被分页到磁盘,当有人"唤醒它"时,从磁盘上读取所有内容需要很长时间进入记忆.这有可能发生吗?(我有点丢弃这个,因为如果可能的话,它听起来像SQL Server中的设计问题)
  • 我还想到了我们泄漏连接的可能性,因为我们可能没有适当地处理EF实体(请参阅我的问题).这是我通过谷歌搜索问题找到的唯一一件事.鉴于我们的负载极低,我正在抛弃这一点.
  • 这总是发生在整个晚上,所以这很可能与一段时间没有发生任何事情有关.例如,我很确定当这些请求命中时,Web服务器进程被回收并且它正在启动/重新监视所有内容.但是,重新JITting并没有解释SQL超时.

更新:我们按照建议添加了一个分析器,在我们遇到新的异常之前花了很长时间.这是我们所知道的新内容:

  • 将探查器附加到极大地减少了我们得到的错误数量.事实上,通常在每天几次之后,我们不得不等待3或4天才能发生这种情况.一旦我们停止了探查器,它就会恢复到正常的错误频率(甚至更糟).因此,探查器有一定的效果可以在某种程度上隐藏这个问题,但并不完全.
  • 查看IIS请求日志旁边的探查器跟踪,请求和查询之间存在预期的1-1对应关系.但是,我偶尔会看到很多正在执行的查询与IIS日志完全无关.实际上,就在记录实际错误之前,我在3分钟内得到了750个查询,所有查询都与IIS日志完全无关.查询文本看起来像EF生成的那种不可读的废话,并且它们并不完全相同,它们看起来就像来自网站的查询:相同的ApplicationName,User等.想一想这多么荒谬是的,该网站在2天的过程中获得了大约370个IIS请求
  • 这些无法解释的查询并非来自与之前网站相同的ClientProcessID,尽管它们可能仍然来自网站,如果此过程在此期间被回收.在最后解释的查询与第一个无法解释的查询之间有近一个小时没有活动.
  • 在我记录错误之前,我不知道它们来自哪里的长条查询之一就出现了,所以我相信这是我们应该遵循的线索.
  • 正如我原先预期的那样,当执行抛出错误的查询时,它来自与前一个不同的ClientProcessID(比前一个无法解释的一个晚了8分钟,几乎比前一个IIS快一个小时).对我来说,这意味着工人流程确实得到了回收.
  • 这是我绝对不明白的事情.IIS日志显示错误请求前一分钟,4完全服务,尽管这些查询根本没有显示在跟踪中.事实上,在那些顺利完成的4个之后,我有4个例外快速连续抛出,这4个也没有显示在跟踪中(这是有道理的,因为如果有连接超时,查询应该从未执行过,但我没有看到跟踪中的连接尝试)

所以,简而言之,我对这一点完全无能为力.我无法找到那些快速连续运行的数百个查询的原因,但我相信这些问题必须与问题有关.
我也不知道如何诊断连接问题...
或者如果Profiler跟踪可能会丢失一些根据IIS进行的查询...

有任何想法吗?


这是例外信息:

System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

System.Data.EntityException: The underlying provider failed on Open. ---> System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
   at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
   --- End of inner exception stack trace ---
   at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
   at System.Data.EntityClient.EntityConnection.Open()
   at System.Data.Objects.ObjectContext.EnsureConnection()
   at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__1[TResult](IEnumerable`1 sequence)
   at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
   at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
   at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
   at MyProject.Controllers.SitesController.Feed(Int32 id) in C:\...\Controller.cs:line 38
   at lambda_method(ExecutionScope , ControllerBase , Object[] )
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at System.Web.Mvc.Controller.ExecuteCore()
   at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Run Code Online (Sandbox Code Playgroud)

任何想法都将受到极大的赞赏.

RBa*_*ung 51

内存不足

这很可能是一个内存问题,可能是由其他事情加剧或触发,但仍然存在内存问题.还有另外两个(不太可能)的可能性,你应该首先检查和消除(因为它很容易这样做):

易于检查的可能性:

  1. 您可能已启用"自动关闭":自动关闭可能具有此行为,但很少打开它.要检查这一点,请在SSMS中右键单击应用程序数据库,选择"属性",然后选择"选项"窗格.查看"自动关闭"条目并确保将其设置为False.还检查tempdb.

  2. SQL代理作业可能会导致它:检查代理的历史记录日志以查看在事件期间是否有任何一致的作业.请记住检查维护作业,因为重建索引等常常在运行时被引用为性能问题.现在这些候选人不太可能,只是因为他们通常不会受到Profiler的影响.

为什么它看起来像一个记忆问题:

如果那些没有显示任何内容,那么你应该检查内存问题.我怀疑Memory是你原因的原因,因为:

  • 你有1 GB的内存:虽然这在技术上高于SQL Server的最低值,但它远低于SQL Server的建议,并且低于我的生产经验,即使对于负载较轻的服务器也是如此.

  • 您在同一个盒子上运行IIS和SQL Server:这本身不是推荐的,很大程度上是因为争用内存的结果,但只有1 GB的内存导致IIS,应用程序,SQL Server,操作系统和任何其他任务和/或维护都在争取很少的内存.Windows管理它的方式是通过积极地将其从非活动进程中取出来为活动进程提供内存.对于像SQL Server这样的大型进程,可能需要几秒甚至几分钟才能获得足够的内存,以便能够在这种情况下完全为请求提供服务.

  • Profiler使90%的问题消失了:这是一个很大的线索,内存可能是问题所在,因为通常情况下,像Profiler这样的东西对这个特定问题产生了这种影响:Profiler任务使SQL Server保持一点点活跃的时间.通常,这只是足够的活动,要么让它远离操作系统的"清道夫"列表,要么至少在某种程度上降低它的影响.

如何检查内存是罪魁祸首:

  1. 关闭Profiler:它对问题产生海森堡影响,因此您必须将其关闭,否则您将无法可靠地看到问题.

  2. 从另一个框运行系统监视器(perfmon.exe),该框远程连接到运行SQL Server和IIS的框上的perfomrance集合服务.您可以通过首先删除三个默认统计信息(它们只是本地),然后添加所需的统计信息(如下)来轻松完成此操作,但请确保在第一个下拉列表中更改计算机名称以连接到SQL框.

  3. 通过在perfmon上创建"计数器日志"将收集的数据发送到文件.如果您对此不熟悉,那么最简单的方法可能是将数据收集到选项卡或逗号分隔文件中,您可以使用Excel打开该文件进行分析.

  4. 设置perfmon以收集到文件并向其添加以下计数器:

    - 处理器\%处理器时间[总计]

    - PhysicalDisk \%空闲时间[ 对于每个磁盘 ]

    - PhysicalDisk\Avg.磁盘队列长度[ 对于每个磁盘 ]

    - 记忆\页数/秒

    - Memory\Page Reads/sec

    - 记忆\可用MBytes

    - 网络接口\字节总数/秒[ 对于每个使用的接口 ]

    - 处理\%处理器时间[ 见下文 ]

    - Process\Page Faults/sec [ 见下文 ]

    - 流程\工作集[ 见下文 ]

  5. 对于进程计数器(上面),您希望包括sqlserver.exe进程,任何IIS进程和任何稳定的应用程序进程.请注意,这仅适用于"稳定"流程.根据需要不断重新创建的进程无法以这种方式捕获,因为在它们存在之前无法指定它们.

  6. 在问题最频繁发生的时间内将此集合运行到文件.将收集间隔设置为接近10-15秒.(这会收集大量数据,但您需要此解决方案来挑选单独的事件).

  7. 发生一个或多个事件后,停止收集,然后使用Excel打开收集的数据文件.您可能需要重新格式化时间戳列以便有用地显示,并显示小时分钟和秒.使用您的IIS日志查找事件的确切时间,然后查看perfmon数据以查看事件发生前后的情况.特别是你想看看它的工作集之前是否很小,之后很大,之间有很多页面错误.这是这个问题最明显的迹象.

解决方案:

将IIS和SQL Server分隔到两个不同的框(首选),或者在框中添加更多内存.我认为3-4 GB应该是最低限度.

那个奇怪的EF东西怎么样?

这里的问题是它很可能是外围的,或者只是对你的主要问题有所贡献.请记住,Profiler使90%的事件消失了,所以剩下的可能是一个不同的问题,或者它可能只是问题的最极端的恶化者.由于它的行为,我猜它要么循环其缓存,要么还有其他应用程序服务器进程的后台维护.

  • 我们通过EF执行proc得到了这个,我在服务器上验证了这种情况肯定是一个内存问题. (3认同)