SQL Server缓存刷新和磁盘I / O


11

我们正在忙于负载测试我们在.NET 4.0中开发的OLTP系统,并在后面运行SQL Server 2008 R2。该系统使用性能非常出色的SQL Server Service Broker队列,但是在处理过程中我们遇到了一种特殊的趋势。

SQL Server处理请求的速度为1分钟,然后增加磁盘写入活动的时间约20秒。下图说明了该问题。

SQL OLTP系统-性能计数器

Yellow = Transactions per second
Blue   = Total CPU usage
Red    = Sqlsrv Disk Write Bytes/s
Green  = Sqlsrv Disk Read Bytes/s

在故障排除期间,我们尝试了以下操作,但模式没有任何重大变化:

  • 停止SQL Server代理。
  • 几乎杀死了所有其他正在运行的进程(没有A / V,SSMS,VS,Windows资源管理器等)
  • 删除了所有其他数据库。
  • 禁用所有对话计时器(我们不使用任何触发器)。
  • 从消息队列驱动的方法转移到简单/粗略的表监视设计。
  • 从轻到重使用了不同的负载。
  • 修复了所有死锁。

似乎SQL Server可能正在建立其缓存并以特定的基于时间的时间间隔将其写入磁盘,但是我找不到任何在线资源来支持该理论。

接下来,我计划将解决方案移至我们专用的测试环境,以查看是否可以重现问题。在此期间的任何帮助将不胜感激。

Update 1 根据要求,提供一个图形,其中包括Checkpoint Pages / SecPage Life Expectancy和一些磁盘延迟计数器。

SQL OLTP系统-性能计数器-检查点

似乎检查点(浅蓝色线)是导致我们观察到的性能下降(黄线)的原因。^

磁盘延迟在处理过程中保持相对一致,并且页面预期寿命似乎没有任何明显的影响。我们还调整了可用于SQL Server的ram数量,这也没有太大的影响。将恢复模式从更改SIMPLEFULL也没有什么不同。

更新2 通过如下更改“恢复间隔”,我们设法减小了检查点的间隔:

EXEC sp_configure 'show advanced options',1
GO 

RECONFIGURE
GO

EXEC sp_configure 'recovery interval', '30'
GO

RECONFIGURE 
GO

EXEC sp_configure 'show advanced options',0
GO
RECONFIGURE

我不确定这是否是不好的做法?


1
添加检查点页面数/秒计数器。然后再次测试并显示图表。当您的事务下降而写入上升时,您是否看到性能问题?我也想补充一些磁盘延迟计数器-平均秒/读取和平均秒/写
迈克·沃尔什

当您发布下一张图表时,可以包含数字。该图没有显示任何比例。
Mike Walsh 2012年

5
最后一件事(对不起!)-该服务器上的内存是多少?您还可以添加页面预期寿命计数器吗?您能描述一下物理设置(内存,IO设置,是否拆分日志和数据文件等)
Mike Walsh 2012年

2
数据库处于哪种恢复模式?事务日志填满后,这看起来像自动检查点。请注意,即使数据库位于FULL或中BULK_LOGGED,在SIMPLE执行完整备份之前,数据库的行为也仍与数据库一样。
乔恩·塞格尔

2
乔恩-无论恢复模式如何,检查点仍然会发生。简化:唯一的区别是恢复模型中的检查点之后,日志中的数据发生了什么。处于“完整”状态时,它将保留在日志中,需要备份。简单地说,它可以被截断(或标记为截断..重用),但检查点仍然必须发生。
Mike Walsh 2012年

Answers:


11

其他人已经指出了罪魁祸首:SQL Server在内存中(在缓冲池中)累积更新,并且仅定期(在检查点)将其清除。建议的两个选项(-k和检查点间隔)是互补的:

但是我并没有仅仅反驳您收到的精美评论:)

