英文原文地址:https://www.simple-talk.com/sql/database-administration/sql-server-alerts-soup-to-nuts/
为了确保数据库无故障运行,你必须得知道一些超出寻常范围内发生的事。你需要了解事件、错误条件、极限负载、硬件问题、安全问题、性能相关条件、失败的进程、回滚、死锁、持久进程、昂贵的缓存执行计划,和一些导致信号问题的因素。仅仅偶尔查看错误日志是不够的:你需要被通知。
某种程度上,数据经历着不适和苦痛。任何生物都需要感受到疼痛,根据疼痛的原因采取行动。数据库需要行动起来避开可能的失败,DBA必须尽快对潜在的失败信号做出回应,否则失败就会发生。告警允许程序员或管理员做出反应。如果你致力于支持一个高可用服务器,你会了解这个技能,在问题发出的前几个信号就阻止它。为了看到这些信号,你已经在查找它们,但是你必须确保提醒到你警惕起来。告警就提供了这样的工具。
专业术语
在开始之前,了解一些术语:告警被定义为对事件的自动回应。在SQL Server中术语“事件”不是特别好定义。在之前的SQL Server版本中,事件是被写入到SQL Server错误日志中,在之后的版本中,在Windows应用程序事件日志中。当前,事件的意思是“在SQL Server中任何可以触发告警的状态或条件”。
无论如何,事件由SQL Server产生,默认也被写入到Microsoft Windows应用程序日志中。SQL Server代理读取应用程序日志,将找到的事件和已经定义的告警比较。当SQL Server代理找到匹配的,就会触发告警。
你可以使用SSMS、TSQL或SMO来定义告警:
-
SQL Server事件(SQL Server events) -- 基于特定的错误或特定安全级的错误等的出现。
-
性能条件(Performance conditions) -- 你会对一个特定对象定义一个性能计数器,并设置告警,当特定的阈值条件达到时触发。
-
WMI事件(Windows Management Instrumentation events) -- 当特定的服务器事件WMI提供者监控的SQL Server事件发生时,告警被触发。
在程序的世界,你认为告警系统是在各种数据库条件下对你的代码定义的回调部分。在SQL Server中,你定义告警来通知你错误、事件或条件。你可以采取补救行动。一些事件需要调查;一些可以被脚本处理。其他的两者都需要。SQL Server告警可以被配置发送消息,或者执行一个脚本。消息被发送给操作者或管理员,通知他们事件相关的提醒(notifications)。
架构
告警在SQL Server的演化过程中是较晚的出现的。原始的设计是一个基于SQL Server代理的简陋但有效的系统,它只读取SQL Server错误日志(现在读取应用程序日志),扫描特定类型或安全级的错误。一旦找到,它会指定一个T-SQL作业并以提醒的方式发送消息。它是有用的,但提供了很少的信息用于在错误发生前采取有效阻止手段。
当监控SQL Server性能的方式便得更加复杂,两个独立的提醒系统设计出来了。一个是基于操作系统,使用性能监视器,提供提醒和命令行可执行程序。另一个使用SQL Server代理的告警服务,提供基于TSQL代理作业的触发器以及提醒。后面的系统有SQL Server计数器,而不是通常的操作系统计数器。
最后,当WMI在SQL Server 2005中引入后,允许告警系统做WMI查询,因此第四类告警被添加。WMI告警系统是一个全面的覆盖了之前系统确实的方面,但是对于忙碌的DBA来处理是相当复杂的。
SQL Server事件告警
通常,程序员系统展示给最终用户数据库的所有错误信息。这是个糟糕的注意。例如,如果事务日志空间不足,终端用户只能电话给DBA或者诅咒IT部门。使用告警的简单方式是允许DBA或开发收到出现在错误日志中的错误的拷贝,以寻呼机、电子邮件或SMS消息。
定义告警
事件由Microsoft SQL Server产生,如果它们标记为“已记录”,被写入到Microsoft Windows应用程序日志和SQL Server错误日志。SQL Server代理,一个独立的应用程序,读取应用程序日志,查看是否你在告警中定义的事件已经被写入。如果是的,代理触发以最准确的方式定义的错误的告警。意思是一个被特定错误号码的事件所触发的特定告警会被选择,而不是一个通常的告警被触发,如果它属于一个特定安全级。
你可以通过SSMS配置告警:
你可以基于错误号码或错误安全级触发告警。定义一个触发在每个错误上的告警是相当容易的,对于一个特定安全级的错误,将会给你电子邮件提醒。
对于SQL Server事件告警好奇的是,你不能对于特定的安全级别上的所有事件配置告警。为了尽量提供一个告警垃圾箱,你需要一个将会遇到的性能告警。如果你希望遵守SQL Server事件告警,需要对每个安全级别创建告警。通过SSMS会非常乏味,通过脚本实现更加容易。然而,对于一个应用程序,这是一个只需要做一次的工作,为了对于你的可记录的错误得到有效的告警。
你可以继续创建一个更加复杂的告警系统,基于特定错误触发的告警。当错误发生时,告警系统选择涵盖这个错误的告警,而不是触发一个错误类型。
如果你指定错误号码,你可以相应特定的事件,例如:
你尝试查询一个虚拟表DBLog,而没有sysadmin固定服务器角色的成员或db_owner固定数据角色(9010)。错误的完整列表,在master.sysmessages中,壮观的,通过文档快速浏览到七千多事件,确认的是对于每个错误添加一个告警将是不可能的,查看定位(SQL Server 2000)系统错误消息。
通常,你想指定哪个数据为告警相应的事件的源,而不是接受任何事件。你甚至可以指定错误必须包含特定的字符串,例如用户相关的可疑活动。(这会是有用的,对于搜索消息像在数据库CreditCardDetails中服务器用户Phil_Factor不是一个有效的用户)
有时,事件会被一个时间段内反复触发。在这种情况下,你想知道发生了什么,但是又不想每个事件触发一次告警。为了避免获得重复消息,你可以在告警相应事件后指定一个延迟,SQL Server代理在再次相应前等待指定的延迟,无论是否事件在延迟期间发生。你也可以以编程方式禁用、重新启用一个告警。
记录错误日志
SQL Server代理从错误日志获得信息,因此错误首先必须被记录。没有方法给没有记录的错误添加告警。所有的错误消息使用安全级别从19到25被自动写入到错误日志中。
当你想记录信息类消息,或者低安全级消息呢?如果你想对任何安全级小于19的错误拥有告警,你必须修改它们在sysmessages表中的入口,设置为总是被记录。你可以使用带有WITH_LOG选项的sp_alterMessage来设置dLevel列为128。如果消息被修改为WITH_LOG,随后将会被写入应用程序日志,而错误发生。即使不带WITH LOG选项执行RAISERROR,你已经修改的错误被写入应用程序日志,因此被告警发现。有很多想去这样做的原因,因为它会记录日志,可选的发送告警,语法错误正常情况下只被最终用户看到。
你可以通过编程方式强制任何错误触发,使用带有WITH LOG参数的RAISERROR命令写入到错误日志。所以,对于用户定义的错误安全级别(9),你可以记录一个事件,触发告警被**,依次发电子邮件给某人,或运行一个作业,只需简单使用RAISERROR。通常,因为相应告警的作业可以被代理以不同的用户运行,你不需要分配不安全的权限给普通用户。你可以使用xp_LogEvent,可能不想这个用户看到错误。(只有Raiserror调用可以在错误消息中利用“Print”格式占位符,使用xp_logevent记录格式化消息到错误日志,以消息、字符串格式标识符等)
错误安全级别
更高安全级别的错误你需要了解的更多,尤其是用户在应用程序中发现一条可怕的消息时打电话给你。
安全级别提供了最好的方式,创建一个多方面的告警系统,对于通常问题增补了特定的告警,例如TempDB运行空间不足。
安全级别10到16
通常是用户错误产生的,用户执行TSQL脚本和存储过程的问题。大量的编程错误和输入问题可触发这类错误。问题是它们没有记录下来,通常不可能别记录下来。
安全级别17(资源不足)和18(非致命内部错误被检测到)
被资源或系统错误产生;用户会话没有中断。
安全级别从17到19
需要DBA注意,通过执行DBCC CHECKDB(database)获得更多信息,发现更多关于盘区损坏。安全级别19(SQL Server资源错误)将会停止当前的批处理。
安全级别20(在当前进程中的SQL Server致命错误),21(在数据库dbid进程中的SQL Server致命错误),22(SQL Server致命错误可疑的表完整性),23(SQL Server致命错误可疑的数据库完整性),24(硬件错误)和25
表明了系统问题。安全级别20或更高级别的错误消息被认为是致命错误,并结束客户端连接。这段错误消息会影响数据库中的所有进程,也许表明数据库或对象已经损坏。这些错误对于此时运行的进程是致命的。进程将会记录诊断信息,然后终止。
标记:从告警到作业间传递信息
标记对于创建告警系统是十分重要的。如果你使用一个告警触发作业,将会有大量有用的信息传递给作业,被用于传递信息给准备处理问题的系统。
这些信息以宏或标记的方式提供给作业。除了WMI标记,其他已经从SQL代理7.0和2000就已经有了。因为这些标记并不出名,我会列出它们:
|
标记 |
描述 |
|
(A-DBN) |
数据库名称以宏的形式从告警传递给作业 |
|
(A-SVR) |
服务器名称以宏的形式从告警传递给作业 |
|
(A-ERR) |
错误号码以宏的形式从告警传递给作业 |
|
(A-SEV) |
错误安全级别以宏的形式从告警传递给作业 |
|
(A-MSG) |
消息文本以宏的形式从告警传递给作业(它将包含错误号码和安全级别作为字符串) |
|
(DATE) |
当前日期(以YYYYMMDD格式) |
|
(INST) |
实例名。对于默认实例,标记为空。 |
|
(JOBID) |
作业ID |
|
(MACH) |
计算机名 |
|
(MSSA) |
主SQLServerAgent服务名 |
|
(OSCMD) |
用于运行CmdExec作业步骤的应用程序前缀 |
|
(SQLDIR) |
SQL Server安装的目录。(默认值为C:\Program Files\Microsoft SQL Server\MSSQL) |
|
(STEPCT) |
步骤计数:执行步骤的计数(不包括重试)。(可被步骤命令用于强制终止一个多步骤循环) |
|
(STEPID) |
步骤ID |
|
(SRVR) |
服务器。运行SQL Server的计算机名。如果SQL Server实例是一个命名实例,它包含实例名。它可以不同于事件源的服务器。 |
|
(TIME) |
当前时间(以HHMMSS格式)。 |
|
(STRTTM) |
作业开始执行的时间(以HHMMSS格式)。 |
|
(STRTDT) |
作业开始执行的日期(以YYYYMMDD格式)。 |
|
(WMI(property)) |
WMI属性。运行作业响应WMI告警,属性值被property指定。例如,$(WMI(DatabaseName))对于触发告警运行的WMI事件提供了DatabaseName属性的值。 |
标记像传统的宏一样,在作业步骤执行之前,在运行时被替换。不幸的是,它们是大小写敏感的,如果括号内有空格会产生无法解释的错误。它们需要小心处理,如果没有意识到这一点,它们会在你的代码中导致非故意的混乱。调试“PrintF”格式非常困难。我通常将宏替换结果记录到表中,在作为SQL执行它们之前,只是检查它们是完好的。
因为标记是字符串,你需要使用特定的宏来确保它们执行。实际上,你现在必须使用它们即使你认为不需要它们。这就是为什么提供了ESCAPE_NONE宏。
SQL Server代理转义宏
|
转义宏 |
描述 |
|
$(ESCAPE_SQUOTE(token_name)) |
在标记替换字符串中转义单引号。替换一个单引号为两个单引号。 |
|
$(ESCAPE_DQUOTE(token_name)) |
在标记替换字符串中转义双引号。替换一个双引号为两个双引号。 |
|
$(ESCAPE_RBRACKET(token_name)) |
在标记替换字符串中转义右中括号。替换一个右中括号为两个右中括号。 |
|
$(ESCAPE_NONE(token_name)) |
在字符串中不用转义任何字符替换标记。宏被提供支持向后兼容性环境,当标记替换字符串只被信任用户使用。对于更多信息,查看“更新作业步骤使用宏”在这个主题的后面。 |
警告:在SQL Server 2005,这些标记因为安全原因被禁用。在你使用这些标记之前,你必须启用它们,通过在对象浏览器中右键SQL Server代理,选择属性,在告警系统页,选择“对于所有的作业替换标记相应告警”。
在SQL Server 2005,SQL Server代理作业步骤标记语法已经改变。现在,一个转义宏必需伴随所有的标记使用在作业步骤中,否则这些作业步骤将会失败(查看http://msdn2.microsoft.com/en-us/library/ms175575.aspx)。因此最好使用转义宏写所有的标记以向后兼容。一个示例应该更加清晰。
这里是一个作业步骤,从SQL Server事件写任何错误传递给它,包含完整的错误文本、安全级别和错误号码,因此你可以将它放到数据库应用程序的自己私有日志中。你会看到它也包含数据库和服务器,你只需聚合这些消息到企业级报表中。
|
1
2
|
INSERT INTO activityLog (TYPE,logstring,comment)
SELECT 204,'SQLServerError','on database: $(ESCAPE_SQUOTE(A-DBN)), Server: $(ESCAPE_SQUOTE(A-SVR)): $(ESCAPE_SQUOTE(A-MSG))
|
SQL Server性能告警
不仅仅是错误和事件可以触发告警。你也可以指定一个特定的性能条件来触发告警。在这种情况下,你指定哪个性能指标告警应该监控,一个告警阈值,和计数器的行为将会触发告警。为了定义个性能告警,在SSMS中,你可以设置:
-
“Object”或者用于监控性能度量的类型。
-
“Counter”或者用于监控度量的属性。
-
特定的“instance”(如果有)用于监控的属性。
-
告警的阈值(一个数字)。
-
产生告警的行为(例如:“falls below”、“becomes equal to”或者“rises above”一个数字,对于特定的性能条件计数器)。
例如,如果你想设置告警发生在“SQL Server:Locks”(object),当Lock Requests/sec(counter),从锁管理器请求的每秒新锁和锁转换数量,超过10,你将会选择“rises above”(behaviour)并设置值为10(threshold)。
你可能想去设置告警发生,当“SQL Server:Transactions”(object),“Free Space in TempDB(kb)”(counter)“falls below”(behaviour)200(threshold),你会看到这个结果,像使用临时表的慢查询进程或一个创建多个永久临时表的进程(查看这出色的定位在tempdb中磁盘空间不足)
另一个明显的告警是错误的警告被写入错误日志。这使用SQL Server:SQL Errors对象、Errors/Sec计数器和User Errors实例。这将对所有的SQL Server错误触发一个告警。
有大量的“object”性能告警可以被设置:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
SQLServer:Access MethodsSQLServer:Backup DeviceSQLServer:Broker ActivationSQLServer:Broker StatisticsSQLServer:Broker / DBM TransportSQLServer:Buffer ManagerSQLServer:Buffer NodeSQLServer:Buffer PartitionSQLServer: Catalog MetadataSQLServer:CLRSQLServer:Cursor Manager by TypeSQLServer:Cursor Manager TotalSQLServer:Database MirroringSQLServer:DatabasesSQLServer:ExecStatisticsSQLServer:General StatisticsSQLServer:LatchesSQLServer:LocksSQLServer:Memory ManagerSQLServer:Plan CacheSQLServer:SQL ErrorsSQLServer:SQL StatisticsSQLServer:TransactionsSQLServer:User SettableSQLServer:Wait Statistics |
这些对象的独立计数器太多无法列完整。如果你只选择这些对象中的一个(SQL Server:General Statistics)将会看到:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
Counters for Active Temp TablesEvent Notifications Delayed DropHTTP Authenticated RequestsLogical ConnectionsLogins/secLogouts/secMars DeadlocksNon-atomic yield rateProcesses blockedSOAP Empty RequestsSOAP Method InvocationsSOAP Session Initiate RequestsSOAP Session Terminate RequestsSOAP SQL RequestsSOAP WSDL RequestsTemp Tables Creation RateTemp Tables For DestructionTrace Event Notifications QueueTransactionsUser Connections |
面对各种各样的可用于触发告警的事件计数器,已经只能参阅联机帮助文档。请放心,对于每个可能或不可能的条件都有计数器。
一些告警的奇怪行为表现为,甚至当计数器不再在特定的级别,告警常常同步触发(每二十分钟)。我禁用了该预防措施,然后启用了在相关作业的计数器。通过文档排查非常困难,我很好奇为什么会发生。
Windows Management Instrumentation告警
WMI告警比之前的类型提供更多的信息。请放心,你需要大量的时间让WMI告警工作。现在不是怯懦的时候。
在SQL Server 2005中,SQL Server代理在Windows Management Instrumentation(WMI)事件发生时触发告警。SQL Server代理会相应SQL Server WMI事件,也相应被操作系统和其他WMI提供者触发的WMI事件。SQL代理甚至被认为能够相应远程WMI事件,但是微软不鼓励。
有大量的WMI变量可用于告警。这些被文档化为“跟踪事件用于事件提醒”。这些WMI变量是代理用于访问WMI标记的机制。
为了创建一个WMI告警,你必须指定用于查询事件的WMI命名空间。每个SQL Server 2005实例有它自己的WMI命名空间,默认是:
\\.\root\Microsoft\SqlServer\ServerEvents\instance_name
在默认的SQL Server安装中instance_name默认是MSSQLSERVER。
为了创建一个WMI事件,你需要指定使用的WMI变量。WMI变量被多样的SQL语法叫做“Windows Management Instrumentation Query Language”(WQL)所访问。SQL Server代理提交了一个WQL请求,收到WMI事件,运行作业相应事件。一些Service Broker对象专注于处理提醒消息,而WMI事件提供者处理创建和管理这些对象的细节。因为基础上使用了Service Broker,在希望SQL Server代理收到WMI事件之前,你必须在msdb和你监控的数据库**它。
一个WQL查询参照事件来配置WMI告警,使用“SELECT * FROM <my_event>”语法。为了起作用,通过勾选相应的复选框来配置SQL Server代理为“对于相应告警的所有作业替换标记”(微软说这是一个安全警示)。
SQL Server代理在作业步骤命令的运行时解析和替换字符串、输出文件,使用标记告警。在SQL Server 2005中语法从“[X]”修改为“$(X)”,X是标记名。结果,标记名不再与存在的数据库对象冲突。(查看Microsoft SQL Server 2005中SQL Server代理的新特性)也必须对WMI标记使用宏,文档地址http://support.microsoft.com/kb/915845/en-us。
一堆日志
SQL Server错误日志
这是SQL Server从Sybase变种来的原始日志。以及事件、SQL Server启动条件、备份和恢复操作的结果、自动化恢复消息、内核消息、用户连接的错误、服务器级别错误消息、批处理命令结果,或者其他命令和进程写入到SQL Server错误日志。SQL Server错误日志输出为ASCII文件位于…Program Files\Microsoft SQL Server\MSSQL.n\MSSQL\LOG\ERRORLOG和ERRORLOG.n文件。
新错误日志在SQL Server实例启动的时候创建,而sp_cycle_errorlog系统存储过程可以用于循环利用错误日志文件而不用重启SQL Server实例。典型的,SQL Server保留之前六个日志文件的备份,最新的日志文件扩展名为.1,第二新的扩展名为.2,等等。当前的错误日志没有扩展名。在错误日志中的错误也复制在应用程序事件日志中。关于任何自动恢复策略的消息试图写入到SQL Server错误日志。
SQL Server代理错误日志
SQL Server代理有它自己的错误日志。记录着有关潜在问题的警告和错误,像“Job <job_name> was deleted while it was running.”或者“Unable to start mail session.”错误消息被作为提醒发送。
SQL Server维护多达九个SQL Server代理错误日志。每个归档日志有一个表名日志相对时间的扩展名。例如,扩展名.1表示最新的归档错误日志,扩展名.9表示最老的归档错误日志。
像SQL Server错误日志一样,SQL Server代理错误日志在服务器上存储为文本文件。通常在SQL Server实例的代码安装的目录下的\MSSQL\Log子目录下。
SQL Server启动日志
SQL Server 2005启动日志通常位于%ProgramFiles%\Microsoft SQL Server\90\Setup Bootstrap\Log\Summary.txt。SQL Server启动日志会显示组件失败,以及在组件日志中的细节,位于%ProgramFiles\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files目录。
SQL Server代理服务历史日志
所有作业的进展和结果存储在系统表msdb中。这些也包含任何错误的描述,因此应该被监控。
应用程序事件日志
SQL Server也可以用于写入应用程序事件日志,任何应用程序产生的系统日志写入到应用程序日志中。Windows应用程序日志提供了发生在Windows操作系统的事件的完整图谱,因为它们是系统和应用程序错误的通用存储库。所有的写入到SQL Server错误日志的错误默认复制到应用程序日志。这是非常有用的,因为事件查看器可以远程访问日志,在企业级系统允许集中化错误处理。
安全事件日志
因为用户连接问题时常位于Windows NT安全系统,DBA需要检查它。当访问特定资源的SQL Server报表被禁用时,这些问题通常很容易被识别。
系统事件日志
SQL Server问题可以被其他服务的失败所导致,这些被记录在系统事件日志中。
告警陷阱
1. 是否SQL Server代理服务启动帐号有足够的权限去做你想做的?
2. 是否告警被启动?
3. 是否SQL Server代理服务正在运行?
4. 是否事件出现在事件日志中?如果没有,使用sp_altermessage强制记录日志。
5. 如果你使用xp_logevent触发事件,注意xp_logevent不会触发告警,除非告警的@database_name设置为’master’或NULL。
6. 告警上次什么时候工作?检查告警的历史值决定告警工作的最后日期。
7. 是否计数器的值维持至少20秒?
8. 如果事情不像期待的那样工作,检查SQL Server错误日志,作业历史和SQL Server代理错误日志。
9. 是否正确指定了消息接收者?
10. 是否在作业步骤之间切换了标记的使用?(见上面)
11. 是否将你的标记包含在转义宏中?(见上面)
12. 在WMI管理应用程序来源的客户端,一个SQL Server实例上的Windows验证登录或组指定在应用程序的连接字符串中?
13. 是否调用应用程序在数据库上分配了正确的权限,用于创建需要的事件提醒?
14. 是否在使用WMI告警之前**了Service Broker?使用如下语句来检查:
|
1
|
SELECT name, is_broker_enabled, service_broker_guid FROM sys.databases;
|