事情起因:
  排查SQL Server上的死锁问题,一开始想到的就是扩展事件,
  第一种方案,开profile守株待兔吧,显得太low了,至于profile的变种trace吧,垂垂老矣,也一直没怎么用过。
  第二种方案是开启TRACE flag(DBCC TRACEON (3605,1204,1222,-1))将死锁写入error log,也是个不错的选择。
  不过想到系统默认的扩展事件system_health已经捕获了死锁信息(sqlserver.xml_deadlock_report),
  就没必要再重新往error log记一次了,理论上从system_health中就能拿到死锁信息,因此尝试从system_health的ring_buffer target获取死锁信息。

排查经过:
  从sysem_health的ring_buffer中目标中,并没有捕获到预期的曾经发生的死锁事件信息,
  在完全确认发生过死锁的情况下(并且是最近,或者是刚刚),为什么sysem_health“没有能够捕获到”?
  无奈之下单独开了一个捕获死锁事件的扩展事件Session(仅捕获sqlserver.xml_deadlock_report),target目标是存储在ring_buffer中
  在人为刻意地制造一个死锁之后,来检验sysem_health和自定义的捕获扩展事件捕获的死锁信息
  此时意想不到的情况发生了,自定义的扩展事件完整地捕获到了这个死锁信息,而system_health仍旧没有捕获到对应的死锁信息。
  什么情况?

  如下自定义扩展事件脚本

CREATE EVENT SESSION [Deadlock_Monitor] ON SERVER
ADD EVENT sqlserver.xml_deadlock_report
ADD TARGET package0.ring_buffer(SET max_events_limit=(5000),max_memory=(4096))
WITH
(MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=10 SECONDS,
MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON) ALTER EVENT SESSION [Deadlock_Monitor] ON SERVER STATE = start;

死锁捕获结果,sysem_health并没有捕获到预期的死锁事件,尽管他包括了sqlserver.xml_deadlock_report事件