不幸的是,您所看到的是排队处理的一种非常典型的行为。无论您使用Service Broker队列还是选择使用表作为队列方法,系统都非常容易出现这种行为。这是因为基于排队的处理的写入量很大,甚至比OLTP处理更重。入出队原语都是写操作,几乎没有读操作。简而言之,与任何其他工作负载(甚至是OLTP)(例如TPC-C之类的工作负载)相比,队列处理将生成最多的写入(=最脏的页面和最多的日志)。

非常重要的是,队列工作负载的写入遵循插入/删除模式:插入的每一行都会很快删除。这对于区分插入繁重(ETL)工作负载的仅追加模式非常重要。基本上,您要给幽灵清理任务提供一顿饱餐,并且可以轻松地将其清除。考虑一下这意味着什么:

  • enqueue是一个插入,它将创建一个脏页
  • dequeue是一个删除,它将再次弄脏同一页面(这可能是幸运的,并且在检查点之前捕获了该页面,因此它避免了两次刷新,但是只有在幸运的情况下)
  • 幽灵清理将清理页面,使其再次变脏

是的,这实际上意味着您可能会针对三个要处理的消息(在最坏的情况下),在三个不同的IO请求中,将页面写三次到磁盘上。而且这也意味着检查点的随机IO 实际上是随机的,因为页面的写入点将由那些移动头在两个检查点之间再次访问(与许多OLT​​P工作负载相比,倾向于将写入集中在某些“热点”上,不排队...)。

因此,您拥有这三个写入点,一次又一次地将同一页标记为脏。而且这是在考虑任何页面拆分之前,由于插入键的顺序,也可能易于进行队列处理。相比之下,“典型”的OLTP工作负载具有更为均衡的读/​​写比率,并且OLTP的写操作分布在插入/更新/删除之间,并且经常进行更新(“状态”更改),而插入占据了大部分份额。根据定义,队列处理写入仅按50/50分割进行插入/删除。

一些后果如下:

  • 检查点成为一个非常热门的问题(不再让您感到惊讶)
  • 您会看到严重的碎片(碎片本身并不重要,因为您不打算进行范围扫描,但是您的IO效率会受到影响,虚影清理还有更多工作要做,甚至会减慢速度)
  • 您的MDF存储随机IO吞吐量将成为您的瓶颈

我的建议用3个字母表示:S,S和D。将MDF移到可以处理快速随机IO的存储中。SSD。如果有钱,请使用Fusion-IO。不幸的是,这是使用更便宜的RAM无法解决的症状之一。

编辑:

正如Mark所指出的,您有两个逻辑磁盘由一个物理磁盘支持。也许您尝试遵循最佳实践并在D:和C:上分割数据,但遗憾的是,C和D是同一磁盘。在检查点之间,您可以实现顺序的吞吐量,但是一旦检查点启动,磁盘头便开始移动,日志吞吐量崩溃,从而降低了整个应用程序的吞吐量。确保分离数据库日志,以便不受数据IO(分离的磁盘)的影响。


2
有趣的是,知道为什么检查点驱动的IO会对应用计数器产生如此巨大的影响。理想情况下,应用程序应在检查点运行时先行耕作。当然,我假设您不共享LDF和MDF存储访问路径(如果这样做,那么您应该得到它……)。也许您在应用程序中有一些不必要的争用点。
雷木斯·鲁萨努

Remus做得很好。
Mark Storey-Smith

3
查看列出的perfmon计数器,我怀疑您可能在同一驱动器或阵列上的数据和日志正确无误。
Mark Storey-Smith

@ MarkStorey史密斯:我想你是对的,OP具有C:D:逻辑磁盘支持通过同一个物理磁盘。我怀疑物理磁盘是否由100个短条带状纺锤形电池组成,因此这可能是根本原因。
Remus Rusanu

是的,此测试是在我的本地dev机器上完成的,该机器只有一个驱动器。谢谢大家的帮助。
安德烈Hauptfleisch
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.