基于關(guān)鍵的可觀測(cè)性指標(biāo)了解應(yīng)用服務(wù)運(yùn)行狀態(tài),能夠提升服務(wù)運(yùn)行效能。本文分析了分布式應(yīng)用的 4 個(gè)核心可觀測(cè)性指標(biāo)。
基于關(guān)鍵的可觀測(cè)性指標(biāo),我們更能了解我們的應(yīng)用服務(wù)運(yùn)行狀態(tài),以便提升服務(wù)運(yùn)行效能。
如今,一種最為流行的架構(gòu)設(shè)計(jì)模式便是將應(yīng)用程序單體分解為更小的微服務(wù)。然后,每個(gè)微服務(wù)負(fù)責(zé)應(yīng)用程序的特定方面或功能。例如,一個(gè)微服務(wù)可能負(fù)責(zé)提供外部 API 請(qǐng)求,而另一個(gè)可能處理前端的數(shù)據(jù)獲取。
以這種方式設(shè)計(jì)一個(gè)強(qiáng)大且故障安全的基礎(chǔ)設(shè)施可能具有挑戰(zhàn)性;一起監(jiān)控所有這些微服務(wù)的操作可能更加困難。最好不要簡(jiǎn)單地依靠應(yīng)用程序日志來(lái)了解系統(tǒng)的成功和錯(cuò)誤。設(shè)置適當(dāng)?shù)谋O(jiān)控將為我們提供更完整的觀測(cè)圖,但可能很難知道從哪里開(kāi)始。在這篇文章中,我們將介紹可觀測(cè)性指標(biāo)應(yīng)該關(guān)注的那些服務(wù)領(lǐng)域,以確保大家不會(huì)錯(cuò)過(guò)關(guān)鍵信息。
在開(kāi)始本文內(nèi)容之前, 我們將對(duì)所運(yùn)行的應(yīng)用程序設(shè)置做一些假設(shè)。我們不需要使用任何特定框架來(lái)開(kāi)始跟蹤指標(biāo),但是,它確實(shí)有助于對(duì)所涉及的組件有一個(gè)大致的了解。換句話說(shuō),你如何設(shè)置你的可觀察性工具比你跟蹤什么更重要。
由于足夠大的微服務(wù)集需要某種程度的協(xié)調(diào),我們將假設(shè)使用 Kubernetes 進(jìn)行編排。我們還假設(shè)有一個(gè)時(shí)間序列數(shù)據(jù)庫(kù),如 Prometheus 或 InfluxDB,用于存儲(chǔ)我們的指標(biāo)數(shù)據(jù)。同時(shí),我們可能還需要一個(gè)入口控制器(例如 Kong 提供的用于控制流量的控制器)和服務(wù)網(wǎng)格(例如 Kuma)以更好地促進(jìn)服務(wù)之間的連接。
在實(shí)施任何監(jiān)控之前,必須了解我們的應(yīng)用服務(wù)實(shí)際上如何進(jìn)行相互交互。編寫(xiě)一份文檔,確定哪些服務(wù)和功能相互依賴,以及可用性問(wèn)題將如何影響它們,可以幫助我們制定戰(zhàn)略,圍繞為構(gòu)成適當(dāng)閾值的內(nèi)容設(shè)置基線數(shù)字。
指標(biāo)類型
我們應(yīng)該能夠從兩個(gè)角度查看數(shù)據(jù)點(diǎn):影響數(shù)據(jù)和因果數(shù)據(jù)。影響數(shù)據(jù)表示識(shí)別誰(shuí)受到影響的信息。例如,如果服務(wù)中斷并且響應(yīng)變慢,Impact Data 可以幫助確定受影響的活躍用戶的百分比。
Impact Data 確定誰(shuí)受到影響,Causal Data 確定受影響的對(duì)象及其原因。Kong Ingress 可以監(jiān)控網(wǎng)絡(luò)活動(dòng),可以讓我們深入了解影響數(shù)據(jù)。同時(shí),Kuma 可以收集和報(bào)告因果數(shù)據(jù)。
讓我們看一下幾個(gè)數(shù)據(jù)源,并探索可以收集到的影響數(shù)據(jù)和因果數(shù)據(jù)之間的差異。
1、延遲
延遲是用戶執(zhí)行操作與其最終結(jié)果之間所花費(fèi)的時(shí)間。例如,如果用戶將一件商品添加到他們的購(gòu)物車中,則延遲將衡量從添加商品到用戶看到表明添加成功的響應(yīng)之間的時(shí)間。如果負(fù)責(zé)執(zhí)行此操作的服務(wù)降級(jí),則延遲會(huì)增加,并且如果沒(méi)有立即響應(yīng),用戶可能會(huì)懷疑該站點(diǎn)是否正在運(yùn)行。
為了在影響數(shù)據(jù)上下文中正確跟蹤延遲,有必要在整個(gè)生命周期中跟蹤單個(gè)事件。繼續(xù)我們的采購(gòu)示例,我們可能希望事件的完整流程如下所示:
客戶點(diǎn)擊“加入購(gòu)物車”按鈕
瀏 覽器發(fā)起服務(wù)器端請(qǐng)求,發(fā)起事件
服務(wù)器接受請(qǐng)求
數(shù)據(jù)庫(kù)查詢確保產(chǎn)品仍有庫(kù)存
解析數(shù)據(jù)庫(kù)響應(yīng),向用戶發(fā)送響應(yīng),事件完成
要成功地遵循此順序,我們應(yīng)該標(biāo)準(zhǔn)化一個(gè)命名模式,以標(biāo)識(shí)正在發(fā)生的事情和發(fā)生的時(shí)間,例如 customer_purchase.initiate、customer_purchase.queried、customer_purchase.finalized 等?;谒捎玫木幊陶Z(yǔ)言,我們可能能夠?yàn)橹笜?biāo)服務(wù)提供功能塊或 lambda:
statsd.timing('customer_purchase.initiate') do# ...end
通過(guò)提供特定的關(guān)鍵字,我們應(yīng)該確定在出現(xiàn)延遲問(wèn)題時(shí)事件的哪個(gè)部分變慢。
跟蹤因果數(shù)據(jù)上下文中的延遲需要我們跟蹤服務(wù)之間事件的速度,而不僅僅是執(zhí)行的操作。實(shí)際上,這意味著定時(shí)服務(wù)到服務(wù)請(qǐng)求:
statsd.histogram('customer_purchase.initiate') dostatsd.histogram('customer_purchase.external_database_query') do# ...endend
這不應(yīng)僅限于捕獲整個(gè)端點(diǎn)請(qǐng)求/響應(yīng)周期。這種延遲跟蹤太廣泛了,應(yīng)該更細(xì)化。假設(shè)我們有一個(gè)帶有發(fā)出內(nèi)部數(shù)據(jù)庫(kù)請(qǐng)求的端點(diǎn)的微服務(wù)。在這種情況下,我們可能希望計(jì)算收到請(qǐng)求的時(shí)間、查詢花費(fèi)的時(shí)間、服務(wù)響應(yīng)請(qǐng)求的時(shí)間以及原始客戶端收到該請(qǐng)求的時(shí)間。通過(guò)這種方式,我們可以精確地確定服務(wù)如何相互通信。
2、流量
如果希望我們的應(yīng)用程序有用且受歡迎——但此時(shí),我們還沒(méi)有做好準(zhǔn)備,大量用戶涌入可能是一件好事!網(wǎng)站流量的變化很難預(yù)測(cè)。我們可能能夠每天為用戶負(fù)載提供服務(wù),但事件(預(yù)期的和意外的)可能會(huì)產(chǎn)生意想不到的后果。我們的電子商務(wù)網(wǎng)站是否在進(jìn)行周末促銷?我們的網(wǎng)站是否因?yàn)橐恍┮馔獾馁澝蓝呒t?流量差異也會(huì)受到地理位置的影響。也許日本用戶正在以一種法國(guó)用戶沒(méi)有的方式體驗(yàn)流量負(fù)載。我們可能認(rèn)為我們的系統(tǒng)正在按預(yù)期工作,但所需要的只是大量用戶涌入來(lái)測(cè)試這種信念。如果一個(gè)事件需要 200 毫秒才能完成,但我們的系統(tǒng)一次只能處理一個(gè)事件,那么看起來(lái)似乎沒(méi)有問(wèn)題——直到事件隊(duì)列突然被工作堵塞為止。
與延遲類似,跟蹤整個(gè)事件生命周期中正在處理的事件數(shù)量以了解任何瓶頸很有用。例如,跟蹤隊(duì)列中的作業(yè)數(shù)、每秒完成的 HTTP 請(qǐng)求數(shù)和活動(dòng)用戶數(shù)是監(jiān)控流量的良好起點(diǎn)。
對(duì)于因果數(shù)據(jù),監(jiān)控流量涉及捕獲服務(wù)如何相互傳輸信息,類似于我們?nèi)绾翁幚硌舆t。我們的監(jiān)控設(shè)置應(yīng)該跟蹤對(duì)特定服務(wù)的請(qǐng)求數(shù)量、它們的響應(yīng)代碼、它們的有效負(fù)載大小等——盡可能多地了解請(qǐng)求和響應(yīng)周期。當(dāng)我們需要調(diào)查惡化的性能時(shí),了解哪個(gè)服務(wù)遇到問(wèn)題將有助于我們更快地跟蹤可能的來(lái)源。
3、錯(cuò)誤率
跟蹤錯(cuò)誤率相當(dāng)簡(jiǎn)單。我們的服務(wù)器作為 HTTP 響應(yīng)發(fā)出的任何 5xx(甚至 4xx)都應(yīng)該被標(biāo)記和計(jì)數(shù)。即使我們已經(jīng)考慮到的情況,例如捕獲的異常,也應(yīng)該受到監(jiān)視,因?yàn)樗鼈內(nèi)匀淮矸抢硐霠顟B(tài)。這些問(wèn)題可以作為防御性編碼產(chǎn)生的更深層次問(wèn)題的警告,這些問(wèn)題沒(méi)有解決實(shí)際問(wèn)題。
Kuma 可以捕獲我們的服務(wù)拋出的錯(cuò)誤代碼和消息,但這僅代表可操作數(shù)據(jù)的一部分。例如,我們還可以捕獲導(dǎo)致錯(cuò)誤的參數(shù)(萬(wàn)一查詢格式錯(cuò)誤)、發(fā)出的數(shù)據(jù)庫(kù)查詢(萬(wàn)一超時(shí))、執(zhí)行用戶的權(quán)限(萬(wàn)一他們進(jìn)行了未經(jīng)授權(quán)的嘗試)、等等。簡(jiǎn)而言之,捕獲產(chǎn)生錯(cuò)誤時(shí)的服務(wù)狀態(tài)可以幫助我們?cè)陂_(kāi)發(fā)和測(cè)試環(huán)境中復(fù)制問(wèn)題。
4、飽和度
除此之外,我們還應(yīng)該跟蹤每個(gè)微服務(wù)的內(nèi)存使用情況、CPU 使用情況、磁盤讀/寫(xiě)和可用存儲(chǔ)。如果我們服務(wù)的資源使用在某些時(shí)間或操作期間經(jīng)常激增或以穩(wěn)定的速度增加,則表明應(yīng)用服務(wù)過(guò)度使用了服務(wù)器資源。雖然服務(wù)器可能按預(yù)期運(yùn)行,但再次涌入的流量或其他不可預(yù)見(jiàn)的事件可能會(huì)迅速推翻它。
Kong Ingress 只監(jiān)控網(wǎng)絡(luò)活動(dòng),因此不太適合跟蹤飽和度。但是,有許多工具可用于使用 Kubernetes 進(jìn)行跟蹤。
實(shí)施監(jiān)控和可觀察性
到目前為止,我們已經(jīng)討論了在云應(yīng)用程序中跟蹤很重要的指標(biāo)類型。接下來(lái),讓我們深入了解我們可以采取的一些具體步驟來(lái)實(shí)現(xiàn)這種監(jiān)控和可觀察性。
1、安裝 Prometheus
Prometheus 是監(jiān)控的首選標(biāo)準(zhǔn),是一個(gè)易于安裝并與 Kubernetes 設(shè)置集成的開(kāi)源系統(tǒng)。如果基于 Helm 部署,則安裝會(huì)特別簡(jiǎn)單。
首先,我們創(chuàng)建一個(gè)監(jiān)控命名空間:
[administrator@JavaLangOutOfMemory ~] % kubectl create namespace monitoring
接下來(lái),我們使用 Helm 安裝 Prometheus。我們確保也將 Prometheus 圖表添加到 Helm:
[administrator@JavaLangOutOfMemory ~] % helm repo add prometheus-community [administrator@JavaLangOutOfMemory ~] % helm repo add stable [administrator@JavaLangOutOfMemory ~] % helm repo update[administrator@JavaLangOutOfMemory ~] % helm install -f -n monitoring prometheus prometheus-community/prometheus
中引用的值文件將 Prometheus 的數(shù)據(jù)抓取間隔設(shè)置為 10 秒。
2、在 Kong 中啟用 Prometheus 插件
假設(shè)正在為 Kubernetes 使用 Kong Ingress Controller (KIC),我們的下一步將是創(chuàng)建一個(gè)自定義資源——KongPlugin 資源——它集成到 KIC 中。創(chuàng)建一個(gè)名為 prometheus-plugin.yml 的文件:
apiVersion: configuration.konghq.com/v1kind: KongClusterPluginmetadata:name: prometheusannotations:kubernetes.io/ingress.class: konglabels:global: "true"plugin: prometheus
3、安裝 Grafana
Grafana 是一個(gè)可觀察性平臺(tái),它為 Prometheus 抓取的數(shù)據(jù)的可視化提供了出色的儀表板。我們使用 Helm 安裝 Grafana 如下:
administrator@JavaLangOutOfMemory ~ % helm install grafana stable/grafana -n monitoring --values
我們可以查看上述命令中的 bit.ly URL,以查看我們?cè)诎惭b時(shí)提供的 Grafana 的具體配置值。
4、啟用端口轉(zhuǎn)發(fā)
現(xiàn)在 Prometheus 和 Grafana 在我們的 Kubernetes 集群中啟動(dòng)并運(yùn)行,我們需要訪問(wèn)他們的儀表板。在本文中,我們將設(shè)置基本端口轉(zhuǎn)發(fā)以公開(kāi)這些服務(wù)。這是一種簡(jiǎn)單但不是很安全的訪問(wèn)方式,但不建議用于生產(chǎn)部署。
[administrator@JavaLangOutOfMemory ~] % POD_NAME=$(kubectl get pods --namespace monitoring -l "app=prometheus,component=server" -o jsonpath="{.items[0].metadata.name}")kubectl --namespace monitoringport-forward $POD_NAME 9090 &[administrator@JavaLangOutOfMemory ~] % POD_NAME=$(kubectl get pods --namespace monitoring -l "app.kubernetes.io/instance=grafana" -o jsonpath="{.items[0].metadata.name}")kubectl --namespace monitoring port-forward $POD_NAME 3000 &
以上兩個(gè)命令在端口 9090 上公開(kāi) Prometheus 服務(wù)器,在端口 3000 上公開(kāi) Grafana 儀表板。
這些簡(jiǎn)單的步驟應(yīng)該足以讓其開(kāi)始運(yùn)行。使用 Kong Ingress Controller 及其集成的 Prometheus 插件,使用 Prometheus 捕獲指標(biāo)并使用 Grafana 將它們可視化設(shè)置起來(lái)既快速又簡(jiǎn)單。
結(jié)論
每當(dāng)我們需要調(diào)查惡化的性能時(shí),我們的影響數(shù)據(jù)指標(biāo)都可以幫助我們確定問(wèn)題的嚴(yán)重程度:它應(yīng)該告訴我們有多少人受到影響。同樣,我們的因果數(shù)據(jù)確定什么不起作用以及為什么。前者將我們指向一縷煙,后者將我們 指向火。
除了上述所有因素外,我們還應(yīng)該考慮指標(biāo)變化的速度。例如,假設(shè)我們的流量數(shù)字正在增加。觀察這些數(shù)字的變化速度可以幫助我們確定何時(shí)(或是否)它會(huì)成為問(wèn)題。這對(duì)于通過(guò)定期部署和服務(wù)更改來(lái)管理即將進(jìn)行的工作至關(guān)重要。它還確定了理想的性能指標(biāo)應(yīng)該是什么。
Google 寫(xiě)了整本關(guān)于站點(diǎn)可靠性的書(shū),這是任何開(kāi)發(fā)人員的必讀之書(shū)。如果我們已經(jīng)在集群旁邊運(yùn)行 Kong,那么像這樣的插件直接與 Prometheus 集成,這意味著我們可以減少用于監(jiān)控和存儲(chǔ)服務(wù)指標(biāo)的配置。
【作者】李杰,專注于Java虛擬機(jī)技術(shù)、云原生技術(shù)領(lǐng)域的探索與研究。