系統可觀測性
想象一下,有一天早上醒來,你發現腰帶上的最後一個洞塞不進去了。你走到體重秤前,發現一夜之間體重增加了很多。你開始緊急節食和健身。幾周後,看了看體重秤,發現自己的體重不知怎麼增加了更多。這是怎麼回事?
你需要了解的是你的身體正在發生什麼變化。如果我們的身體有內置可觀察性功能,我們的身體就會有指標,就可以在儀表盤上繪製激素水平。如果能看到我們的激素水平突然失衡,在所有條件都相同的情況下,可以推測激素失衡一定是根本原因。但是,由於無法看到發生了什麼變化,爲了查出問題所在需要做很多的改變,每種改變都有各自的效果。
我們讓系統可可觀測,這樣就可以提出問題深入瞭解系統,並調試意料之外的問題。這意味着我們可以解決以前沒有發生過的任意問題。接下來,我們將實現服務的可觀測,這樣我們就可以理解服務正發生什麼變化。
三類遙測數據
可觀測性是從外部輸出瞭解系統內部 (它的行爲和狀態) 的一種方式。我們使用指標 (metrics)、結構化日誌(logs) 和鏈路跟蹤 (trace) 作爲輸出,使我們的系統可觀察。雖然有三種類型的遙測數據,每一種都有自己的用途,我們將討論,它通常來自相同的事件。例如,每當 web 服務處理一個請求時,它可能會增加 “已處理請求” 指標,爲該請求發出日誌,並對請求鏈路進行跟蹤。
指標 (Metrics)
指標:度量隨時間變化的數據,例如失敗的請求數量或每個請求花費的時間。諸如此類的度量有助於定義服務級別。我們將使用指標來報告系統的運行狀況,觸發內部告警,並在看板上繪製圖形,以便一目瞭然地瞭解系統的運行情況。
因爲指標是數值類型數據,你可以逐漸降低分辨率,以減少存儲需求和查詢時間。例如,如果我們經營一家圖書出版公司,就會對每一本書的購買都有指標。爲了運送客戶的圖書,我們需要知道客戶的訂單,但是在交付了圖書並且通過了退貨政策之後,我們不再關心訂單。當我們對業務做分析時會存在很多的細節。最終,我們只需要季度收益就可以計算納稅、計算年增長率,並知道是否可以僱傭更多的編輯和作者來擴大業務。
有三類指標:
-
計數 Counters
跟蹤事件發生的次數,比如請求失敗的次數,或者系統中某些操作的總和,比如系統處理的字節數。
經常需要使用計數器來獲得一個速率:在一定時間範圍內事件發生的次數。誰會關心服務接受請求的總次數?我們關心的是在過去的一秒或一分鐘內處理了多少請求——如果請求數量顯著下降,你就需要檢查系統的延遲。你需要知道請求錯誤率何時達到峯值,這樣就可以發現哪裏出了問題並進行修復。
-
直方圖 (Histograms)
直方圖顯示的是數據的分佈情況。使用直方圖來測量請求持續時間和大小的百分比。
-
計量表 (Gauge)
追蹤某事物的當前值。可以完全替換該值。Gauge 對於飽和類型的度量很有用,比如主機的磁盤使用率或與雲提供商的限制相比負載均衡的數量。
我們可以測量任何東西,那麼應該測量什麼數據呢?” 什麼指標將在您的系統上提供有價值的信號? 以下是谷歌提出的衡量系統狀態的四個黃金信號:
-
延時:服務處理請求所需的時間。如果延遲出現峯值,通常需要通過升級一個具有更多內存、cpu 或 IOPS 的計算實例來垂直擴展你的系統,或者通過向你的負載均衡添加更多實例來水平擴展你的系統。
-
流量:你的服務需求量。對於典型的 web 服務,這可能是每秒處理的請求數。對於在線視頻遊戲或視頻流服務,它可以是併發用戶數。這些指標是可以用來炫耀你的系統規模的,但更重要的是,它們可以幫助你瞭解自己的系統狀態,以及何時需要新的系統設計來應對大規模流量。
-
錯誤:請求失敗率。內部服務器錯誤尤其重要。
-
飽和度:衡量服務的能力。例如,如果您的服務將數據持久化到磁盤,按照當前的輸入速率,會很快耗盡硬盤空間嗎? 如果你有一個內存存儲,與可用內存相比,你的服務使用了多少內存?
雖然大多數調試故事都是從參數開始的—要麼是通過警報,要麼是有人注意到看板上的異常—但都需要查看日誌和跟蹤,以瞭解有關問題的更多細節。讓我們接下來看看日誌。
結構化日誌
日誌描述系統中的事件。我們應該記錄任何可以幫助瞭解服務的事件。日誌能幫助我們排除故障、審計和配置文件,這樣我們就可以瞭解出了什麼問題以及爲什麼,誰運行了什麼操作,以及這些操作花費了多長時間。例如,gRPC 服務日誌可以記錄每個 RPC 調用:
{ "request_id": "f47ac10b-58cc-0372-8567-0e02b2c3d479", "level": "info", "ts": 1600139560.3399575, "caller": "zap/server_interceptors.go:67", "msg": "finished streaming call with code OK", "peer.address": "127.0.0.1:54304", "grpc.start_time": "2020-09-14T22:12:40-05:00", "system": "grpc", "span.kind": "server", "grpc.service": "log.v1.Log", "grpc.method": "ConsumeStream", "peer.address": "127.0.0.1:54304", "grpc.code": "OK", "grpc.time_ns": 197740 }
在這個日誌中,我們可以看到調用者的 IP 地址、他們調用的服務和方法、調用是否成功以及請求花費了多長時間。在分佈式系統中,請求 ID 有助於拼湊由多個服務處理的請求的完整圖像。
這個 gRPC 日誌是一個 JSON 格式的結構化日誌。結構化日誌是一組格式一致的鍵值對,便於程序讀取。結構化日誌使我們能夠分離日誌捕獲、傳輸、持久化和查詢。例如,我們可以用 protobuf 捕獲和傳輸我們的日誌,然後用 Parquet 格式對其進行編碼,並將它們持久化到數據庫中。
我建議在像 Kafka 這樣的事件流平臺上收集結構化日誌,以便對日誌進行任意處理和傳輸。例如,可以將 Kafka 與 BigQuery 這樣的數據庫連接起來查詢日誌,同時將 Kafka 與 GCS 這樣的對象存儲連接起來維護歷史副本。
在日誌記錄太少和沒有調試問題所需的信息之間,或者日誌記錄太多,被太多的信息淹沒和錯過重要的東西之間,需要一個平衡。我建議對錯誤日誌記錄詳細,並減少無用的日誌。這樣一來,就不太可能缺少故障排除或審覈問題所需的信息。
鏈路追蹤 (trace)
跟蹤捕獲請求的生命週期,對請求流經系統時跟蹤請求。使用 Jaegar、Stackdriver、和 Lightstep 等用戶界面,可以直觀地表示請求在系統中花費的時間。在分佈式系統中,當請求在多個服務上被處理時,這尤其有用。
你可以用詳細信息標記鏈路追蹤,以更多地瞭解每個請求。一個常見的例子是用用戶 ID 標記每個跟蹤,這樣如果用戶遇到問題,您就可以輕鬆地找到他們的請求。
鏈路追蹤包括一個或多個跨度。它可以是父 / 子關係,也可以是兄弟姐妹關係。每個跨度表示請求執行的一部分。具體如何分割這些部分取決於你自己。通常跨所有服務端到端跟蹤請求,從服務的入口點開始到出口點結束。然後深入每個服務並跟蹤重要的方法調用。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/90L9mOKYtmmvA4MxkEXkdQ