SELECT  xed.value('@timestamp', 'datetime') AS Creation_Date ,
CAST(REPLACE(REPLACE(REPLACE(CAST(xed.query('.') AS NVARCHAR(MAX)),'&lt;', '<'),'&gt;', '>'),'&amp;apos;','''') AS xml) AS Extend_Event
FROM ( SELECT CAST([target_data] AS XML) AS Target_Data
FROM sys.dm_xe_session_targets AS xt
INNER JOIN sys.dm_xe_sessions AS xs ON xs.address = xt.event_session_address
WHERE xs.name = N'system_health'
AND xt.target_name = N'ring_buffer'
) AS XML_Data
CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]')
AS XEventData ( xed )
ORDER BY Creation_Date DESC select * from sys.dm_xe_session_targets SELECT CAST([target_data] AS XML) AS Target_Data
FROM sys.dm_xe_session_targets AS xt
INNER JOIN sys.dm_xe_sessions AS xs ON xs.address = xt.event_session_address
WHERE xs.name = N'system_health'
--AND xt.target_name = N'ring_buffer' -- Parse the XML to show wait details
SELECT event_table.*
FROM (
SELECT CAST(event_data AS XML) xml_event_data
FROM sys.fn_xe_file_target_read_file(N'path\Log\system_health*', NULL, NULL, NULL)
) AS event_table
CROSS APPLY xml_event_data.nodes('//event') n (event_xml)
WHERE event_xml.value('(./@name)', 'varchar(1000)') IN ('xml_deadlock_report')

  由于sysem_health有两个输出的target,一个ring_buffer,一个是target_file,无奈下从event_file查询捕获的死锁信息,这里又是没问题的,正常捕获到了。

  

  因此就可以说,系统默认自带的sysem_health扩展事件,捕获死锁本身是没有问题的,问题出在扩展事件的输出目标ring_buffer上。
  在不过滤所有的扩展事件情况下,从ring_buffer里面解析出来的数据还有个特点,其不包含最近一段时间的任何一种事件信息。
  也就是说,ring_buffer中解出来的事件信息,是当前时间前一段时间的事件信息,并不包含所有的事件信息,以及最近一段事件所有的事件信息。
  当然你可以说ring_buffer是先进先出的队列模型,那也应该留下新的事件,而不是解析不出来最新的事件信息。

原因分析:
  参考了sqlskill上的一篇文章,这篇文章深入地解析了这个问题,
  简单说就是:
  ring_buffer并没有“丢失”事件信息,至于为什么解析不出来,要从ring_buffer解析方式开始,ring_buffer扩展事件从sys.dm_xe_session_targets 这个DMV中解析的,
  受到sys.dm_xe_session_targets 这个DMV的目标数据列target_data字段只能容纳大约4 MB的XML数据的限制。
  当ring_buffer捕获的事件(内存中的二进制数据)转换为XML格式大于(大约)4MB的情况下,超过4MB的其他的事件会被被“截断”,
  从sys.dm_xe_session_targets解析出来的XML文件优先输出更早的事件,所以我们预期下的最近发生的事件是无法看到的。
  因此,正如上文中遇到的情况一样:“丢失”部分事件信息,并且没有最近的事件信息。

总结:  
  以此来看,使用ring_buffer为扩展事件的target,潜在以下问题
  1,解析出来的结果并不可靠(完整),可能无法解析到最近的部分事件。
  2,以下译文中还会提到,ring_buffer作为target可能会撑爆内存的情况,所以要谨慎使用。
  3,同样下文会提到,SSMS的UI对ring_buffer中的事件支持的并不好,对于ring_buffer的target,UI也仅仅是show出来一个XML文件,必须要自己解析,而不像event_file中那样表格化展示(可读性)
  因此要尽量避免在扩展事件中使用ring_buffer target。

如下是译文,原文地址:https://www.sqlskills.com/blogs/jonathan/why-i-hate-the-ring_buffer-target-in-extended-events/

(标题)我为什么讨厌扩展事件中的ring_buffer target

我曾经多次遇到扩展事件中有关ring_buffer target同样的问题,
我想我会写一篇博客文章,解释了我教的所有信息关于ring_buffer target和与之关联的问题。
自从sqlserver 2012发布以及扩展事件新UI的更新,我以后坚决不会再使用ring_buffer target
事实上,正如文章标题所言,我确实很讨厌ring_buffer target,这篇文章中我将会阐述我讨厌ring_buffer target的原因,并且希望说服应该使用file_target代替。

丢失事件

这是我通过电子邮件解释关于ring_buffer目标的最常见问题。一般来说,如下是典型的问题描述:

我从SQL Server中心的一篇文章中得到了下面的代码,它不起作用。我遇到的问题是,当我运行代码时,即使我知道应用程序中刚刚发生了一个死锁事件,它也不会显示任何死锁信息。
似乎我只在system_health会话中看到较旧的死锁,但从来没有看到最新的死锁。我打开了Trace 1222并以这种方式获取信息,那么为什么不这样做。

实际情况是,事件(event)实际上在就那里,你无法看到(你预期的事件)是因为sys.dm_xe_session_targets 这个DMV的限制。
这个DMV的目标数据列只能输出大约4 MB的XML数据。
Bob Ward20009年的时候在CSS SQL Server工程师博客中解释了DMV的4 MB格式XML限制的信息。
为了证明这种限制的结果,让我们来看看在SQL Server 2012 SP1+CU7服务器上的系统健康事件会话中包含的事件数量,我可以使用下面的查询来查看信息。

SELECT
ring_buffer_event_count,
event_node_count,
ring_buffer_event_count - event_node_count AS events_not_in_xml
FROM
( SELECT target_data.value('(RingBufferTarget/@eventCount)[1]', 'int') AS ring_buffer_event_count,
target_data.value('count(RingBufferTarget/event)', 'int') as event_node_count
FROM
( SELECT CAST(target_data AS XML) AS target_data
FROM sys.dm_xe_sessions as s
INNER JOIN sys.dm_xe_session_targets AS st
ON s.address = st.event_session_address
WHERE s.name = N'system_health'
AND st.target_name = N'ring_buffer' ) AS n ) AS t;

ring_buffer_event_count是RingBufferTarget根元素返回的XML文档的eventCount属性(译者注:ring_buffer_event_count是RingBufferTarget捕获到的事件的总数)
event_node_count是sys.dm_xe_session_targets 这个 DMV中返回的ingBufferTarget/event nodes中事件的个数(两者的差值就是所谓丢失的事件个数)
这里你可以看到ring_buffer target中一共有5000个事件,(原因是)system_health会话基于2012新的MAX_EVENTS_LIMIT选项设定在5000。
不过,仅仅有3574个事件被DMV中的XML输出了出来,剩下有1426个事件仍然不可用(不可见,无法解析出来),尽管他们是滞留在内存中的。
sys.dm_xe_session_targets 的XML文件优先输出更早的事件,所以我们预期下的最近发生的事件是无法看到的。

译者注,如下是system_health中ring_buffer MAX_EVENTS_LIMIT选项设定在5000的值:

我们可以观察扩展事件目标占用的内存和DMV中的XML二进制数据占用的内存情况,使用如下查询

SELECT
target_data.value('(RingBufferTarget/@memoryUsed)[1]', 'int') AS buffer_memory_used_bytes,
ROUND(target_data.value('(RingBufferTarget/@memoryUsed)[1]', 'int')/1024., 1) AS buffer_memory_used_kb,
ROUND(target_data.value('(RingBufferTarget/@memoryUsed)[1]', 'int')/1024/1024., 1) AS buffer_memory_used_MB,
DATALENGTH(target_data) AS xml_length_bytes,
ROUND(DATALENGTH(target_data)/1024., 1) AS xml_length_kb,
ROUND(DATALENGTH(target_data)/1024./1024,1) AS xml_length_MB
FROM (
SELECT CAST(target_data AS XML) AS target_data
FROM sys.dm_xe_sessions as s
INNER JOIN sys.dm_xe_session_targets AS st
ON s.address = st.event_session_address
WHERE s.name = N'system_health'
AND st.target_name = N'ring_buffer') as tab(target_data)

这里我们可以看到,二进制数据占用的内存大约为1.7MB,不过一旦序列化为XML,文件的大小就变为大约4.7MB,比二进制数据空间要大
问题的本质就在于,扩展事件生成的特点,决定了他紧凑的二进制格式的,但是序列化的格式化XML会为这些事件增加存储空间。

system_health事件会话特别倾向于收集最多5000个事件但ring_buffer,DMV实际上只能输出一小部分事件会话。
最有可能的是,sp_server_diagnostics_component_output和xml_deadlock_report具有相当大的事件是(占用的空间),因为这两个事件返回的XML的大小取决于它们何时触发的条件的具体情况。

我发现在繁忙的服务器上出现问题时,sp_server_diagnostics_component_output事件的大小超过了512KB,
因此当输出XML中包含其中一个事件时,对ring_buffer目标,由DMV返回的数据可能会受到很大限制。

没有UI的支持

这对我来说可能是我日常工作中不再使用ring_buffer作为输出目标的最大原因。
扩展事件UI不支持分解ring_buffer目标中包含的信息, UI的唯一功能是显示由sys.dm_xe_session_targets DMV的target_data列输出的XML。

这意味着要使用数据,您必须打开XML并扫描事件,或编写XQuery以将XML解析为表格形式,这要求您知道事件会话中使用的事件,列和操作定义来真正访问数据。
如果我正在进行短期数据收集,并且不希望它保存到SQL Server 2012上的文件系统中的文件,我只需选择实时视图就可以将数据流式传输回UI的列表中,
在这种情况下,我不必处理XML并可以快速找到我感兴趣的信息。
对于任何长期任务,甚至查看system_health事件会话中的信息,我都使用file_target,UI可以读取和处理事件,无需手动执行任何XQuery。

当心内存的使用

在生产服务器上配置ring_buffer目标的方式需要非常小心,这对我来说是前所未闻的。
两周之前,Andy Galbraith遇到一个所有连接报701系统内存不足的错误,
经过分析,Andy发现在内存16GB,最大内存(max server memory)配置为11000MB的服务器上,MEMORYCLERK_XE memory clerk 占用了10GB的内存,
问题就在于,一个扩展事件配置了收集最大(MAX_EVENTS_LIMIT)1,000,000 个事件,但是没有配置最大内存限制,
因此内存的使用就基于扩展事件收集到的事件个数,并且没有最大的内存使用限制,那么它就可以使用无限的内存,在内存有限的情况下,从而导致服务器上出现问题。

SQL Server扩展事件的使用ring_buffer target时“丢失”事件的原因分析以及ring_buffer target潜在的问题的更多相关文章

  1. SQL Server 扩展事件(Extented Events)从入门到进阶(1)——从SQL Trace到Extented Events

    由于工作需要,决定深入研究SQL Server的扩展事件(Extended Events/xEvents),经过资料搜索,发现国外大牛的系列文章,作为“学习”阶段,我先翻译这系列文章,后续在工作中的心 ...

  2. SQL Server 扩展事件(Extented Events)从入门到进阶(4)——扩展事件引擎——基本概念

    本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列 在第一二节中,我们创建了一些简单的.类似典型SQL Trace的扩展事件会话.在此过程中,介绍了很多扩展事 ...

  3. SQL Server 扩展事件(Extented Events)从入门到进阶(3)——通过界面操作Extented Event

    本文属于 SQL Server扩展事件(Extended Events)从入门到进阶 系列 对于接纳扩展事件,其中一个最大的障碍就是要对XML和XQuery有一定的了解以便分析数据.我们可以使用T-S ...

  4. SQL Server扩展事件-- 使用system_health默认跟踪会话监控死锁

    SQL Server扩展事件(Extended Events)-- 使用system_health默认跟踪会话监控死锁 转自:http://blog.51cto.com/ultrasql/160037 ...

  5. SQL Server 扩展事件

    SQL Server 扩展事件(Extended Event)是用于服务器的常规事件处理系统,是追踪SQL Server系统运行状态的神器,同时也是一个日志记录工具,扩展事件完全可以取代SQL追踪(S ...

  6. SQL Server 扩展事件(Extented Events)从入门到进阶(2)——在GUI中创建基础扩展事件

    本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列 第一篇文章中提到了如何在Profiler中创建跟踪(trace),并以服务器端(server-side)跟 ...

  7. SQL Server扩展事件system_health会话总结

    system_health会话概念 我们知道扩展事件(Extended Events)是从SQL Server 2008开始引入的.system_health会话是SQL Server默认包含的扩展事 ...

  8. 使用SQL Server 扩展事件来创建死锁的时间跟踪

    我们通过SQL Server 2012图形界面来部署一个扩展事件跟踪会话.然后可以生成SQL脚本,在2008或2008 R2版本下运行类似的跟踪. 步骤1: 通过“Object Explorer”连接 ...

  9. 使用SQL Server 扩展事件来创建死锁的跟踪

    我们通过SQL Server 2014图形界面来部署一个扩展事件跟踪会话.然后可以生成SQL脚本. 步骤如下: 步骤1: 通过“对象资源管理器”连接到实例,展开“管理”.“扩展事件”.“会话”. 步骤 ...

随机推荐

  1. DB SQL Monitor 会话状态及等待事件监控工具

    DB SQL Monitor v1.7.6       Designed by Wang Zhaoguan   工具说明 --------------------------------------- ...

  2. django 防止xss攻击标记为安全的二种方法

    str='<a href="/page?page=1">1</a>' 一,在前端模板语言中实现,只须用到帮助函数safe.如: {{ str|safe }} ...

  3. centos7远程安装oracle11g R2详细教程-解决一切问题

    相关链接与资源: sqldevelper(各种操作系统的oracle客户端) http://www.oracle.com/technetwork/cn/developer-tools/sql-deve ...

  4. MVC5 方法扩展

    public static MvcHtmlString DataDictionaryDropDownList(this HtmlHelper htmlHelper, string name, obje ...

  5. Ruby版快速排序

    class Array def quick_sort return self if self.length<=1 k = self[0] head = 0 tail = self.length ...

  6. SpringBoot启动源码探究---listeners.starting()

    1.首先调用starting()方法,其内部是一个对所有listener的starting()调用的for循环,然后每个listener调用另一个starting方法,其内部调用multicastEv ...

  7. VS2017编译GDAL(64bit)+解决C#读取Shp数据中文路径的问题

    编译GDAL过程比较繁琐,查阅了网上相关资料,同时通过实践,完成GDAL的编译,同时解决了SHP数据中文路径及中文字段乱码的问题,本文以“gdal-2.3.2”版本为例阐述整个编译过程. 一.编译准备 ...

  8. Spring编程式事务管理和声明式事务管理

    本来想写一篇随笔记一下呢,结果发现一篇文章写的很好了,已经没有再重复写的必要了. https://www.ibm.com/developerworks/cn/education/opensource/ ...

  9. 前端-JavaScript1-8——JavaScript之作业练习

    1.表示气温有两种方法:摄氏度和华氏度.两者的关系是: 编写程序,让用户输入摄氏度,弹出对应的华氏温度. //第一步,让用户输入数字 var sheshidu = parseFloat(prompt( ...

  10. WPF设计界面不执行代码

    一般在我们在设计WPF XAML界面时,XAML 引用一些后端的类.比如UserControl.Converter.MVVM,引用 xmlns:ALLUserControl="clr-nam ...