我們如何做SQL監控
對于SQL,我們一般都說SQL審計,SQL優化,很少談SQL監控。確實也是,SQL是很難監控的,因為一個復雜的系統中,每天SQL的執行次數高達千萬級別,甚至數十數百億,執行不同SQL的數量也可能高達數萬數十萬。如果大量的SQL是動態生成的或者沒有使用綁定變量,那么可能在幾分鐘內就有數萬條不同的SQL在執行。
在這樣的情況下,如果我們需要開發一個通用性的產品用于做SQL監控是十分困難的。當然如果我們的業務系統相對比較穩定,需要監控的SQL數量相對穩定,針對這些SQL做針對性的監控也是比較容易實現的。而事實上,對于大多數企業來說,我們需要監控的數據庫系統有上百甚至上千套,業務系統也在不斷發生變更,在這種環境下,要實現通用的SQL監控確實還是有難度的。
對于DBA來說,也會有一定的SQL語句監控的需求,也都會掌握一些SQL語句監控與分析的技巧。對于Oracle數據庫的DBA來說,我們已經十分習慣于通過AWR報告的TOP SQL相關內容來分析SQL的運行情況,發現存在問題的SQL。不過這種分析只能算SQL優化,而無法稱之為SQL監控。
今天我們來探討一下SQL監控的問題,隨著硬件、云平臺、數據庫技術以及應用架構的不斷優化演進,一些完全因為硬件資源或者數據庫配置等引發的數據庫問題的比例相對較少了,而因為SQL引發的問題在運維中的占比越來越高。對于SQL的監控需求是一直存在的,而且需求的種類也五花八門。前陣子有個客戶提出需要了解隨意一條SQL在某個時間段內的精確執行次數,問我們的D-SMART是否支持。另外一個客戶問我D-SMART是否支持對任意一條SQL的執行計劃變化進行跟蹤,發現問題及時報警。
實際上SQL監控的目的依然是及時發現系統可能存在的風險。我和第一個朋友聊了聊他需要做如此精確的監控的目的是什么,他也說不出一個所以然來。實際上這個需求最好從應用的角度去做,在應用系統的模塊中通過鉤子進行統計的成本是最低的,從數據庫去做可能成本太高。如果要從數據庫的角度去統計,其精準度就要大打折扣了,因為數據庫的內存中保存的SQL統計信息并不完整,因此我們去采樣的時候會有誤差。當某條SQL有一定時間沒有執行的時候,很可能會從內存統計緩沖區中被清除,下一次再出現的是可能從頭統計了。目前我們的TOP SQL采集工作也是5分鐘進行一次,對這段時間內比較活躍的SQL進行一次統計。因為大型系統中的SQL數量可能會十分龐大,為了避免給生產系統帶來太大的負載,這種采集也必然是輕量級的,只采集一些十分重要的TOP SQL的詳細信息。
至于第二個需求,如果我們要對全量的SQL進行執行計劃的跟蹤,那肯定是不現實的,如果系統中存在幾萬條SQL,幾十萬個執行計劃,采集一次的成本開銷之大,對于一些并發量較高,并且業務對SQL執行延時的穩定性要求較高的系統來說,是無法承受的。
Oracle數據庫的SQL語句都是存儲于共享內存的CURSOR結構中的,而不少開源、國產數據庫并不使用全局共享CURSOR的方式,CURSOR僅在會話內共享。因此采集SQL語句與執行計劃的接口并不十分完善,有些數據庫甚至還要開啟一些特殊的跟蹤功能才能實現。針對不同的數據庫產品,我們需要采取不同的手段來采集TOP SQL,因此SQL監控的實現方式還是需要仔細去設計的。
另外一點,我們做SQL監控的目的并不是SQL監控本身,SQL監控的目標是防止SQL出現異常,從而導致數據庫系統出現問題。因此我們不能把SQL監控當初目標,而是把SQL監控當成一種手段和方法。因此在一個系統中,監控某個時間段內某條SQL的精確執行次數在絕大多數場景中沒有任何意義,我們只需要知道某些可能影響系統的SQL語句的大致執行數量、平均每次執行的開銷以及執行次數與開銷的歷史波動情況,就足以支撐我們所需要的運維分析場景了。
而某條SQL語句的執行計劃發生了變化,如果其執行成本并無增加,對數據庫的穩定運行并無太大的影響,那么這種變化我們也無需實時發現,只要在定期的審計中有所發現,并能夠分析出其存在的潛在風險就可以了。而因為執行計劃的變化而導致了系統負載過高,系統性能下降,那么我們從其他一些方面也可以觀察到。我們利用數據庫可觀測性的一些其他側面能夠發現此類問題就可以了。比如我們可以通過整個系統的邏輯讀/物理的突然增加,CPU使用率的增加,活躍會話數的增加等相對容易觀察到,并且監控成本比較低的可觀測性指標也能夠發現因為SQL執行計劃變壞導致的問題,并能夠通過分析定位,快速發現是因為SQL執行計劃變壞導致了該問題。那么我們也就能解決這個問題了。
比如說在D-SMART中采用了關鍵SQL平均邏輯讀突增與每秒邏輯讀數量超出正常水平等兩種方式來發現相關的問題。我們以關鍵SQL平均邏輯讀突然增加的告警來看看D-SMART是如何分析這個問題的。
從SQL的歷史分析上看,確實出現了平均每次邏輯讀突變的情況。我們再來看看SQL的執行計劃,是不是出現了多個執行計劃。
從分析上看,確實出現了兩個不同子游標,其中一個游標的執行成本明顯大于另外一個。正是因為這個問題,導致了剛才那個告警的出現。這種方式是針對關鍵SQL的,關鍵SQL是一個系統中對應用可用性或者SLA有著關鍵影響的SQL,我們可以在每個采樣周期都對其進行監控。因為一個系統中的關鍵SQL的數量不會很大,因此這種專項監控的成本也不高。
而如果出問題的并不是關鍵SQL,而是隨便哪一條SQL,突然因為統計信息不準確或者說表數據量的變化,亦或是系統變更后出現了應用的BUG,從而引起了執行計劃的變化,進而導致了系統資源不足,引起關鍵SQL因為系統資源不足(內存,CPU,IO等)而引發了性能問題。這種情況也是十分常見的。如果這條SQL出問題還沒有觸發系統資源不足,從而導致核心業務故障,那么這個問題并不一定需要馬上被捕捉到,并且進行處置。
只需要在定期的SQL審計(比如每周)中發現這個問題,就完全可以解決。如果比較嚴重了,可能會導致系統故障,那么我們還是需要盡可能早的捕獲到此類問題。在D-SMART中我們針對邏輯讀突增、物理讀突增、R隊列突增、活躍會話數突增、同一條SQL的并發執行量達到某個閾值(此類SQL執行計劃異常后必然出現執行時間過長,如果對系統產生較大影響,則大概率會出現多個SQL同時執行的情況出現)等,都會產生告警。并且在這些告警中,都可有執行計劃發生變化的診斷路徑,可以用于根因溯源。這樣就采取了一種迂回策略,從一個側面解決了此類問題的預警問題。