https://www.ekongsoft.com/a/xinwenzhongxin/diannaojiankongruanjian/535.html
由於業務的多樣性,平台和系統也變得異常的復雜。如何對其進行監控和維護是我們 IT 人需要面對的重要問題。就在這樣一個紛繁復雜的環境下,監控系統粉墨登場了。
今天,我們會對 IT 監控系統進行介紹,包括其功能,分類,分層;同時也會介紹幾款流行的監控平台。
監控系統的功能
在 IT 運維過程中,常遇到這樣的情況:
- 某個業務模塊出現問題,運維人員並不知道,發現的時候問題已經很嚴重了。
- 系統出現瓶頸了,CPU 占用持續升高,內存不足,磁盤被寫滿;網絡請求突增,超出網關承受的壓力。
以上這些問題一旦發生,會對我們的業務產生巨大的影響。因此,每個公司或者 IT 團隊都會針對此類情況建立自己的 IT 監控系統。
監控系統工作流程圖
其功能包括:
- 對服務,系統,平台的運行狀態實時監控。
- 收集服務,系統,平台的運行信息。
- 通過收集信息的分析結果,預知存在的故障風險,並采取行動。
- 根據對風險的評估,進行故障預警。
- 一旦發生故障,第一時間發出告警信息。
- 通過監控數據,定位故障,協助生成解決方案。
- 最終保證系統持續、穩定、安全運行。
- 監控數據可視化,便於統計,按照一定周期導出、歸檔,用於數據分析和問題復盤。
監控系統的分類
既然監控系統對我們意義重大,針對不同場景把監控系統分為三類,分別是:
- 日志類
- 調用鏈類
- 度量類
日志類
通常我們在系統和業務級別上加入一些日志代碼,記錄一些日志信息,方便我們在發現問題的時候查找。
這些信息會與事件做相關,例如:用戶登錄,下訂單,用戶瀏覽某件商品,一小時以內的網關流量,用戶平均響應時間等等。
這類以日志的記錄和查詢的解決方案比較多。比如 ELK 方案(Elasticsearch+Logstash+Kibana),使用ELK(Elasticsearch、Logstash、Kibana)+Kafka/Redis/RabbitMQ 來搭建一個日志系統。
ELK 結合 Redis/Kafka/RabbitMQ 實現日志類監控
程序內部通過 Spring AOP 記錄日志,Beats 收集日志文件,然后用 Kafka/Redis/RabbitMQ 將其發送給 Logstash,Logstash 再將日志寫入 Elasticsearch。
最后,使用 Kibana 將存放在 Elasticsearch 中的日志數據顯示出來,形式可以是實時數據圖表。
調用鏈類
對於服務較多的系統,特別是微服務系統。一次服務的調用有可能涉及到多個服務。A 調用 B,B 又要調用 C,好像一個鏈條一樣,形成了服務調用鏈。
調用鏈就是記錄一個請求經過所有服務的過程。請求從開始進入服務,經過不同的服務節點后,再返回給客戶端,通過調用鏈參數來追蹤全鏈路行為。從而知道請求在哪個環節出了故障,系統的瓶頸在哪兒。
調用鏈監控的實現原理如下:
①Java 探針,字節碼增強
Java 代碼運行原理圖
在介紹這種方式之前,我們先來復習一下 Java 代碼運行的原理。通常我們會把 Java 源代碼,通過“Java 編譯器”編譯成 Class 文件。再把這個 Class 的字節碼文件裝載到“類裝載器”中進行字節碼的驗證。
最后,把驗證過后的字節碼發送到“Java 解釋器”和“及時編譯器”交給“Java 運行系統”運行。
Java 探針,字節碼增強的方式就是利用 Java 代理,這個代理是運行方法之前的攔截器。
在 JVM 加載 Class 二進制文件的時候,利用 ASM 動態的修改加載的 Class 文件,在監控的方法前后添加需要監控的內容。
例如:添加計時語句,用於記錄方法耗時。將方法耗時存入處理器,利用棧先特性(先進后出)處理方法調用順序。
每當請求處理結束后,將耗時方法和入參 map 輸出到文件中,然后根據 map 中相應參數,區分出耗時業務。
最后將相應耗時文件取下來,轉化為 xml 格式並進行解析,通過瀏覽器將代碼分層結構展示出來。
Java 探針工具原理圖
備注:ASM 是一個 Java 字節碼操縱框架,它可以動態生成類或者增強既有類的功能。
ASM 可以直接產生二進制 Class 文件,可以在類被載入 Java 虛擬機之前改變類行為。
Java Class 被存儲在 .class文件里,文件擁有元數據來解析類中的元素:類名稱、方法、屬性以及 Java 字節碼(指令)。
ASM 從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠生成新類。
②攔截請求
獲取每次請求服務中的信息來實現跟蹤的。這里以 Zipkin+Slueth 為例說明其原理。
Sleuth 提供鏈路追蹤。由於一個請求會涉及到多個服務的互相調用,而這種調用往往成鏈式結構,經過多次層層調用以后請求才會返回。常常使用 Sleuth 追蹤整個調用過程,方便理清服務間的調用關系。
Sleuth 服務調用追蹤圖例
每次請求都會生成一個 Trace ID,如上圖所示這個 Trace ID 在整個 Request 和 Response 過程中都會保持一致,不論經過了多少個服務。這是為了方便記錄一次調用的整個生命周期。
再看每次請求的時候都會有一個 Span ID,這里的 Span 是 Sleuth 服務跟蹤的最小單元,每經過一個服務,每次 Request 和 Response 這個值都會有所不同,這是為了區分不同的調用動作。
針對每個調用的動作,Sleuth 都做了標示如下:
- Server Received 是服務器接受,也就是服務端接受到請求的意思。
- Client Sent 是客戶端發送,也就是這個服務本身不提供響應,需要調用其他的服務提供該響應,所以這個時候是作為客戶端發起請求的。
- Server Sent 是服務端發送,看上圖SERVICE 3 收到請求后,由於他是最終的服務提供者,所以作為服務端,他需要把請求發送給調用者。
- Client Received 是客戶端接收,作為發起調用的客戶端接受到服務端返回的請求。
實際上 Sleuth 就是通過上述方式把每次請求記錄一個統一的 Trace ID,每個請求的詳細步驟記作 Span ID。
每次發起請求或者接受請求的狀態分別記錄成 Server Received,Client Sent,Server Sent,Client Received 四種狀態來完成這個服務調用鏈路的跟蹤的。
Sleuth 服務調用追蹤圖例
在調用服務的鏈路上每個被調用的服務節點都會通過 Parent ID 來記錄發起調用服務的 Span ID,由於 Span ID 是唯一確認最小服務單元的,所以知道了 Parent 的 Span ID 也就知道了誰調用自己了。
度量類
實現了時序數據庫(TimeSeriesData,TSD)的監控方案。實際上就是記錄一串以時間為維度的數據,然后再通過聚合運算,查看指標數據和指標趨勢。說白了,就是描述某個被測主體在一段時間內的測量值變化(度量)。
由於 IT 基礎設施,運維監控和互聯網監控的特性,這種方式被廣泛應用。一般對時序數據進行建模分為三個部分,分別是:主體,時間點和測量值。
通過這個例子來看一下,時序數據庫的數學模型,例如:需要監控服務器的 In/Out 平均流量:
- 整個監控的數據庫稱為“Metric”,它包含了所有監控的數據。類似關系型數據庫中的 Table。
- 每條監控數據,稱為“Point”,類似於關系型數據庫中的 Row 的概念。
- 每個“Point”都會定義一個時間戳“Timestamp”,將其作為索引,表明數據采集的時間。
- “Tag”作為維度列,表示監控數據的屬性。
- “Field”作為指標列,作為測量值,也就是測量的結果。
時序數據庫數據模型圖例
時序數據庫的存儲原理,關系型數據庫存儲采用的是 B tree,雖然降低了數據查詢的磁盤尋道時間,但是無法解決大量數據寫入時的磁盤效率。
由於監控系統的應用場景,經常會遇到大批量的數據寫入,所以我們會選擇 LSMtree(Log Structured Merge Tree)存儲時序數據庫。
LSMtree(Log Structured Merge Tree),從字面意義上理解,記錄的數據按照日志結構(Log Structured)追加到系統中,然后通過合並樹(Merge Tree)的方式將其合並。
來看一個 LevelDB 的例子,方便我們理解,LSM-tree 被分成三種文件:
- 接收寫入請求的 memtable 文件(內存中)
- 不可修改的 immutable memtable 文件(內存中)
- 磁盤上的 SStable文件(Sorted String Table),有序字符串表,這個有序的字符串就是數據的key。SStable 一共有七層(L0 到 L6)。下一層的總大小限制是上一層的 10 倍。
LSMtree LevelDB 存儲示意圖
LSMtree 寫入流程:
- 將數據追加到日志 WAL(Write Ahead Log)中,寫入日志的目的是為了防止內存數據丟失,可以及時恢復。
- 把數據寫到 memtable 中。
- 當 memtable 滿了(超過一定閥值),就將這個 memtable 轉入 immutable memtable 中,用新的 memtable 接收新的數據請求。
- immutablememtable 一旦寫滿了, 就寫入磁盤。並且先存儲 L0 層的 SSTable 磁盤文件,此時還不需要做文件的合並。
每層的所有文件總大小是有限制的(8MB,10MB,100MB… 1TB)。從 L1 層往后,每下一層容量增大十倍。
- 某一層的數據文件總量超過閾值,就在這一層中選擇一個文件和下一層的文件進行合並。
如此這般上層的數據都是較新的數據,查詢可以從上層開始查找,依次往下,並且這些數據都是按照時間序列存放的。
監控系統的分層
談完了監控系統的分類,再來聊聊監控系統的分層。用戶請求到數據返回,經歷系統中的層層關卡。
監控系統分層示意圖
一般我們將監控系統分為五層來考慮,當然也有人分成三層,大致的意思都差不多,僅供參考:
- 客戶端監控,用戶行為信息,業務返回碼,客戶端性能,運營商,版本,操作系統等。
- 業務層監控,核心業務的監控,例如:登錄,注冊,下單,支付等等。
- 應用層監控,相關的技術參數,例如:URL 請求次數,Service 請求數量,SQL 執行的結果,Cache 的利用率,QPS 等等。
- 系統層監控,物理主機,虛擬主機以及操作系統的參數。例如:CPU 利用率,內存利用率,磁盤空間情況。
- 網絡層監控,網絡情況參數。例如:網關流量情況,丟包率,錯包率,連接數等等。
流行的監控系統
前面講了監控系統的功能,分類,分層,相信大家對 IT 監控系統都有一定的了解了。
接下來,我們來看看有哪些優秀實踐。這里介紹兩個比較流行的監控系統:
- Zabbix
- Prometheus
Zabbix
Zabbix 是一款企業級的分布式開源監控方案。它由 Alexei Vladishev 創建,由 Zabbix SIA 在持續開發和支持。
Zabbix 能夠監控網絡參數,服務器健康和軟件完整性。它提供通知機制,允許用戶配置告警,從而快速反饋問題。
基於存儲的數據,Zabbix 提供報表和數據可視化,並且支持主動輪詢和被動捕獲。它的所有報告、統計信息和配置參數都可以通過 Web 頁面訪問。
Zabbix 的 API 功能,完善度很高,大部分操作都提供了 API 接口,方便和現有系統整合。
例如:通過歷史數據查詢 API,獲取線上服務器使用情況,生成報表;設置條件,對問題服務器和問題業務進行篩選,加入告警。
利用 Zabbix graph 的 API,生成關鍵指標趨勢圖,方便運維人員實時了解系統情況。利用告警添加 API,讓監控系統和部署系統聯動。
比如新部署了一個新實例,那么自動添加所需要的監控策略;反之,下線一個實例,就刪除關聯的監控策略。
Zabbix 由 Server,Agent,Proxy(可選項)組成:
- Agent 負責收集數據,並且傳輸給 Server。
- Server 負責接受 Agent 的數據,進行保存或者告警。
- Proxy 負責代理 Server 收集 Agent 傳輸的數據,並且轉發給 Server。Proxy 是安裝在被監控的服務器上的,用來和 Server 端進行通信,從而傳輸數據。
Zabbix 的部署模式
Zabbix 的數據采集,主要有兩種模式:Server 主動拉取數據和 Agent 主動上報數據。
以 Server 拉取數據為例,用戶在 Web-portal 中,設置需要監控的機器,配置監控項,告警策略。Zabbix-Server 會根據策略主動獲取 Agent 的數據,然后存儲到 MySQL 中。
同時根據用戶配置的策略,判定是否需要告警。用戶可以在 Web 端,以圖表的形式,查看各種指標的歷史趨勢。
在 Zabbix 中,將 Server 主動拉取數據的方式稱之為 Active Check。這種方式配置起來較為方便,但是會對 Zabbix-Server 的性能存在影響。
所以在生產環境中,一般會選擇主動推送數據到 Zabbix-Server 的方式,稱之為 Trapper。
即用戶可以定時生成數據,再按照 Zabbix 定義的數據格式,批量發送給 Zabbix-Server,這樣可以大大提高 Server 的處理能力。
Proxy,作為可選項,起到收集 Agent 數據並且轉發到 Server 的作用。
當 Server 和 Agent 不在一個網絡內,就需要使用 Proxy 做遠程監控,特別是遠程網絡有防火牆的時候。同時它也可以分擔 Server 的壓力,降低 Server 處理連接數的開銷。
Prometheus(普羅米修斯)
隨着這幾年雲環境的發展,Prometheus 被廣泛地認可。它的本質是時間序列數據庫,而 Zabbix 采用 MySQL 進行數據存儲。
從上面我們對時間序列數據庫的分析來看,Prometheus 能夠很好地支持大量數據的寫入。
它采用拉的模式(Pull)從應用中拉取數據,並通過 Alert 模塊實現監控預警。據說單機可以消費百萬級時間序列。
一起來看看 Prometheus 的幾大組件:
- Prometheus Server,用於收集和存儲時間序列數據,負責監控數據的獲取,存儲以及查詢。
- 監控目標配置,Prometheus Server 可以通過靜態配置管理監控目標,也可以配合 Service Discovery(K8s,DNS,Consul)實現動態管理監控目標。
- 監控目標存儲,Prometheus Server 本身就是一個時序數據庫,將采集到的監控數據按照時間序列存儲在本地磁盤中。
- 監控數據查詢,Prometheus Server 對外提供了自定義的 PromQL 語言,實現對數據的查詢以及分析。
- Client Library,客戶端庫。為需要監控的服務生成相應的 Metrics 並暴露給 Prometheus Server。
- 當 Prometheus Server 來 Pull 時,直接返回實時狀態的 Metrics。通常會和 Job 一起合作。
- Push Gateway,主要用於短期的 Jobs。由於這類 Jobs 存在時間較短,可能在 Prometheus 來 Pull 之前就消失了。為此,這些 Jobs 可以直接向 Prometheus Server 端推送它們的 Metrics。
- Exporters,第三方服務接口。將 Metrics(數據集合)發送給 Prometheus。
- Exporter 將監控數據采集的端點,通過 HTTP 的形式暴露給 Prometheus Server,使其通過 Endpoint 端點獲取監控數據。
- Alertmanager,從 Prometheus Server 端接收到 Alerts 后,會對數據進行處理。例如:去重,分組,然后根據規則,發出報警。
- Web UI,Prometheus Server 內置的 Express Browser UI,通過 PromQL 實現數據的查詢以及可視化。
Prometheus 架構圖
說完了 Prometheus 的組件,再來看看 Prometheus 的架構:
Prometheus Server 定期從 Jobs/Exporters 中拉 Metrics。同時也可以接收來自 Pushgateway 發過來的 Metrics。
Prometheus Server 將接受到的數據存儲在本地時序數據庫,並運行已定義好的 alert.rules(告警規則),一旦滿足告警規則就會向 Alertmanager 推送警報。
Alertmanager 根據配置文件,對接收到的警報進行處理,例如:發出郵件告警,或者借助第三方組件進行告警。
WebUI/Grafana/APIclients,可以借助 PromQL 對監控數據進行查詢。
最后將兩個工具進行比較如下:
Zabbix 和 Prometheus 比較圖
從上面的比較可以看出:
- Zabbix 的成熟度更高,上手更快。高集成度導致靈活性較差,在監控復雜度增加后,定制難度會升高。而且使用的關系型數據庫,對於大規模的監控數據插入和查詢是個問題。
- Prometheus 上手難度大,定制靈活度高,有較多數據聚合的可能,而且有時序數據庫的加持。
- 對於監控物理機或者監控環境相對穩定的情況,Zabbix 有明顯優勢。如果監控場景多是雲環境的話,推薦使用 Prometheus。
總結
監控系統思維導圖
監控系統對 IT 系統運維意義重大,從狀態監控到收集/分析數據,到故障報警,以及問題解決,最后歸檔報表,協助運維復盤。
監控系統分為三大類,日志類,調用鏈類,度量類,他們有各自的特點,且應用場景各不相同。
因為要對整個 IT 系統進行監控,所以將其分為五層,分別是,客戶端,業務層,應用層,系統層,網絡層。
Zabbix 和 Prometheus 是當下流行的監控系統,可以根據他們的特點選擇使用。