欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SQL Server 磁盘请求超时的833错误原因及解决方法

程序员文章站 2022-04-11 12:28:11
最近遇到一个sql server服务器响应极度缓慢,并且出现客户端请求报错的情况,在数据库中的errorlog中出现磁盘请求超过15s才完成的error消息。 对于此类问...

最近遇到一个sql server服务器响应极度缓慢,并且出现客户端请求报错的情况,在数据库中的errorlog中出现磁盘请求超过15s才完成的error消息。

对于此类问题,到底是存储系统或者磁盘的故障,还是sql server 自己的问题,亦或是应用程序引发的呢?又要如何解决?

本文将对引起此问题的某一方面的因素进行简单的分析,但是无法涵盖所有潜在的可能性,因此遇到类似问题还要做具体的分析。

sql server中的磁盘请求超时

  该错误的英文版的错误信息如下:

  sql server has encountered %d occurrence(s) of i/o requests taking longer than %d seconds to complete on file [%ls] in database id %d. the os file handle is 0x%p. 0
  the offset of the latest long i/o is: %#016i64x

  中文版的错误信息如下

  sql server 已遇到 %1! 次对数据库 id %4! 中的文件 [%3!] 进行的 i/o 请求超过 %2! 秒才完成。操作系统文件句柄为 0x%5!。最新的长时间 i/o 的偏移量为: %6!

  参考message信息中的833号错误消息

SQL Server 磁盘请求超时的833错误原因及解决方法

具体的833 error 申请磁盘请求超时现象

  具体报错情况如下:

  sql server 已遇到 m 次对数据库 n 中的文件***进行的 i/o 请求超过 15 秒才完成。操作系统文件句柄为 ***。最新的长时间 i/o 的偏移量为: ***

  也就是说在数据库的文件自动增长的过程中遇到了错误。

  SQL Server 磁盘请求超时的833错误原因及解决方法

  

  比较有意思的是某dba将此错误信息报告给负责存储(san存储,并非挂的磁盘)的工程师,认为是可能存储系统存在故障或者不稳定造成的,

  存储工程师认为存储没有问题,检查服务器后说服务器不正常,内存“几乎占满”,对于数据库服务器,内存“几乎占满”的情况可以说是完全正常的,鉴于负责存储的工程师并非专业dba,对于sql server数据库服务器的内存使用可能不是太了解,提出此疑问也可以理解。

  因为数据库服务器使用的存储是高性能的san存储,存储是作为一个服务存在的,有n多服务器共同来使用的,其他服务器并没有出现磁盘请求,不太可能说某一台服务器会出现疑似“存储故障”就简单认定为是存储故障。

  那么究竟原因在什么地方呢?

数据库引擎错误833的含义

  首先来看这个833错误的具体含义是什么,就不自己装13解释一通了,那本经典的书上写的很清楚了。

  总之,意思就是,sql server在请求磁盘读写的时候,遇到磁盘繁忙或者其他一些因素,超过了15秒还没有完成
  比如数据的读写的时候需要向磁盘发起请求,而磁盘正忙或者其他问题,来不及或者相应的不够及时,这样无疑会严重影响sql server对外提供服务器的响应时间。

  上面简单分析了,因为该问题并非普片发生的,存储系统不太可能出现问题,那就很有可能定位到当前服务器自身的因素了。

SQL Server 磁盘请求超时的833错误原因及解决方法

原因分析

  因为是专门的sql server服务器,没有其他应用程序的请求,很有可能跟向sqlserver数据库发起的请求有关。

  其实发生这个问题之前,早就有预兆了,平时还算稳定的服务器(cpu很少超过60%,内存的ple也可以稳定在20分钟以上,磁盘io延迟较低等等),只是偶尔会存在抽风一阵子的情况

  抽风的时候表现为cpu狂飙到80%左右,内存的ple会严重下降,io延迟严重增高。

  现在只能从sql server的session入手,在观察sql server中的活动session的时候,发现某一类的sql语句的查询时间非常长,
  平时这类sql在某一个时间段内执行的频率还算比较高。

  但是正常情况下,这类sql的执行效率还是比较高的,为什么突然就变的非常之底?

  在检查活动session的对应的执行计划的时候,发现这类活动session的等待状态都是io等待(pageiolatch_sh),同时sql的执行完全是意料之外的执行方式。

  因为类似查询还是执行的比较频繁的,此类session会从不同的客户端发起,一旦sql的执行效率降下来,服务器上会积压大量的活动session

  为什么平时执行的好好的sql语句突然就变的很慢很慢,

  原因就在于在某一点,sql server自动触发了统计信息的更新,但是这是一个比较大的表,但是默认统计信息更新的取样比例是不够的,如果取样百分比不够,这个统计信息完全是不可用的。

  一旦自动收集统计信息完成之后,会根据当前收集到的统计信息,向之前的sql语句发出一种它认为高效的方式(table scan而不是index seek),其实这种方式并非是合理的,
  由此引发对应的sql利用一种并非合理的执行计划来实现查询,同时会引发session的拥堵,客户端发过来大量的session同时在利用一种低效的方式缓慢执行。

  所以cpu会飙升,io延迟增加,内存的ple严重下降。

  由此也不难理解,数十个查询的session正在以一种不合理的方式疯狂地想磁盘发出请求,磁盘正在忙于活动session的数据请求,出现无法响应因为数据或者索引文件的自动增长请求,造成一开始说的问题。

  最后经过索引重建(促使统计信息更新,当然纯粹的统计信息更新也可以)解决,长期预防的话,需要安排job人为地定义统计信息更新的阈值以及取样百分比。

总结:

  数据库服务器上的问题,很多问题都是一个连锁反应的过程,对应观察到的一部分现象,很有可能并不是表面上的反应的那样(磁盘请求超时,问题出在存储上?)
  专业的位置上必须要有专业的素养,比如一开始dba误以为是存储问题,存储工程师认为服务器内存用满了是不正常的等,其实都不是问题的根本原因所在。
  面对问题,要追本溯源,找出来最根本的原因,才是解决问题的关键。