如何構建日誌監控系統
有哪些資料型別會被監控
監控資料通常由幾種型別的資料組成:
· 日誌資料:豐富、詳細的文字和資料;
· 可以用於遙測的標籤資料;
· 執行狀況檢查資料;
· 來自應用程式的效能資料;
日誌資料
日誌資訊幾乎可以記錄攻擊者需要的任何東西,包括漏洞資訊、通訊資訊、電子郵件資訊等。不過要將這些資訊進行輸出,沒有一定的技術和付出是不可能的。首先,你需要為日誌記錄本身分配字串,比如記憶體和垃圾收集(適用於.NET和其他一些平臺)。當你在某處進行日誌記錄時,磁碟空間必定要執行。如果我們遍歷網路(在某種程度上是在本地),這也意味著頻寬和延遲。
日誌資料會記錄所有的事情。如果技術能力夠硬且付出一定的成本,你就能詳細檢視這些日誌,挖掘更多內容。所以聰明的人,會通過構建日誌記錄,記錄他們認為需要的內容。但這個構建過程並不容易,比如當出現問題時,你會發現有時新新增的功能沒有正確的日誌記錄。
至於日誌具體能記錄什麼?這取決於系統。在本文的示例中,我們使用StackExchange.Exceptional執行記錄操作,這是我維護的一個開源.NET的資料庫的中央異常日誌檢視器。這些異常日誌會記錄到SQL Server,然後通過應用程式或通過Opserver(Stack Overflow 的開源監控產品)檢視。
對於像Redis,Elasticsearch和SQL Server這樣的系統,我們只需使用內建的日誌記錄和日誌迴旋(Log Rotation)機制登入到本地磁碟。日誌迴旋(Log Rotation) 可以設定日誌的迴旋是基於檔案大小還是基於時間間隔。當滿足其中的一個條件時,當前訪問日誌被關閉,新的訪問日誌被建立。對於其他基於SNMP的系統,如network gear,我們可以將所有這些日誌轉發到Logstash叢集,Logstash 是開源的伺服器端資料處理管道,能夠同時從多個來源採集資料,轉換資料,然後將資料傳送到您最喜歡的 “儲存庫” 中。不過用Logstash之前,可以先用Kibana(一個開源的分析和視覺化平臺)查詢。 將日誌轉發到Logstash集群后,Bosun會在發出警報時,詢問其中的很多細節和趨勢,我們將在下文中深入探討。Bosun 是一個新型的監控和告警系統,由Stack Exchange團隊打造,使用golang編寫,支援定義複雜的告警規則,支援OpenTSDB、Graphite、Logstash-Elasticsearch 等資料來源。
用HAProxy構建日誌監控
HAProxy預設情況下並沒有啟用日誌功能,或者說已經啟用了但需配合日誌軟體方能有效。
在本文的示例中,我們還記錄了通過HAProxy(負載均衡器)的公共HTTP請求,不過其中只記錄了頂級域名,沒有cookie,沒有表單資料等。
在這些請求中,我們將使用某些特定的效能數字將標頭髮送到HAProxy, HAProxy會捕獲這些標頭並將這些標頭剝離到我們轉發的syslog行中,以便最後進行SQL處理。這些標頭包括:
·SQL Count(查詢);
· Redis Count(查詢命中次數);
· HTTP Count(傳送請求);
· Tag Engine Count (查詢);
· Elasticsearch Count(查詢命中);
利用這些查詢,我們可以輕鬆查詢和比較歷史資料。它在我們從未真正想過的方式中也很有用。例如,我們將看到一個請求和執行的SQL查詢計數,它將告訴我們使用者沿著程式碼路徑走了多遠。或者當SQL連線池堆積起來時,我們可以檢視特定時間內來自特定伺服器的所有請求,以檢視導致該爭用的原因。我們所做的就是跟蹤n個服務的通訊次數和時間。這個方法非常簡單,但也非常有效。
監控syslog並將其儲存為SQL的過程稱為流量處理服務(Traffic Processing Service),因為我們計劃在一天內傳送報告。
除了這些標頭之外,預設的HAProxy日誌行格式還有一些其他計時請求:
TR:客戶端向我們傳送請求所用的時間(在keepalive執行時相當無用);
Tw:排隊等待的時間;
Tc:等待連線到web伺服器的時間;
Tr:web伺服器完全呈現響應所花費的時間;
另一個簡單但重要的例子是,Tr和AspNetDurationMs報頭(一個計時器在請求的開始和結束時開始和結束)之間的增量,會告訴我們在作業系統中花費了多少時間,在IIS中等待執行緒等。
執行狀況檢查
在任何負載分配設定(例如一起工作的伺服器叢集或一組伺服器前面的負載均衡器)中,執行狀況檢查是一種檢視成員是否符合角色或任務的方法。例如,在Elasticsearch中,如果一個節點宕機後,當節點恢復執行時,再次執行此操作。在Web層中,負載均衡器將停止向下行節點發送流量,並繼續在執行流量節點之間進行操作。
在HAProxy中,我們使用了內建的執行狀況檢查和警告。截至2018年末,在我們編寫這篇文章時,仍用的是ASP.NET MVC5。一個重要的細節是我們的錯誤頁面是一個重定向的,例如出現/questions的時候,會定向到/error?aspxerrorpath=/questions。應該說這是舊.NET基礎結構的執行細節,但是當與HAProxy結合使用時,就成了問題。例如,如果你有:
server ny-web01 10.x.x.1:80 check
然後它將接受200-399個HTTP狀態碼響應(它只會發出一個HEAD請求),如果是400或500個HTTP狀態碼響應,則不會觸發執行,但我們的302重定向不會發生此情況。發生重定向後,瀏覽器將獲得5xx狀態程式碼,但HAProxy實際上不會這樣做。你可以在同一後端使用http-check expect 200(或任何狀態程式碼或範圍或正則表示式)來更改此設定,這意味著我們的執行檢查終端只允許200。
不同的應用程式因執行檢查端點而異,但對於stackoverflow.com,由於它是主頁,它會檢查我們可能無法檢查的事情,全面檢查很重要。我的意思是,如果使用者點選同一頁面,它會全面檢查嗎?,如果我們進行了執行檢查,資料庫和一些快取和理智檢查了我們知道需要聯機的大事,那就太棒了,就這樣了有總比沒有好。如果我們對資料庫和快取進行了執行檢查,檢查我們需要的大資料。但是,假設我們在程式碼中放入了一個漏洞,此時一個看起來並不重要的快取都沒有重新被正確載入,此時所有使用者都會呈現在頂欄。
我們還在資料庫內進行了執行檢查,最簡單的表現就是心跳(Heartbeat)程序的檢查。例如,StackExchange.Redis用於定期檢查與Redis的套接字連線是否處於執行狀態。我們會使用相同的方法來檢視套接字是否仍然開啟,並在Stack Overflow(一個與程式相關的IT技術問答網站)上利用WebSocket實現資料的實時推送。這是一種沒有在這裡大量使用的監控,但它確實被使用了。
其他執行檢查還包括標籤引擎伺服器,我們可以通過HAProxy來平衡負載(這會增加一個跳轉),但是讓每個Web層伺服器直接瞭解每個標籤伺服器對我們來說都是更好的選擇。我們可以監控的資訊如下:
1.選擇如何分配負載;
2.更容易測試新構建;
3.獲取每伺服器操作計數指標和效能資料;
我們可以通過一個簡單的“ping”命令進行執行狀況檢查,例如它最後一次在資料庫更新的時間。
所以,這可以保證對你的執行狀態的絕對監控。Microsoft .NET團隊一直致力於開發一個在ASP.NET Core中進行執行檢查的統一方法。
不過,對執行狀態的監控與執行的頻率有關,比如每100毫秒的執行監控與每秒、5秒或每分鐘的監控都不一樣。
Stack Overflow就是一個實際的例子:當你將HAProxy後端伺服器從MAINT(維護模式)切換到ENABLE時,後端會正常執行,直到檢查執行狀態發現問題時,才會停止。但是,當你從DRAIN切換到ENABLE時,後端會先停止執行,必須通過3次狀態檢查才能獲得流量。當我們處理執行緒池增長限制和快取試圖啟動時(比如我們的Redis連線),由於執行狀況檢查,我們可能會遇到非常討厭的執行緒池飢餓(thread pool starvation)問題。這個影響是巨大的。因為在進行模式切換時,我們需要大約8-20秒才能完全準備好在新構建的Web伺服器上提供流量。
使用httpUnit構建監控系統
HttpUnit是基於JUnit構建的一個開源測試框架,專門針對Web應用的測試,解決使用JUnit框架無法對遠端Web內容進行測試的弊端。
HttpUnit通過模擬瀏覽器的行為,包括提交表單(form)、處理頁面框架(frames)、基本的http驗證、cookies及頁面跳轉(redirects)處理等。通過HttpUnit提供的功能,使用者可以方便的和伺服器端進行資訊的互動,將返回的網頁內容作為普通文字、XML Dom物件或者是作為連結、頁面框架、影象、表單、表格等的集合進行處理,然後使用JUnit框架進行測試,還可以導向一個新的頁面,然後進行新頁面的處理,這個功能使你可以處理一組在一個操作鏈中的頁面。總的來說,httpUnit是一個相當簡單易用的工具,我們用它來檢查端點的狀態,看看此URL是否返回我們期望的狀態程式碼?
通過不斷檢查並在失敗時提供警報,我們可以快速識別問題,尤其是那些來自基礎架構的無效配置更改的問題。在應用使用者負載之前,我們還可以輕鬆測試新的配置或基礎架構,防火牆規則等。
使用Fastly構建監控系統
Fastly作為美國的CDN廠商,近年來不斷在邊緣雲領域深度佈局。你可以將Fastly視為負載均衡器時,它類似於HAProxy後端,內建了執行檢查。
監控指標
監控指標可以是時間序列資料,這意味其中你有一個名稱、一個時間戳、一個值,在本文的示例中,有一些標籤。例如,單個條目看起來如下所示:
·名稱:dotnet.memory.gc_collections
· 時間:2018-01-01 18:30:00(UTC)
· 值:129389139
· 標籤:伺服器:NY-WEB01,應用程式:StackExchange-Network
條目中的值也可以採用幾種形式,但一般情況下是計數器。計數器會報告一個不斷增加的值(通常在重新啟動時重置為0)。通過計算值隨時間的差值,你可以找到視窗中的Delta值。例如,如果我們在10分鐘之前有129389139個程序,我們就知道在那十分鐘內該伺服器上的程序運行了100個Gen 0垃圾收集通道。另一個例子是報告一個絕對時間點的值,例如“此GPU當前為87°”,那麼我們用什麼來處理這些監控到的資料問題呢?
警報資訊的處理
我們如何處理所有這些資料呢? Bosun是我們內部的主要警報源,它由OpenTSDB支援儲存。它是一個基於HBase構建的時間序列資料庫,具有很高的可擴充套件性。bosun是常用的報警系統,通過配置metrics(items)圖可以得到某一個引數在指定時間內的變化,比如設為10s,每隔10s就會監控這個資料並畫圖,依據這個圖可以實現對某些引數的監控,以此作為報警的依據。
在.NET中,我們使用我們維護的另一個開源NuGet庫BosunReporter傳送監控指標。它看起來像如下這樣:
// Set it up once globallyvar collector = new MetricsCollector(new BosunOptions(ex => HandleException(ex)){ MetricsNamePrefix = "MyApp", BosunUrl = "https://bosun.mydomain.com", PropertyToTagName = NameTransformers.CamelToLowerSnakeCase, DefaultTags = new Dictionary<string, string> { {"host", NameTransformers.Sanitize(Environment.MachineName.ToLower())} }});// Whenever you want a metric, create one! This should be likely be static somewhere// Arguments: metric name, unit name, descriptionprivate static searchCounter = collector.CreateMetric<Counter>("web.search.count", "searches", "Searches against /search");// ...and whenever the event happens, increment the countersearchCounter.Increment();
我們還可以在Bosun的資料計數器中,新增更多標籤,例如,計數器在哪個伺服器上執行(通過主機標籤),我們可以在IIS中新增應用程式池,或者使用者點選的Q&A網站等。
許多其他系統都可以傳送指標,scollector為Redis、Windows、Linux等提供了大量的內建功能。我們用於關鍵監控的另一個外部示例是一個小型Go服務,它可以監控Fastly日誌的實時流。有時Fastly可能會返回503,錯誤的原因也許是被切斷的套接字,或者是路由問題,或者是壞的證書。無論原因是什麼,我們都希望在這些請求失敗並且使用者感覺到失敗時系統會發出警報。這個小服務只會監控日誌流,不過它從每個條目中解析一些資訊,並將它們彙總後傳送給Bosun。
我真正喜歡Bosun的一個關鍵特性是,它能夠監控歷史警報。這有助於我們瞭解警報具體是何時觸發的,這是一個很棒的監控過程。說實話,很多監控來自經驗教訓,警報經常是在事情發生之後,才將出錯的資訊新增到其中。
你可以看到在11月18日有一個很低的系統值,低到足以觸發安全警告。
我們還通過以下幾種方式監控(通過Bosun)錯誤:
1.通過每個應用程式總結我們的異常錯誤日誌;
2.通過Fastly和HAProxy;
如果我們在這兩種應用程式上都看到了高錯誤率,那麼一兩分鐘後,帶有詳細資訊的訊息就會出現在聊天中。由於它們是基於聚合計數的,因此不能立即執行。
另一種傳遞警報的方式是電子郵件,Bosun就有這個功能。電子郵件可能只是一個簡單的提醒。比方說,磁碟空間正在減少,或者CPU處於高位執行,而電子郵件中的一個簡單圖表就能說明很多問題。要想得到更復雜的警報,我們可以為電子郵件本身新增故障和詳細資訊。你可以得到更好的資訊來處理(或者甚至決定忽略)一封電子郵件的提醒,而無需進一步深入。這是本文的示例中,NY-TSDB03的CPU突發事件的郵件示例,其中包括了最近的10個事件。
Grafana
Grafana是一個開源的度量分析和視覺化套件,它最常用於視覺化基礎設施和應用程式分析的時間序列資料。
如果監控資料,你看不到,那麼這些資料有什麼用呢?所以時間序列資料的圖形化視覺化是一種很好的方式。這就是我們為什麼使用Grafana的地方,它是一個優秀的開源工具,為此我們提供了一個 Bosun外掛 ,這樣它就可以成為一個數據源。 (從技術上講,你可以直接使用OpenTSDB)。注意:我們對Grafana的使用過程,會使用圖片的方式來解釋。
以下是一個狀態儀表板,顯示了Fastly的運作方式。因為我們的外掛會支援他們的DDoS保護和更快的內容傳送,所以當前顯示的狀態也是我們的當前狀態。
這是一個隨機的儀表盤,它是按地域劃分的,你可以看到當人們醒著的時候,世界各地的網路流量分佈情況。
客戶端計時
關於上面提到的所有內容,一個重要的注意事項是它是伺服器端。記住,渲染網頁的速度並不重要,這一點至關重要。
幾年前,當我們需要的部分首次在瀏覽器中可用時,我構建了一個客戶機計時管道。這個概念很簡單:使用web瀏覽器中可用的導航計時API並記錄它。要了解其工作原理,請訪問 teststackoverflow.com 。
MiniProfiler
有時,你要捕獲的資料比上述方案更具體和詳細。MiniProfiler是一款針對.NET, Ruby, Go and Node.js的效能分析的輕量級程式。可以對一個頁面本身,及該頁面通過直接引用、Ajax、Iframe形式訪問的其它頁面進行監控,監控內容包括資料庫內容,並可以顯示資料庫訪問的SQL(支援EF、EF CodeFirst等 )。並且以很友好的方式展現在頁面上。MiniProfiler的一個特別有用的功能是它與資料庫框架的整合。除了.NET原生的DbConnection類,MiniProfiler還內建了對實體框架(Entity Framework)以及LINQ to SQL、RavenDb和MongoDB的支援。任何執行的Step都會包括當時查詢的次數和所花費的時間。為了檢測常見的錯誤,如N+1反模式,profiler將檢測僅有引數值存在差異的多個查詢。
預設情況下,你可以看到這個數字,但是你可以將其展開以檢視樹形式中哪些內容需要花費多長時間。在那裡連結的命令也是可見的,因此你可以Fastly檢視執行的SQL或Elastic查詢,或發出的HTTP呼叫,或者獲取的Redis快取等。
由於MiniProfiler的執行成本很低,我們可以在每個請求上執行它。為此,我們在Redis中保留了每MVC路由的配置檔案樣本。例如,我們在給定時間保留任何路由的100個最慢的配置檔案。這樣我們就可以看到使用者可能會遇到的問題,我們可以看到Bosun中的路由速度很慢,HAProxy日誌中的點選率下降了,還有需要深入研究的配置檔案快照。
使用Opserver構建日誌監控系統
那麼,什麼是Opserver?Opserver是Stack Overflow的開源監控產品,stackoverflow網站是基於asp.net開發的,它是一個基於網路的儀表板和監控工具。大約5年前,我們遇到了一個問題,即SQL Server AlwaysOn可用性組在SSMS儀表板上顯示為綠色(由主伺服器提供支援),但是副本已經好幾天沒有看到新資料了。這是一個監控極度失效的例子。發生的情況是HADR執行緒池耗盡,並停止更新處於“all good”狀態的檢視。這樣的設計不一定是有缺陷的,但是當快取/儲存一個事物的狀態時,它需要有一個時間戳。如果尚未在<選擇閾值>中更新,則為紅色警報。無論如何,進入Opserver。它做的第一件事是監控每個SQL節點而不是信任主節點。
從那時起,我在基於Web的Fastly檢視中為我們想要的其他系統添加了監控功能。
Opserver:主要儀表板
登陸儀表板是一個伺服器列表,顯示了內容的概述。使用者可以按名稱、服務標籤、IP地址、VM主機等進行搜尋。你還可以深入檢視每個節點上CPU、記憶體和網路的歷史記錄圖表。
在每個節點內看起來像這樣:
如果使用Bosun並執行Dell伺服器,則我們添加了如下硬體元資料。
Opserver:SQL Server
在SQL儀表板中,我們可以看到伺服器狀態以及可用性組的工作方式。我們可以看到每個節點在任何給定時間有多少活動,以及哪個節點是主節點(藍色部分)。底部是AlwaysOn可用性組,我們可以看到每個可用性組的主伺服器是誰,複製的進度落後了多少,以及備份了多少佇列。如果事情變糟並且副本不執行,則會出現更多指示符,例如哪些資料庫存在問題以及T-logs中涉及的所有驅動器的主資料庫上的可用磁碟空間(因為如果複製仍然停止,它們將開始增長):
還有一個頂級的全部作業檢視,用於Fastly監控和啟用/禁用:
在每個例項檢視中,我們可以看到有關伺服器、快取等的統計資訊,我們發現它們隨著時間的推移而變得相關。
對於每個例項,我們還報告頂級查詢(基於計劃快取,而不是查詢儲存),active-right – now查詢(基於sp_whoisactive)、連線和資料庫資訊。
如果你想深入到一個頂部的查詢,它看起來是這樣的。
在資料庫檢視中,可以查看錶、索引、檢視、儲存過程、儲存使用情況等。
Opserver:Redis
對於Redis,我們希望檢視主要副本和副本的拓撲鏈以及每個例項的總體狀態:
請注意,你可以終止客戶端連線、獲取執行配置、更改伺服器拓撲以及分析每個資料庫中的資料(可通過Regexes配置)。最後一個是KEYS和DEBUG OBJECT掃描,因此我們在副本節點上執行它或允許在主伺服器上強制執行它(為了安全起見)。分析看起來像這樣:
Opserver:Elasticsearch
對於Elasticsearch,我們通常希望看到叢集檢視中的內容,因為這就是它的行為方式。下面沒有看到的是,當索引變為黃色或紅色時。當這種情況發生時,儀表板的新增的部分將顯示出有問題的碎片、它們正在做什麼(初始化、重新定位等),並且計數將出現在每個叢集中,彙總有多少碎片處於哪種狀態。
Opserver:異常
Opserver中的異常是基於StackExchange.Exceptional。在這種情況下,我們特別關注Exceptional的SQL Server儲存提供程式。Opserver是許多應用程式共享單個數據庫和表佈局的一種方式,並允許開發人員在一個地方檢視其異常。
此處的頂級檢視可以只是應用程式(預設),也可以按組配置。在上面的例子中,我們按團隊配置應用程式組,這樣團隊就可以標記或快速單擊他們負責的異常。在每個例外頁面中,詳細資訊如下所示。
還記錄了詳細資訊,例如請求標頭(帶有安全過濾器,因此我們不會記錄身份驗證cookie),查詢引數以及新增到異常的任何其他自定義資料。
Opserver:HAProxy
HAProxy部分非常簡單,我們只是簡單地呈現當前的HAProxy狀態並允許對其進行控制。這是主儀表板的樣子:
對於每個後臺組,特定後端伺服器,整個伺服器或整個層,它還允許一些控制。如果我們需要將其關閉以進行緊急維護等,可以讓後端伺服器停止運作,或者讓整個後端關閉,或者讓web伺服器退出所有後端。