上節回顧:http://www.javashuo.com/article/p-kivzmehu-k.htmlhtml
腳本示意:https://github.com/lotapp/BaseCode/tree/master/database/SQL/SQLServernode
PS:這些腳本都是我之前用SQLServer手寫的,參考便可(如今用MySQL,下次也整理一下)git
以前寫SQLServer監控系列文章由於換環境斷篇了,只是簡單演示了下基礎功能,如今準備寫MySQL
監控相關內容了,因而補了下:github
SQLServer性能優化之---數據庫級日記監控:http://www.javashuo.com/article/p-nnywaxsf-da.htmlsql
在說監控前你能夠先看下數據庫發郵件:http://www.javashuo.com/article/p-btuevyov-gn.html數據庫
應用:通常就是設置個定時任務,把耗時SQL信息或者錯誤信息經過郵件的方式及時預警性能優化
好處就太多了,eg:客戶出錯若是是數據庫層面,那瞬間就能夠場景重放(PS:等客戶找會下降業績)服務器
以往都是程序的try
+catch
來捕獲錯誤,但數據庫定時任務之類的出錯程序是捕獲不到的,因此就須要數據庫層面的監控了session
PS:開發的時候經過
SQLServer Profiler
來監控架構
先說說本質吧:SQLServer2012的XEVENT機制已經完善,eg:經常使用的擴展事件error_reported
就能夠在錯誤的時候經過郵件來通知管理員了
PS:擴展事件性能較高,並且比較輕量級
PS:SQLServer的監控大致思路三步走:發郵件
,事件監控
,定時執行
這個以前講過,這邊就再說下SQL的方式:
這個配置一次便可,之後使用就能夠直接經過配置名發郵件:
--開啓發郵件功能 exec sp_configure 'show advanced options',1 reconfigure with override go exec sp_configure 'database mail xps',1 reconfigure with override go --建立郵件賬戶信息 exec msdb.dbo.sysmail_add_account_sp @account_name ='dunitian', -- 郵件賬戶名稱 @email_address ='xxx@163.com', -- 發件人郵件地址 @display_name ='SQLServer2014_192.168.36.250', -- 發件人姓名 @MAILSERVER_NAME = 'smtp.163.com', -- 郵件服務器地址 @PORT =25, -- 郵件服務器端口 @USERNAME = 'xxx@163.com', -- 用戶名 @PASSWORD = '郵件密碼或受權碼' -- 密碼(受權碼) GO --數據庫配置文件 exec msdb.dbo.sysmail_add_profile_sp @profile_name = 'SQLServer_DotNetCrazy', -- 配置名稱 @description = '數據庫郵件配置文件' -- 配置描述 go --用戶和郵件配置文件相關聯 exec msdb.dbo.sysmail_add_profileaccount_sp @profile_name = 'SQLServer_DotNetCrazy', -- 配置名稱 @account_name = 'dunitian', -- 郵件賬戶名稱 @sequence_number = 1 -- account 在 profile 中順序(默認是1) go
一樣我只演示SQL的方式,圖形化的方式能夠看我之前寫的文章:
-- 發郵件測試 exec msdb.dbo.sp_send_dbmail @profile_name = 'SQLServer_DotNetCrazy', --配置名稱 @recipients = 'xxx@qq.com', --收件郵箱 @body_format = 'HTML', --內容格式 @subject = '文章標題', --文章標題 @body = '郵件內容<br/><h2>This is Test</h2>...' --郵件內容
效果:
主要用途其實就是出錯排查:
-- 查詢相關 select * from msdb.dbo.sysmail_allitems --查看全部郵件消息 select * from msdb.dbo.sysmail_mailitems --查看郵件消息(更多列) select * from msdb.dbo.sysmail_sentitems --查看已發送的消息 select * from msdb.dbo.sysmail_faileditems --失敗狀態的消息 select * from msdb.dbo.sysmail_unsentitems --看未發送的消息 select * from msdb.dbo.sysmail_event_log --查看記錄日記
會了郵件的發送,那下面就是監控了
不推薦使用圖形化的方式,但能夠來理解擴展事件的監控
1.新建一個會話嚮導(熟悉後能夠直接新建會話)
2.設置須要捕獲的擴展事件
3.這邊捕獲的全局字段和左邊SQL是同樣的(截圖全太麻煩了,因此偷個懶,後面會說怎麼生成左邊的核心SQL)
4.本身根據服務器性能設置一個合理的值(IO、內存、CPU)
5.生成核心SQL(咱們圖形化的目的就是生成核心SQL,後面能夠根據這個SQL本身擴展)
6.核心代碼以下
7.啓動會話後一個簡單的擴展事件監控就有了
8.SQLServer提供了查看方式
9.日誌能夠本身查下xxx\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Log
上面只是過家家,主要目的就是讓你們知道核心SQL是怎麼來的,憑什麼這麼寫
下面就來個制定化監控:
先截圖演示下各個核心點,而後貼一個我封裝的存儲過程附件
1.擴展事件相關的核心代碼
2.內存中數據存儲到臨時表
3.臨時表中的數據存儲到本身創建的表中
我拋一個課後小問給你們:爲何先存儲在臨時表中?(提示:效率)
4.發送監控提醒的郵件
5.看看數據庫層面多了什麼:
6.來個測試
7.效果(能夠本身美化)
-- 切換到須要監控的數據庫 USE [dotnetcrazy] GO --收集服務器上邏輯錯誤的信息 SET QUOTED_IDENTIFIER ON SET ANSI_NULLS ON GO -- 自定義的錯誤信息表 IF OBJECT_ID('log_error_message') IS NULL BEGIN CREATE TABLE [dbo].[log_error_message] ( [login_message_id] [uniqueidentifier] NULL CONSTRAINT [DF__PerfLogic__Login__7ACA4E21] DEFAULT (newid()), [start_time] [datetime] NULL, [database_name] [nvarchar] (128) COLLATE Chinese_PRC_CI_AS NULL, [message] [nvarchar] (max) COLLATE Chinese_PRC_CI_AS NULL, [sql_text] [nvarchar] (max) COLLATE Chinese_PRC_CI_AS NULL, [alltext] [nvarchar] (max) COLLATE Chinese_PRC_CI_AS NULL, -- [worker_address] [nvarchar] (1000) COLLATE Chinese_PRC_CI_AS NULL, [username] [nvarchar] (1000) COLLATE Chinese_PRC_CI_AS NULL, [client_hostname] [nvarchar] (1000) COLLATE Chinese_PRC_CI_AS NULL, [client_app_name] [nvarchar] (1000) COLLATE Chinese_PRC_CI_AS NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] END GO -- 建立存儲過程 CREATE PROCEDURE [dbo].[event_error_monitor] AS IF NOT EXISTS( SELECT 1 FROM sys.dm_xe_sessions dxs(NOLOCK) WHERE name = 'event_error_monitor') -- 不存在就建立EVENT -- 建立擴展事件,並把數據放入內存中 BEGIN CREATE EVENT session event_error_monitor on server ADD EVENT sqlserver.error_reported -- error_reported擴展事件 ( ACTION -- 返回結果 ( sqlserver.session_id, -- 會話id sqlserver.plan_handle, -- 計劃句柄,可用於檢索圖形計劃 sqlserver.tsql_stack, -- T-SQ堆棧信息 package0.callstack, -- 當前調用堆棧 sqlserver.sql_text, -- 遇到錯誤的SQL查詢 sqlserver.username, -- 用戶名 sqlserver.client_app_name, -- 客戶端應用程序名稱 sqlserver.client_hostname, -- 客戶端主機名 -- sqlos.worker_address, -- 當前任務執行時間 sqlserver.database_name -- 當前數據庫名稱 ) WHERE severity >= 11 AND Severity <=16 -- 指定用戶級錯誤 ) ADD TARGET package0.ring_buffer -- 臨時放入內存中 WITH (max_dispatch_latency=1seconds) -- 啓動監控事件 ALTER EVENT SESSION event_error_monitor on server state = START END ELSE -- 存儲過程已經存在就把數據插入表中 BEGIN -- 將內存中已經收集到的錯誤信息轉存到臨時表中(方便處理) SELECT DATEADD(hh, DATEDIFF(hh, GETUTCDATE(), CURRENT_TIMESTAMP), n.value('(event/@timestamp)[1]', 'datetime2')) AS [timestamp], n.value('(event/action[@name="database_name"]/value)[1]', 'nvarchar(128)') AS [database_name], n.value('(event/action[@name="sql_text"]/value)[1]', 'nvarchar(max)') AS [sql_text], n.value('(event/data[@name="message"]/value)[1]', 'nvarchar(max)') AS [message], n.value('(event/action[@name="username"]/value)[1]', 'nvarchar(max)') AS [username], n.value('(event/action[@name="client_hostname"]/value)[1]', 'nvarchar(max)') AS [client_hostname], n.value('(event/action[@name="client_app_name"]/value)[1]', 'nvarchar(max)') AS [client_app_name], n.value('(event/action[@name="tsql_stack"]/value/frames/frame/@handle)[1]', 'varchar(max)') AS [tsql_stack], n.value('(event/action[@name="tsql_stack"]/value/frames/frame/@offsetStart)[1]', 'int') AS [statement_start_offset], n.value('(event/action[@name="tsql_stack"]/value/frames/frame/@offsetEnd)[1]', 'int') AS [statement_end_offset] into #error_monitor -- 臨時表 FROM ( SELECT td.query('.') as n FROM ( SELECT CAST(target_data AS XML) as target_data FROM sys.dm_xe_sessions AS s JOIN sys.dm_xe_session_targets AS t ON t.event_session_address = s.address WHERE s.name = 'event_error_monitor' --AND t.target_name = 'ring_buffer' ) AS sub CROSS APPLY target_data.nodes('RingBufferTarget/event') AS q(td) ) as TAB -- 把數據存儲到本身新建的表中(有SQL語句的直接插入到表中) INSERT INTO log_error_message(start_time,database_name,message,sql_text,alltext,username,client_hostname,client_app_name) SELECT TIMESTAMP,database_name,[message],sql_text,'',username,client_hostname,client_app_name FROM #error_monitor as a WHERE a.sql_text != '' --AND client_app_name !='Microsoft SQL Server Management Studio - 查詢' AND a.MESSAGE NOT LIKE '找不到會話句柄%' AND a.MESSAGE NOT LIKE '%SqlQueryNotification%' --排除server broker AND a.MESSAGE NOT LIKE '遠程服務已刪除%' -- 插入應用執行信息(沒有SQL的語句經過句柄查詢下SQL) INSERT INTO log_error_message(start_time,database_name,message,sql_text,alltext,username,client_hostname,client_app_name) SELECT TIMESTAMP,database_name,[message], SUBSTRING(qt.text,a.statement_start_offset/2+1, (case when a.statement_end_offset = -1 then DATALENGTH(qt.text) else a.statement_end_offset end -a.statement_start_offset)/2 + 1) sql_text,qt.text alltext, username,client_hostname,client_app_name FROM #error_monitor as a CROSS APPLY sys.dm_exec_sql_text(CONVERT(VARBINARY(max),a.tsql_stack,1)) qt -- 經過句柄查詢具體的SQL語句 WHERE a.sql_text IS NULL AND tsql_stack != '' --AND client_app_name = '.Net SqlClient Data Provider' DROP TABLE #error_monitor -- 刪除臨時表 --重啓清空 ALTER EVENT SESSION event_error_monitor ON SERVER STATE = STOP ALTER EVENT SESSION event_error_monitor on server state = START END -- 美化版預警郵箱 DECLARE @body_html VARCHAR(max) set @body_html = '<table style="width:100%" cellspacing="0"><tr><td colspan="6" align="center" style="font-weight:bold;color:red">數據庫錯誤監控</td></tr>' set @body_html = @body_html + '<tr style="text-align: left;"><th>運行時間</th><th>數據庫</th><th>發生錯誤的SQL語句</th><th>消息</th><th>用戶名</th><th>應用</th><th>應用程序名</th></tr>' -- 格式處理(沒內容就空格填充) select @body_html = @body_html + '<tr><td>' + case (isnull(start_time, '')) when '' then ' ' else convert(varchar(20), start_time, 120) end + '</td><td>' + case (isnull(database_name, '')) when '' then ' ' else database_name end + '</td><td>' + case (isnull(sql_text, '')) when '' then ' ' else sql_text end + '</td><td>' + case (isnull(message, '')) when '' then ' ' else message end + '</td><td>' + case (isnull(username, '')) when '' then ' ' else username end + '</td><td>' + case (isnull(client_hostname, '')) when '' then ' ' else client_hostname end + '</td><td>' + case (isnull(client_app_name, '')) when '' then ' ' else client_app_name end + '</td></tr>' from ( select start_time, database_name,sql_text, message, username, client_hostname, client_app_name from [dbo].[log_error_message] where start_time >= dateadd(hh,-2,getdate()) -- 當前時間 - 定時任務的時間間隔(2h) and client_app_name != 'Microsoft SQL Server Management Studio - 查詢' -- and client_hostname in('') ) as temp_message set @body_html= @body_html+'</table>' -- 發送警告郵件 exec msdb.dbo.sp_send_dbmail @profile_name = 'SQLServer_DotNetCrazy', --配置名稱 @recipients = 'xxxxx@qq.com', --收件郵箱 @body_format = 'HTML', --內容格式 @subject = '數據庫監控通知', --文章標題 @body = @body_html --郵件內容 go
下節預估:定時任務、完整版監控
PS:估計先得更八字的文章(拖過久)而後更完SQLServer更MySQL,等MySQL監控更完會說下備份與恢復,接着咱們開架構篇(MyCat系列先不講放在Redis和爬蟲系列的後面)
晚點在下面補上