本文根據吳燕軍老師在〖deeplus直播:逆襲生產力擔當,雲原生時代的運維新歸宿〗線上分享演講內容整理而成。(文末有回放的方式,不要錯過)
大家好,我是來自於去哪兒網的吳燕軍。目前在公司主要負責監控系統的開發、容器化以及上雲過程的相關工作。今天的分享主要包含以下幾個方面的內容:
一、基本介紹
1、原來的監控架構
去哪兒網是一個發展得比較久的公司,我們有很多的業務線,而這些業務線反映到公司的架構層面就是多個部門。最初的時候,我們每個部門都有一套獨立的監控系統,一般都是Cacti或Cacti+Nagios,Cacti主要用於畫圖和看圖,而Nagios則用於配置報警策略。每個部門之間相互獨立。但這樣就帶來了一些問題:
- Cacti單機部署,不能橫向擴充套件,效能差,非高可用;
- 各部門維護一套甚至多套,運維成本高;
- 報警配置有專人負責,不能由開發人員定製,效率低;
- 各個監控系統之間資料不通,不便於整體分析和使用。
2、Watcher系統
1)基本特點
基於這些問題,我們提出了一個解決方案:搭建企業級統一監控報警平臺,也就是我們的Watcher系統。這個Watcher系統它有些什麼特點呢?
- 首先,Watcher系統是基於graphite深度定製開發。也就是說,它的整體核心都是graphite以及Carbon和Whisper這一套服務;
- 然後,它是多種開源產品的有機結合。包括Grafana等;
- 最後,這套系統完成以後,我們可以實現海量監控資料實時處理。
這是它的基本特點。
2)四大特性
Watcher系統支援主機的基礎監控報警,比如CPU、Load和Memory、記憶體以及swap等,它的報警採集、採集記錄以及畫圖都是自動新增的,使用者不需要參與。我們會記錄業務指標、分析類結果統計指標,比如Flink任務採集到的log指標以及異常日誌的分析、統計等。Watcher系統還提供嵌入SDK記錄的訪問類指標等。由於我們的整個技術棧比較統一,基本都是Java類的服務,因此我們提供了Java的SDK,允許開發人員記錄它在整個使用過程中所有的監控資訊。這樣一來,開發人員可以記錄某個介面甚至某個函式的訪問時間情況,操作會更加便利。
3)支援協議
Watcher系統支援多種協議。最初它是基於graphite定製開發的一套監控系統,而graphite是基於Python來開發的,所以它天然支援Python的Pickle協議,即TCP協議,同時它也支援UDP協議。也就是說,Watcher支援兩種協議來採集資料。
TCP和UDP本身在特點和效能上存在一些差別,TCP可以支援大的TCP包之類的處理邏輯,但UDP可能並不支援這種特別大的資料和處理方式,它們各有利弊。
4)採集方式
Watcher系統支援推、拉兩種資料採集方式:
我們更傾向於採用透過server端拉取使用者所提供的, SDK上的資料的方式。因為這種方式更可控,如果SDK端有異常或其它情況,我們可以感知到並做出相應的動作,如拉黑等;但是像一些分析類的服務,比如Flink任務、一些日誌分析的任務等。這些分析完的系統的如果沒有暴露HTTP的介面等途徑,那我們是沒辦法拉取的。所以在這裡,我們允許它作為一個數據推送到我們服務。因此支援兩種方式。
5)系統架構
上文有提到,Watcher系統是多種開源系統的有機結合。如圖所示:
Watcher系統涉及到較多的開源系統,在這裡我先給大家簡要介紹一下它的定位。
首先是Graphite。Graphite可以說是整個系統的核心。我們最核心的儲存也就是時序資料的儲存、Whisper以及它的資料高可用、多副本的處理都是Graphite來做的,當然我們也做了很多二次開發來調整整體的架構;同時我們也使用了Grafana來做展示和看圖的Dashboard;用PG來儲存一些元資料資訊。
這裡需要說明的一點是,雖然Graphite最初的版本不需要源資料DB,而是直接根據檔案目錄來查詢整個指標的內容;但後續,Graphite發展到1.x版本時,它是提供了一個tag指標類的查詢方式。而使用了這個方式之後,它的指標會被雜湊掉,也就是說,一個指標會變成一個模糊的雜湊串。那這時候完全沒辦法把它反過來找到我們的指標名了,所以就需要一套監控系統或者說一套記錄原資訊和雜湊串對應關係的系統,也就是我們現在使用的PG系統。
當然我們開始並沒有使用Graphite提供的方式。因為我們使用了一種多叢集使用Graphite的方式,這使得我們天然需要一個記錄原資訊和目標指標的對應關係的資料庫,所以我們其實很早就使用了PG的資料庫。
近期,因為業務發展以及一些使用者的訴求,我們其實也在較為深入地使用ClickHouse,這也是比較新的一套開源的OLAP作為線上資料分析的儲存資料庫。它在我們的Watcher系統有比較重的使用。
另外一個就是Icinga。Icinga其實是一個報警的管理和通知的模組,類似於Nagios的升級版。當然,這些基本上都是開源的系統,我們也都在上面做了一些定製化的開發和處理。
3、整體架構
以上是我對Watcher系統的基本介紹,有些內容可能比較偏概念,所以有些無聊。接下來我會給大家詳細地說一下這個監控系統的整體架構情況,這裡是一個整體簡化過的架構圖:
1)指標收集
上文提到,Watcher系統支援多種指標型別,像一些普通的基礎監控,即CPU、 Load等。體現在整個架構圖中,就是左上角這部分。主機的CPU、Load、記憶體等,都會透過基礎指標直接上報到我們的Grelay,也就是一個數據分發和處理的模組,我們基於Graphite和collectd做了一個二次開發,增加了一些定製化的功能,這就是基礎指標的資料收集。
然後是業務指標的資料收集。業務指標這一塊對應到了一些像Flink任務、日誌分析任務等資料處理邏輯,它們都會採用一種同樣的方式把資料推送到Grelay服務,由Grelay服務做到多副本或雜湊的儲存,保證資料儲存到它應該到的地方。當然,Grelay也會Mirror出一份元資訊儲存起來,記錄元資料和真實儲存位置的對應關係。
另外是我們比較推薦的,同時也是現在使用比較重的一個系統,就是Qmonitor系統。我們提供的很多定製化功能都是在SDK做的,SDK會自動記錄一些JVM的監控資訊,甚至一些介面類的其他資訊。提供了SDK之後,它會對外暴露一個HTTP介面,這時候我們會透過Qmonitor的 server端抓取這些資料,做一定的聚合處理後,上報到我們的儲存系統進行儲存。
2)儲存
這裡比較有意思的點在於,Qmonitor是一個比較抓取儲存的系統,而SDK又被放給了使用者。隨著它的使用發展,在使用者或開發人員迭代等時候,可能會出現SDK使用氾濫的情況。很多資訊都記錄在SDK裡,我們難以判斷它能否清理。現在這個問題可以藉助混沌工程、輔助程式碼、指標的清理邏輯之類的方式解決,但在過去,就會導致需要處理的資料量巨大。
我們原先的監控系統的整體技術棧是Python,在處理 SDK抓取以及聚合計算併發送到Grelay的時候,它的多程序和多執行緒的模型,現在延時已經到了分鐘級,比較極端的甚至已經達到了4分鐘。
對於監控這種需要及時發現問題的系統來說這是不能容忍的,所以我們在這一塊做了一些最佳化。把監控系統從Python的抓取轉變成Go的方式,因為Golang對於非同步或併發的支援是天然比較友好的。另外,相對於Python,它是個強型別的語言,不需要面對Python的GIL鎖以及變數型別解析等過程帶來的損耗,整體能夠帶來8倍到10倍的效能提升。
單機樹系統採用了支援多種資料儲存的ClickHouse。一般使用Qmonitor,它是支援資料聚合邏輯的,而單機數這裡相當於把資料聚合邏輯直接設定為不聚合,會帶來資料量的大量膨脹。但ClickHouse有一個特點,它對批次寫的支援非常好,能夠滿足我們的寫入要求。Clickhouse在使用過程中能夠達到每秒百萬級以上的寫;但它讀請求支援的QPS不是特別多,因為ClickHouse在每次讀請求時可能還需要處理大量資料。所以我們對於單機數的定位可能更多在於輔助和排查解決問題。
使用者使用Qmonitor server抓取元資訊,並存儲到我們的監控系統,通過後續報警來使用這些資料。而一旦發現問題,就可以反過來使用ClickHouse查詢發生問題的具體位置。比如整個服務有10臺主機,一般出現問題的可能只是其中的某一臺或是某幾臺。我們如何才能快速定位問題所在呢?這時候就會使用到單機數系統,我們會把所有Qmonitor抓取的原始資訊全部記錄下來,儲存到ClickHouse。
3)最佳化
①資源匹配
需要注意的是,這個系統的讀和寫都非常極端,而且對於我們來說,它只是一個用來分析、發現問題的抓取分析的系統。因此,在對系統資源進行分配時必須進行最佳化。目前這套單機數系統大概使用的儲存和及解析指標的機器,大概是聚合儲存的1/10到1/5,使用比較少。我們是怎麼做到這種最佳化的呢?
首先是ClickHouse支援批次寫這一部分,這部分我們不需要改動太多。ClickHouse基本上沒有做太多開發,只是在每臺機器訪問ClickHouse的時候做了一些高可用授權及健康檢查。整個系統最大的最佳化點在於:如何讓解析系統使用更少的資源支援更大的請求?
這一塊我們採用了MQ的形式,對資料的抓取和處理做了解耦。在資料抓取時,一般抓完一次就直接把它塞到 MQ,所以它的業務邏輯並不重,不需要進行特殊處理。
②資料解析
所以我們最大的最佳化點是資料解析,每進行一次的抓取解析服務就需要起一個協程去處理,但整個系統在使用過程中支援的處理能力卻並不高。經過對比分析候發現,當大量資料湧入時,解析程式碼的這部分會存在好幾萬的抓取邏輯,基本上都有併發的幾萬個協程處理。這樣一來它帶來的排程以及其他開銷就會很高。為了解決這個問題,我們採用了Golang中的channel的方式,在內部又做了一個小的佇列。channel後面會對接到一個類似協程池的形式,固定幾個來處理協程。而我只需要重複從 channel裡取出資料並進行處理這樣一個過程。最佳化完成之後,單臺32核左右的主機的系統性能基本上能達到每分鐘處理1億或是1.2億的量級,也就是說,它每核基本上每秒可以處理10萬+的指標。
③資訊轉換
當然這部分還有其他一些需要最佳化的點,比如原始資訊的轉換等。因為指標基本上都是一些文字資訊,但我們需要做一些特殊的處理和檢查,把它關聯到某個具體的請求,記錄它的原始資訊或處理等。整個文字的處理可能會涉及到字串和位元流的轉換過程。而整套系統只是把資料做一些輔助資訊的新增和處理,然後扔到儲存的一箇中間系統。能否拋棄位元流到字串之類的轉化過程,直接採用位元的流式處理呢?
基於這種想法,我們在拉取HTTP的文字到單機數系統之後,直接遍歷迴圈整個文字的位元流,再基於位元流做資料的切片和合法性校驗,把結果扔給批次寫的服務,批次寫入服務聚合成一個大的二進位制文字,再批次寫入ClickHouse。這裡是採用單個TCP的傳送方式,頻寬轉發資料基本在1G以上,效能比較高。這是我們在Qmonitor以及單機數系統處理的時候所面臨的問題、它的特點以及我們的最佳化手段。
架構圖中顏色較深的部分是儲存系統,當指標資料抓取、儲存到整個儲存系統之後,我們提供了一個統一的API來訪問這個服務,對外所有的資料或看圖類的請求都透過 API來執行。這樣一來,使用者在使用過程中就不需要關心每一個系統單獨的實現方式是怎樣的,而只是作為一個解耦的方式更方便大家使用。使用者可以訪問API做一些定製化的使用,比如訪問指標值、對它做一些定製化處理或者一些其他的預警方式,這些都是可以支援的。
④報警抑制
從使用者的角度看,他的所有請求都會落到Dashboard系統上。而Dashboard系統提供了一些報警配置的功能,當它配置完成之後,報警就會落到Dashboard儲存庫。當然,他也可以查詢我們的一些指標值或者是單機數值,直接透過API來拉取資料,這是一些使用者的使用行為。除了使用者使用行為,監控系統其實更多是在和報警系統打交道,或者說互動。我們不可能一直人肉盯著整個服務或者指標的趨勢,因此報警系統就顯得格外重要。什麼系統、什麼時候出現了問題?怎麼讓使用者及時感知到?以及如何儘量避免打擾使用者等。
當用戶配置的報警資訊落到了Dashboard儲存庫之後,我們的報警解析模組會讀取整個報警資訊以及它配置的規則,真正拉取整個指標值,並根據它的規則進行,判斷是否滿足報警條件,然後把它推送給Icinga服務,由它來做報警管理,透過Qtalk(內部IM)、電話等方式通知使用者。這裡包含了一種升級的規則,因為一般Qtalk這種工具大家下班或者其他的一些時間不太經常看。如果真的發生大問題,就需要更及時的一種通訊方式,也就是電話。我們的報警最初是傳送 IM訊息,如果大家看到並處理掉之後,系統就不會再打電話;但如果使用者沒有關注到,而報警一直在持續的話,我們就需要實行報警升級策略,進行電話通知。當然,如果使用者認為整個報警並不是很重要並進行了關閉報警等,系統也不會打電話。
當用戶發展到一定規模之後,大家在處理報警或者配置報警的過程中一定會面臨一個很大的問題:如何避免轟炸到使用者?比如我同時配置使用了特別多的報警,一旦出現問題,我的手機或者其他的聯絡方式就會一直接收到報警訊息,但有些報警其實在一段時間後會自動恢復。為了避免出現“狼來了”效應,我們提供了一個報警抑制策略。如果一個服務基於報警解析,判斷它滿足報警條件,但透過報警抑制模組後發現這個報警一直在閃報,每次報警後過兩分鐘就恢復了。那這個時候系統就會傾向於認為這個報警並不重要,沒必要一直打擾使用者。所以系統會採取報警抑制策略,把它標註為被抑制狀態,保證不騷擾使用者。
這個演算法並不是複雜,只是基於使用者的使用過程、歷史的報警情況以及報警的重要程度進行評判。為了保險起見,我們也設立了一個絕對值,如果某次報警的持續的時間比較長,就會自動退出報警抑制狀態,通知使用者。這是我們的一個兜底手段。
以上是我對於整個報警系統架構的介紹,在這個過程中也涉及到了我們面臨的一些問題以及最佳化手段等。介紹完了監控系統的架構,接下來我給大家簡單介紹一下它整體的使用情況。
二、使用情況
我們目前的業務指標已經達到了6000萬的量級。而且,因為一些樹結構的組成形式等,它的真實儲存可能已經到了7000萬;一些基礎監控指標也已經達到了2.5千萬左右,這裡我們採用了一種分級的方式,按照點分級組成樹結構的形式,結構形式比較複雜,在5000萬到6000萬之間。
大家可以看到,業務指標和基礎指標之間存在很大的區別,為什麼業務指標和基礎指標會存在兩倍以上的差距呢?基礎指標基本上屬於扁平類的指標,是對於指標應該怎麼使用的規劃,規劃沒那麼多,那他們就會看到指標上的差異。
什麼叫多環境指標?直觀地說,因為我們線上的業務可能會分為測試或者線上環境等多種環境,也就是說,我們支援線上、測試、甚至是其他的一些灰度環境來實現指標抓取。當環境增多後,它的指標量會比較少,而且從儲存策略上說,我們對於這種指標儲存的時間週期會比較短,當然,這種多環境指標是排除了線上的指標的,這是我們指標量的使用情況。
業務類的報警大概在15萬左右,每週的報警情況更是將近100萬,這裡大家也可以看到報警抑制的必要性。當然這一塊也能看到我們的基礎監控和業務監控在使用情況上的差別,業務指標較多,但它的報警量反而相對較少。
最後是單機數大概處理的情況。目前,單機數每分鐘寫入的點數在4000萬左右,但它每分鐘處理的點數卻將近1.3億,為什麼會有這麼大的差別?這是由於我們實施的一些最佳化手段。系統每分鐘處理1.2億之後,寫入4500萬,剩下2/3是什麼呢?大家可能不太關注,一般在監控指標中存在很多0值指標,尤其是在指標量特別大的情況下。比如有些業務我訪問過一次之後,這個記錄一直被保留了下來,沒有被清理掉,但他的值其實一直是0。
這一類的指標存在非常大的比例,當我們處理完每分鐘的指標之後,會把所有的0值指標全部丟掉,這樣一來寫入量就是1/3,相當於做了一個定製項的最佳化。大家在其他系統的使用過程中可能也會面臨這種情況,這時候可以考慮一下這種最佳化手段。當然,並不是所有的0值都沒用,我們對於線上的0值會比較慎重,只是把單機數的0值去掉。這樣就能讓單機樹系統使用更少的資源提供更多的服務。
三、可觀測性
瞭解了監控系統的使用情況,接下來是對它的可觀測性的介紹。
從這張圖中,我們能夠比較直觀地看到可觀測性結合的內容。之前有同學問到:監控和可觀測性有什麼區別?這個問題的答案我們可以從這張圖中找到。監控系統主要集中在一些指標、指標的聚合以及聚合完後對應的報警等;而可觀測性是一個更新的概念,它把指標以及整個訪問過程的鏈路、日誌的情況進行結合,結合完之後,它們之間的交集,或者說它結合的整個過程,就是可觀測性的內容。
上文中,我們比較詳細地介紹了 metric這一部分的內容,接下來我會給大家會介紹metric、Trace以及log的部分關聯,也就是我們在可觀測性上做的一些工作。
這是我們整體的架構方式。可觀測性的誕生其實是從微服務開始的,而它帶來的問題就是服務的混亂。比如我訪問B服務並向它要了一個數據,而B服務可能掉了CDEF等N個服務而我並不知道。一旦發生問題,我又不是特別熟悉這套系統,那就很難排查到問題的真正位置。最多隻能定位到 A跟B要資料時B服務提供的資料錯誤,但是為什麼會這樣呢,大家並不知道,這就是可觀測性上做的一些事情。
那麼整體的架構就是:我們中介軟體團隊提供Agent的方式來採集一些可觀測性的資訊,包括記錄它的Span等;當它記錄完成之後,就會透過ELK的形式,將資訊收集到Kafka系統;當收集Kafka系統之後,Flink任務會處理分析這些記錄的Trace或Span資訊,建立相應的索引儲存到Hbase之類的資料庫。整個過程也會有一些其他的索引建立來幫助快速定位,日誌基本上也是以同樣的方式收集到Clog服務,並透過Flink這一套資料處理方式進行索引建立和儲存。
從圖中可以看到,因為可觀測性是後提出的概念,所以我們的日誌和Tracing的服務與指標服務並不會混合在一起,Metrics服務或者說監控服務基本上是一個比較獨立的過程。從監控報警中收完指標,同時Tracing收完它的SpanID、Log收完日誌之後,它們要如何實現關聯呢?這裡我們是透過開發一套新的服務讓它們實現關聯。
因為有指標資訊的存在,所以我們會基於關注的指標做一些定製化處理,將它推送到收集的Agent上,讓它記錄這些指標的Tracing,當它記錄完成之後,Trace會帶著這些指標資訊以及它自己生成的SpanID類的資訊解析到儲存裡,同時Flink處理時,也會再生成一份指標和ID的索引資訊。這樣一來就可以實現指標和Span的關聯。日誌也是同樣,當問題發生之後,我只需要把SpanID輸入到日誌裡,就能找到相對應的資訊。透過指標我們可以關聯到Span資訊或者trace資訊,而透過Span ID,我們也可以找到對應的日誌, 這就是我們的整個架構的關聯方式。
接下來給大家展示一下我們這一架構方式下的成果:
這是我們監控系統的介面,大家可以看到,當報警發生時,我可以透過查詢Trace檢視報警資訊。這時候就會用到我們剛剛建立的TraceID和 Metrics資訊的索引。當然我們也會做一些定製化的排序等,排完序之後,大家就可以透過TraceID直接跳轉到Trace系統來檢視它的整個呼叫過程。
如圖所示,因為一些安全問題,我隱藏了某些節點的資訊。圖中每一個方塊其實都代表了一些節點,這些節點我在圖片的上部分做了大概的說明。從圖中我們可以看到,單次呼叫的時候整個鏈路會很複雜,人力基本不可能瞭解到清楚整個過程情況。所以我們可以透過指標查詢到Trace資訊,然後透過Trace系統定位到真正出現問題的位置。如果只是單純的時間高的話,我就能知道哪個時間更高一些。
因為這裡儲存著N個系統上傳的Span資訊,如果我們想了解更多詳細的Span資訊,我也可以透過“全部Span”來檢視。假如這是一個Trace資訊,而我的問題是:它為什麼耗時這麼高?這時候只要點開更詳細的Span,就能看到Span在系統或者是這次呼叫中各部分花費的時間,然後去查耗時最高的系統,瞭解原因,從而實現問題的輕鬆定位。
除了透過TraceID查詢到整個Trace的詳細資訊之外,透過TraceID我們也可以查詢到與它相關的所有日誌。在圖中大家可以看到一些關鍵字,像合併、WARN等,這些都可以關聯起來。這就是我們在可觀測性方面做的一些事情。
四、新的挑戰
上文在介紹架構的時候有提到它的挑戰,比如說:當我們的業務發展過程中指標量特別高,而處理能力無法滿足時要怎麼解決?
可能大家比較早的時候,發展基本上都是使用Python或者PHP之類的指令碼型語言,那麼見效比較快的最佳化形式,就是從指令碼化的Python轉變為Golang。這裡不是說Python語言不好,只是我認為,Python可能並不適合大併發以及資料量特別大的處理場景,而是更適合做一些其他指令碼或者是科學計算等。所以技術棧的切換是一個很好的最佳化點。
以我們的經驗來看,把Python語言最佳化到Golang語言帶來的效能提升基本在8倍到10倍左右。
然後是語言資訊的儲存系統。在這方面我們一直髮展得不錯。從我進入公司時的2000萬,到現在已經發展到了6000萬~7000萬的水平,業務量翻了好幾倍。大家如果對資料庫有一定的瞭解就會明白,當一個數據庫中的資料量達到了這個量級,那它的處理就會是一個非常艱難的過程。不僅每次查詢索引的耗時高,從索引中找到真實資料花費的時間更高。
面對這樣的情況要如何進行最佳化?
我們最早的系統採用PG的Ltree方式來實現指標的查詢,每次查詢可能會查到Ltree的某一級,並進行模糊匹配,匹配完成之後再把資料返回給使用者。但這裡有一個很大的最佳化點:Ltree的匹配或者說字串的匹配會涉及到很多演算法相關的內容,效能都不是特別好。我認為比較好的方式是:將抽象出來的模糊匹配的資料或者常用關鍵字轉為tag。
比如我們是做旅遊業務的,工作中會經常涉及到各種地名,像上海、北京等。如果用Ltree的方式,當我要檢視各地的查詢情況,我可能會寫一個shanghai.status_code.500,然後找到它各個系統的內容;又或者找到Ltree的這一級,將它全部展開。
轉換成tag的方式之後,比如我在系統中增加了一個數據維度的資訊,我一般稱之為city資訊。這個city資訊可能代表北京或上海,如果存在一個北京或上海和ID的對映關係,我就可以直接透過ID查到整個指標。這帶來的效能提升基本上是數量級的,int型別的比較要比字串的比較快很多。
當遇到資料量特別大的情況時,大家可能會想到兩種處理方式。比較常用的方式是分庫分表。但除了分庫分表之外,我還想給大家提供一種新思路:PG或MySQL有一些類似於分割槽表的新特性。這裡簡單介紹一下我們使用PG或MySQL的分割槽表之後發生的變化。
在資料的處理過程中,這些資料在物理上都是分成塊的,但我在使用時其實並不需要關注它分成物理塊的方式以及具體的查詢過程。只需要它的關鍵資訊就能進行查詢,這就是我們對於分割槽表的使用方式。經過我們的實踐,使用分割槽表可以會讓業務的實現變得更加簡單,自己也不再需要維護大量的事務資訊。所以,大家在出現效能問題時,可以適當考慮分割槽表的形式。
這部分介紹了許多我們業務量發展到一定程度後帶來的問題。除了業務量發展帶來的問題之外,在整個容器化的過程中,我們從不變的KVM固定主機變成了會經常變動的pod,而這一變動也帶來了一些挑戰。原有系統在面對不同的資料時,可能只需要新增一個配置,在固定的主機名上請求業務;變成了pod之後,誰也不知道哪個pod代表了什麼。
那這個時候就需要透過建立pod IP,透過pod以及IP等同我們服務之間的對映關係進行事件驅動,以這樣的方式將資料進行彙總和定時更新。這是我們從不變到變的過程中的解法,需要建立對映關係,一般會有一個服務類的模組幫助我們實現統一參與,在應對變化時將它變成一種普遍的解答方法。
五、未來規劃
接下來簡單給大家介紹一下我們對未來的規劃。
我們目前使用到了K8s以及Prometheus,但它與我們之前的業務的結合並不完美,所以我們下一步計劃對Prometheus等做更多的相容,甚至是對某些功能和模組做替換。
文中有提到,在從不變到變化的過程中,使用者的訪問會產生大量不可控的SDK的指標或大數的指標。那個時候我們可能會考慮在整個pod中新增一個sidecar的容器,用sidecar的小容器對部分資料做提前過濾。當資料處理完成之後,再由server來實現統一的收集抓取。
後續我們也會更多地去關注可觀測性的發展,幫助它更快實現定位、提高Trace的關聯比例等。
以上就是我分享的全部內容,大家如果有什麼想法,歡迎在評論區提出~
>>>>
Q&A
Q1:對於指標的資料聚合來說,在超大系統規模下,做可觀測性如何最佳化資源佔用和時效?
A1:這個問題比較大,我們可以將它拆分成兩個部分進行回答,一個是資料聚合,另一個是可觀測性下資源和時效的均衡問題。
首先是資料聚合。文章中有提到,我們的資料量十分龐大,已經達到了幾千萬的指標量級。而資料聚合我們可以想到好幾個思路,最容易想到的方式是做服務的拆分,也就是微服務化,這樣一來,當某個服務出現問題時我們可以針對它做一些動態的擴縮容,實現節約資源或提高系統處理能力的目的。
還有一種思路是將資料聚合的時間提前或者延後,避免大量資料湧入。舉個例子,使用者可能會有一個記錄監控來記錄系統的訪問情況,而我每次訪問時都會記錄一個指標,如果每次都直接把訪問的記錄情況扔給監控系統的儲存,那麼儲存面臨的QPS壓力就會特別大。這一部分我們會提供一些預聚合服務,像statsd等,允許使用者做一些定製化的聚合邏輯。把大量需要聚合的請求提前擋住,降低儲存壓力。而statsd或其他預聚合服務可以實現定製化開發,所以它的成本也會低一些。除了聚合提前以外,我們也可以對它做一些延後的聚合,大家可能會好奇,為什麼做了聚合的提前之後還要做聚合的延後?這是它們因為針對的場景不同。如果我們將同樣一份程式碼部署到線上,且分別提供了web端的展示服務以及 API的服務,而我們在日常檢視服務訪問時往往都是分開看的,只是偶爾需要進行總和計算或對比。因為偶爾的使用所以平時沒必要花費大量開銷來進行提前聚合,所以只需要在檢視端,也就是Dashboard之類的介面將兩個指標都查到之後進行對比或聚合。
接下來講可觀測性如何最佳化資源佔用和實效。可觀測性方面確實會需要很多資源,包括Trace、log以及監控指標等等。那要如何做到資源分配均衡呢?首先要想清楚可觀測性的定位。如果我們的可觀測性是要把所有的內容記錄得大而全的話,那麼最佳化資源基本上是不太可能實現。但如果我們的可觀測性的定位是:用來發現問題和解決問題的這種系統,這時候就可以做一些最佳化手段了。
如果我們有6000多萬的指標,當它全部關聯到Trace上時就會帶來的一些問題,我們沒有這麼大的處理資源來處理這些Trace資訊。因此我們會挑出一些重點指標關聯到Trace上。那我們的重點是哪些呢?這需要我們自己定義。比如報警指標,當我們把所有的報警指標都關聯到了Trace後,從量級上看,可能會直接從十幾萬飆升到七千萬的量級,這種提升基本上是百倍的。而這一類報警指標關聯到Trace,可能會帶來一些延後的問題。有可能報警已經發生了,然後Trace才關聯到系統上,這時候報警已經過去,所以Trace其實沒有采集到資訊或者採集到的資訊有誤。針對這一部分,一些像exception或者是error之類的異常類的指標,我們要做到全量的定義採集。對於資源的平衡,我的建議是:考慮清楚定位,只需要管理一些關鍵資訊和Trace,而不必把所有的指標都關聯。
多提一句,如果是訪問耗時類的指標,也沒必要把每一個耗時的資料請求都記錄下來,可能只需要記錄Top 10或者是兩個極值就能發現問題。這是對於資源佔用的最佳化或均衡。
Q2:去哪兒網現有監控系統,是如何與容器雲平臺監控做對接和融合的?
A2:我們現在還是用Prometheus實現容器雲平臺的監控、資料採集和儲存。因為Prometheus是從k8s或者是雲誕生時就結合在一起的,它們肯定天然適配。目前我們和它相容的方式是把Prometheus作為另外一個數據源,讓現有的監控系統用與Prometheus相容的API來查詢資料。收集到資料後再進行繪圖和展示,所以Prometheus只是作為一個數據源輔助融合。另外,對於告警模組,我們沒有使用Prometheus的alertmanger,因為我們已經有一套比較成熟的報警通知系統了。Prometheus檢測完報警之後,我們會自行開發、封裝一個Prometheus告警通知模組,再透過我們的報警通知系統將報警發出去。
Q3:請問你們是基於什麼設計的效能監控指標?是自動化干預還是手動調優?
A3:這個問題偏業務,我們中介軟體團隊其實提供了一些通用的模組,每一個介面或者QPS、時延等都是由監控自動新增的,不需要使用者來參與。而新增完之後,因為每個業務線對於效能的定義各不相同。我們不會直接干預使用者的效能調優,更多的是提供一些指標、週期的同比、環比等形式,配合一些觸發報警的條件來通知使用者。當然,我們也提供了一些報警回撥介面等,使用者可以基於報警以及他的報警回撥來觸發他自己設定的調整動作,自動處理,解決報警問題。所以基本上我們提供是能力,而不是手動干預。
Q4:請問一些服務的自定義指標,需要應用開發者來實現metrics,這部分運維如何推動?
A4:如果只是單純的運維的話,要推動開發來來實現metrics是比較困難的。從我的角度來講,我的解決方案是,提供更多通用方式。像我們中介軟體團隊會提供一些自動加鏈路的QPS延時的監控方式。對使用者的侵入越小,推動過程中可能會受到的阻力也會越小。如果真的需要推動,我可能會需要透過自上而下的方式,或者是建立一個美好的未來給使用者,讓他對實現後的效果產生期待,這時候推動起來會比較順利。
Q5:請老師再講一下,可觀測性裡面,監控資料怎麼和trace span關聯的?
A5:我們的監控系統發展得比可觀測性要早很多,所以它相對比較獨立,指標之類的也都比較成熟。在做關聯的過程中,我們其實是單獨實現了一個服務。這個服務會讀取到監控系統中配置了哪些報警,以及這些報警關聯了哪些指標資訊。知道報警關聯的指標之後,我可以透過指標反查到具體的業務。透過服務可以把指標資訊以及它需要做一些取樣頻率等推送給trace、Span的 Agent,由它來進行採集關聯。關聯之後,報警每次經過Span時就會被記錄下來,同時也會記錄報警指標的一些資訊。記錄完成之後,它會透過Kafka移到Flink處理,這個過程會建立指標和SpanID、traceID的關聯關係。
這樣一來,在報警發生時,我可以直接透過指標查詢到Span ID和traceID,透過traceID找到所有log。
Q6:請問老師有沒有做告警收斂,如何做告警收斂?
A6:告警收斂我們有做,但做的不是特別好。文章中在提到報警模組時,有提到報警抑制,這是一個比較簡單的演算法,在某塊指標多次發生閃報、恢復時進行抑制。而告警收斂是,在上層的網路服務出現問題時,大量報警湧入,這時候我們會有一個小的視窗期來對它們做聚合,也就是進行報警收斂。將所有的、相關的報警收斂成一個電話,告訴使用者:在哪個區間發生了多少報警、可能涉及到多少系統等,同時透過IM把更詳細的資訊發給使用者,而不再單獨通知所有人。這是我們做的一些告警收斂的相關工作,但還沒能達到能夠透過指標進行自動關聯的程度。
獲取本期PPT,請關注公眾號dbaplus社群
↓點這裡可回看本期直播
關注公眾號【dbaplus社群】,獲取更多原創技術文章和精選工具下載