自動化流程設計的核心目標在於減少人工介入,提升效率。構建有效的通知機制至關重要,選擇合適的通知方式如電子郵件或專業服務,並善用通訊群組簡化管理。錯誤處理流程需謹慎設計,記錄錯誤資訊並逐步建立自動修復機制。持續改進是自動化流程的關鍵,需定期檢視並根據實際情況最佳化。系統可觀測性同樣重要,透過指標和日誌分析,能更深入地瞭解系統執行狀態,減少維運盲點。開發和維運團隊需要更緊密合作,共同理解業務背景,並設計有效的監控指標,例如吞吐量、錯誤率和延遲。日誌管理也至關重要,集中式日誌管理能更好地追蹤系統事件,提升故障排除效率。
自動化流程的結構化設計與持續改進
在設計自動化流程時,重點在於如何消除不必要的人工干預,從而提高團隊的工作效率與協作關係。本章節將探討如何結構化地設計自動化流程,包括通知機制、錯誤處理以及持續改進的方法。
通知機制的設計
在自動化流程中,通知機制扮演著至關重要的角色。選擇適當的通知方式可以避免不必要的麻煩。常見的通知方式包括電子郵件、簡訊以及透過專業的通知服務如PagerDuty或Opsgenie等。
使用現有的通知系統
盡可能使用現有的通知系統可以簡化訊息處理的流程,讓使用者自行組態通知方式(如電子郵件、簡訊或電話),並由服務提供者負責訊息的傳遞。然而,這種方法的缺點是會限制通知的物件範圍,因為只有擁有該服務帳戶的使用者才能接收通知。
電子郵件通知的設計
若無法使用專業的通知服務,則電子郵件成為主要的通知方式。在設計電子郵件通知時,應避免直接在應用程式中維護個別的電子郵件地址,而是盡可能使用通訊群組,以減少因人員變動而需要調整郵件列表的工作量。
使用通訊群組的好處包括:
- 減少因人員更動而需要調整郵件列表的工作
- 當員工離職時,終止流程可以自動移除相關使用者,避免產生退信
- 通知列表的管理可以交由組織的服務台流程處理
錯誤處理
在自動化任務中,錯誤處理是一個複雜的問題。雖然處理常見的錯誤模式是必要的,但過度自動化的錯誤處理可能會導致意想不到的後果。
謹慎處理錯誤
對於已知的錯誤情況,應當提供足夠的資訊讓使用者瞭解錯誤的原因,並確保任務可以重新啟動。將錯誤訊息記錄在相同的日誌系統中(如工單系統),以便於後續的故障排除。
自動還原與錯誤處理
若程式能夠偵測到錯誤並選擇適當的修復路徑,則應當將錯誤偵測結果及修復過程記錄在日誌系統中。隨著對錯誤情境的瞭解加深,可以逐步建立起一套完善的自動修復機制。
持續改進
在實作自動化流程後,持續改進是確保其有效執行的關鍵。應當定期檢視自動化流程,並根據新的使用案例進行更新和最佳化。
承諾持續改進
自動化流程的設計與實作不是一次性的任務,需要持續投入時間進行迭代和最佳化。透過消除人工干預,團隊成員可以獲得更多的自主權,從而改善團隊之間的關係,提高工作效率。
維運盲點:如何提升系統可觀測性
在啟動系統時,我們期望它能夠按照預定的順序執行一系列任務,並產生預期的結果。但在實際操作中,系統的複雜性往往導致我們難以準確掌握其執行狀態,尤其是在出現錯誤時。這種現象被稱為「維運盲點」(Operational Blindness)。
戰鬥故事:一次真實的維運盲點經歷
某天,一個通知在維運團隊中傳出,緊接著電子郵件和即時訊息也紛紛發出。團隊成員開始聚集,試圖確定通知是否只是單純的電腦問題還是更大的系統故障。網站已經宕機,外部監控系統在過去的三次健康檢查中都失敗了,這才觸發了警示。
不幸的是,這個警示並不足以讓團隊快速定位問題,因此他們只能從頭開始排查。首先,他們檢查了常見的嫌疑物件——Web伺服器的系統指標,看起來一切正常。記憶體使用率正常,CPU使用率雖然有小幅上升但仍在可接受範圍內,磁碟效能也正常。接著,他們對資料函式庫層進行了同樣的檢查,同樣沒有發現異常。
維運團隊將問題升級至開發團隊,因為伺服器看起來運作正常。但開發團隊也不完全清楚該關注哪些方面,由於無法直接存取生產系統,他們不得不與維運團隊協同工作,共同排查問題。最終,他們發現資料函式庫中有大量查詢正在執行,其中大多數處於等待狀態。同時,Web伺服器上也有大量的處理程式,很可能是等待對應的SQL查詢完成。某個時刻,Web伺服器達到了容量上限,停止了對新請求的回應,包括健康檢查頁面。
經過深入調查,團隊成功取消了阻塞查詢,讓其他查詢得以完成,Web伺服器也得以清空佇列並重新開始處理新請求。
問題根源:缺乏有效的系統指標和日誌分析
在這個案例中,大量的時間被浪費在嘗試確定問題根源上。當問題被升級時,接收問題的人員並沒有足夠的許可權去檢視對他們有用的系統檢視。相反,他們仍然嚴重依賴維運團隊。在這個場景中,每一分鐘的停機時間都意味著金錢損失,因此這種依賴關係現在有了明確的經濟成本。
儘管團隊擁有大量的系統指標圖表和警示,但他們並沒有因此更接近於理解系統何時出現了異常行為。CPU使用率的峰值是否相關?如果CPU使用率達到90%,是否會影響客戶?團隊監控這些指標是因為在很多情況下,這是他們唯一能夠獲得的資訊。在上述例子中,這些系統指標看似正常,這耗盡了團隊的故障排除能力,迫使他們將問題升級。但即使在升級後,那些本該有用的指標也沒有被收集,因此也沒有被用於警示。系統並沒有提出(和回答)關於其效能的正確問題。
對於許多組織來說,日誌中包含了對系統執行狀態的寶貴見解。例如,可以組態資料函式庫將長時間執行的查詢記錄到日誌中。但由於種種原因,這些見解仍然被鎖定,未被用於理解系統效能。
改變開發和維運的視野
在本章中,您將學習到DevOps組織如何看待指標,以及這些指標如何告訴您系統在業務背景下的效能狀況。為了理解這些業務背景,開發人員和維運人員需要對他們所支援的應用系統有更深入的瞭解。本章將介紹不同的方法來產生應該在系統中追蹤的指標。最後,本章將討論日誌和日誌聚合的問題。隨著系統變得越來越廣泛和分散,集中式日誌管理在任何規模的組織中都成為了一種必要。
從傳統角色到DevOps的轉變
傳統上,開發和維運之間有一條清晰的分界線。維運負責底層硬體和基礎設施,這使得應用程式交付成為可能。但這種定義是短視的。如果伺服器啟動了,網路運作正常,CPU和記憶體統計資料看起來正常,那麼應用程式中的任何問題都一定是由於程式碼寫得不好。同樣,開發人員也不為他們的程式碼在投入生產後的問題負責。在本地開發環境中無法重現的問題顯然是基礎設施相關的問題。應用程式在開發模式和生產模式下的表現差異一定是維運團隊的問題!
這些故事聽起來是否很熟悉?多年來,很多組織都是這樣運作的。但DevOps正在改變這兩個團隊的工作方式。
隨著每一家公司基本上都成為了一家軟體公司,維運團隊所支援的應用程式不再只是次要的內部使用應用程式。在許多組織中,這些應用程式是收入驅動因素,是公司盈利能力的核心。隨著從內部工具到收入產生的轉變,對應用程式有更深入瞭解的壓力越來越大。
服務中斷可能會讓公司損失一大筆錢。著名的Knight Capital事件由於軟體組態問題導致交易平台在股票市場上進行錯誤交易,從而導致每分鐘損失1000萬美元(http://mng.bz/aw7X)。我相信當應用程式故障時,他們的CPU和記憶體圖表看起來完全正常!CPU和記憶體層級的指標並不總是能說明業務故事!
3.3 瞭解產品運作
您的應用程式究竟做了什麼?乍看之下,這似乎是個簡單的問題。一個基本的電子商務公司看起來似乎很簡單:使用者造訪網站、將商品加入購物車、結帳,然後公司將商品寄給客戶。但即使是像電子商務這樣看似簡單的網站,當你深入觀察時,也會變得極為複雜。例如,您可能會問以下問題:
- 您的應用程式是否自行處理信用卡付款,還是與第三方服務互動?
- 是否在購買完成前驗證庫存,還是之後才進行?
- 訂單資料如何傳輸到物流設施?
- 信用卡交易是以同步還是非同步方式處理?
- 如何產生附加商品的推薦?
這些只是系統可能具有的互動型別的幾個例子。瞭解每一個運作機制對於理解您的應用程式效能至關重要。
瞭解您所支援的產品,有助於更好地理解需要產生和監控的指標型別,以驗證系統是否按預期運作。如果您知道您的應用程式與第三方服務介面以處理信用卡付款,您可能會建立一個指標來觀察應用程式處理信用卡付款的速度。如果這個指標下降,可能表明第三方服務出現問題,導致其處理時間增加。傳輸到物流設施的訂單是否被確認?如果傳送的訂單和確認的訂單之間出現巨大差異,可能意味著這兩個系統之間的通訊出現問題。
許多這類別資訊對開發人員來說是自然而然的,因為他們的工作就是構建這些系統。(瞭解系統為什麼以特定方式運作是另一個話題。)但這種程度的理解在過去往往超出許多維運團隊的範疇。他們更關注基礎設施和網路建設,將應用程式的部分留給開發人員。
3.4 建立維運可視性
在DevOps組織中,情況不能再是這樣。在DevOps組織中,目標是繼續推動和實作更快地向最終使用者交付功能和產品。這最終會減少團隊之間的協調。(協作和協調並不相同。)維運團隊對異常情況的反應能力取決於對正常情況的瞭解。這種瞭解只能透過對產品的理解和對產品長期觀察而來。不瞭解產品的維運工程師很快就會被像是亞馬遜的基礎設施即服務(IaaS)解決方案所取代。如果您不瞭解我的產品,那麼是什麼讓您比服務API更有用?您對工具的專業知識加上對公司產品和業務的瞭解,才是使維運工程師有價值和必要的關鍵。瞭解產品在DevOps組織中是必不可少的。如果您不從業務角度理解並增加價值,您可能只是離失業只有一個API呼叫之遙。
3.4 建立維運可視性
維運可視性主要來自兩個來源:指標和日誌。兩者看似可以互換,但實際上並非如此。指標是在某一時刻對系統資源的測量。另一方面,日誌是系統產生的訊息,描述系統中發生的事件。日誌往往更詳細地描述事件,提供比指標更細微的細節。
本文重點介紹指標,但我們稍後在本章中會回來討論日誌。
指標是溝通系統中各種活動狀態的好方法。不幸的是,一旦超出標準系統指標(如CPU、記憶體利用率和磁碟利用率),就需要由工程師設計、開發和視覺化對應用程式和支援團隊最重要的指標。考慮到這一點,建立維運可視性的第一步是超越系統指標,為您的應用程式開發自定義指標。
在處理系統時,系統正在執行的工作的三個特性幾乎是普遍有用的。這些指標是吞吐量、錯誤率和延遲。或者換個角度思考,問自己三個關於您正在測量的事情的問題:這件事發生的頻率是多少?它失敗的頻率是多少?完成它需要多長時間?
吞吐量定義為在任何給定時間流經系統的工作量。如果您正在執行Web伺服器,您的吞吐量就是您在任何給定時間處理的請求數量。吞吐量的時間範圍受到系統活動量的影響很大。在一個適度流行的網站上,您可能會以每秒點選次數來衡量吞吐量。吞吐量可以幫助您瞭解系統的繁忙程度。您還可以將這些指標置於更具業務導向的背景下,例如每秒訂單數。這可能是根據在給定時間內完成訂單(結帳)的使用者數量。
內容解密:
此段落介紹了建立維運可視性的重要性,並說明瞭指標和日誌之間的區別。主要闡述瞭如何透過自定義指標來監控系統的運作狀態,包括吞吐量、錯誤率和延遲等關鍵指標。其中,吞吐量是指系統在單位時間內處理的工作量,例如Web伺服器的請求數量。這些指標有助於瞭解系統的繁忙程度和運作效能,並可以與業務指標(如每秒訂單數)相結合,以更好地評估系統的運作狀態。
此圖示展示了一個簡單的錯誤處理流程。如果發生錯誤,則記錄錯誤並傳送警示;否則繼續執行直到結束。
內容解密:
此Plantuml圖表示了一個錯誤處理流程,主要步驟包括檢查是否發生錯誤,如果發生錯誤則進行記錄並傳送警示,如果沒有錯誤則繼續執行直到結束。此圖示清晰地展示了錯誤處理的基本邏輯和流程,能夠幫助讀者更好地理解相關概念。
運作盲點:建立運作可視性
在監控系統運作時,錯誤計數(Error Counts)和錯誤率(Error Rates)是兩個不同的指標。錯誤計數是大多數工程師熟悉的指標,它記錄了自程式或系統啟動以來發生的錯誤數量。每個系統都有一個工作單元,例如網頁請求。該工作單元將根據應用程式內的標準被視為成功或失敗。錯誤計數就是系統遇到的失敗工作單元的簡單計數。
錯誤率則是根據錯誤計數計算出來的,以總請求數的百分比表示。要計算錯誤率,需要將失敗的工作單元數量除以總工作單元數量。例如,如果工作單元是網頁點選,且收到 100 次點選,那就是總工作單元數量。如果其中 10 次點選導致請求失敗,那麼錯誤率就是 10%(10 除以 100)。
錯誤率比錯誤計數更有用,因為它們為不熟悉系統的人提供了上下文。例如,每分鐘 500 次錯誤聽起來很多,直到你意識到在該取樣期間總點選次數是 100,000 次。「500」這個數字可能會讓不熟悉正常運作量的人感到警惕,但 0.005% 則傳達了錯誤在總流量中的比例。它還可以使警示在流量波動時更容易管理。
最後,延遲(Latency)是衡量特定操作完成所需時間的指標。以網頁請求為例,延遲是指網頁請求完成所需的時間。當與吞吐量(Throughput)結合時,延遲可以為未來的容量規劃提供訊號。如果你可以同時處理 5 個請求,且每個請求的處理延遲為 1 秒,那麼如果你每秒收到 10 個請求,你就會知道你的系統將會出現無限增長的待處理請求,因為你沒有足夠的容量來處理你的請求量!每當你思考該衡量什麼指標時,幾乎總是可以迴歸到這三種型別的指標。
建立自定義指標
建立自定義指標對於提高應用程式的運作可視性至關重要。實施細節將根據所使用的監控解決方案而有很大差異。本文重點介紹定義這些自定義指標的機制,而不是嘗試列舉公司可能擁有的所有可能組態。實施這些指標的任務將留給讀者。
指標最常見的記錄方式有兩種:Gauge 和 Counter。Gauge 代表某個特定時刻的離散讀數。可以把它想像成汽車的速度計。當你低頭讀取速度時,這是你當前速度在特定時刻的測量值。系統中的 Gauge 示例可能就像「可用磁碟空間」一樣簡單。該指標在某一時刻被讀取和記錄。
Counter 是一種始終遞增的值,代表特定事件發生的次數。可以把它想像成汽車的里程錶。它每次行駛一英里就增加一。Counter 示例可能是網頁點選次數。每次使用者存取網站時,Counter 就增加一,以標記存取。透過一些數學計算,你可以在特定時間間隔內測量 Counter 的變化率,從而計算事件發生的速率。如果第一次檢查 Counter 的值是 100,一小時後第二次檢查的值是 200,那麼你可以確定你的 Counter 的運作速率是 100 事件/小時。如果你想要更精細的測量結果,只需更頻繁地取樣即可。
決定要測量的內容
決定要測量什麼可能是一項艱鉅的任務。本文重點介紹佇列系統。大多數應用程式系統都有某種形式的佇列系統,並且有一些常見的模式適用於幾乎任何佇列系統架構。
佇列系統用於將大型工作分解成較小的部分,同時允許以非同步方式執行工作並分離關注點。在佇列系統中,建立工作的流程和執行工作的流程可以分離。這使得處理工作的速度和對系統資源的壓力具有靈活性。
佇列系統的核心是訊息佇列本身。發布者流程負責完成工作並在佇列上建立訊息。消費者流程負責讀取這些訊息並根據需要執行特定的任務。圖 3.1 顯示了一個突出此過程的圖表。
此圖示說明
此圖示呈現了一個典型的佇列系統的三個元件:生產者、訊息佇列和消費者。生產者負責建立工作並在訊息佇列上發布訊息,以向其他流程發出需要完成某種工作的訊號。消費者接收由訊息佇列分派的工作,並執行必要的處理。訊息佇列充當正在進行的工作和等待完成的工作之間的緩衝區,將工作分派給可用的消費者。
自定義指標與佇列系統監控
監控佇列系統時,需要關注生產者、訊息佇列和消費者的效能指標。例如,可以測量生產者發布訊息的速率、訊息佇列中的訊息數量,以及消費者處理訊息的速率。這些指標可以幫助你瞭解佇列系統的工作負載,並找出潛在的瓶頸。
自定義指標實踐
import time
from prometheus_client import Counter, Gauge
# 定義一個 Counter 來記錄訊息發布的次數
message_published = Counter('message_published', 'Number of messages published')
# 定義一個 Gauge 來記錄訊息佇列中的訊息數量
message_queue_size = Gauge('message_queue_size', 'Size of the message queue')
def publish_message(message):
# 發布訊息
# ...
message_published.inc() # Counter 增加 1
def get_queue_size():
# 取得訊息佇列的大小
size = # ...
message_queue_size.set(size) # 設定 Gauge 的值
while True:
# 模擬發布訊息和取得佇列大小
publish_message("example message")
get_queue_size()
time.sleep(1)
內容解密:
message_published是一個Counter,用於記錄訊息發布的次數。每當發布一條訊息時,message_published.inc()就會被呼叫,使Counter增加 1。message_queue_size是一個Gauge,用於記錄訊息佇列中的訊息數量。get_queue_size()函式取得佇列的大小,並使用message_queue_size.set(size)設定Gauge的值。- 在這個範例中,我們使用了一個無限迴圈來模擬不斷發布訊息和取得佇列大小的過程。這樣,我們就可以持續監控佇列系統的狀態。
透過定義和收集這些自定義指標,你可以更好地瞭解你的應用程式和佇列系統的工作狀態,並及時發現潛在的問題。
運作盲點:真實世界的佇列系統範例
信箱是佇列系統的一個真實範例。當你需要寄信時,你成為了系統中的發布者。你準備好訊息並將其送到信箱。信箱扮演著佇列的角色,接受你的訊息並等待消費者(郵局)來取信。郵局工作人員會停靠在信箱旁,清空佇列,並開始將信件送到預期的收件人手中。這種設計的力量在於,作為發布者,你不需要了解郵局如何將信件送到收件人手中的內部運作機制。你只需按照約定的協定將訊息放入佇列中(寄件人地址、收件人地址和郵票都是郵寄信件協定的一部分)。如果信箱經常填滿,郵局可以增加清空信箱的頻率;如果信箱經常是空的,郵局工作人員可能會減少檢查的頻率。
應用程式中的佇列系統模式
佇列系統是應用程式中常見的模式。對於一個佇列系統,有幾個重要的指標需要被監控。透過檢視應用程式結構的每個部分,可以開始思考需要測量的內容。這個系統有三個階段:訊息需要被發布、訊息需要被佇列、以及訊息需要被消費和處理。這三個動作結合起來代表了佇列系統的吞吐量。但是,如果沒有監控,如果處理速度變慢或停止,就無法瞭解可能導致問題的原因。指標可以幫助解決這個問題。透過為這三個獨立的元件新增指標,可以開始監控系統。
生產者指標
生產者負責將訊息發布到佇列中供消費者處理。要追蹤這一點,需要知道生產者正在履行其職責。這裡最合適的指標是計數發布的訊息數量。我將這個指標稱為 messages.published.count。對於每一個被發布的訊息,messages.published.count 增加 1。如果每分鐘取樣這個指標,就可以比較 messages.published.count 的值,以確定訊息被發布的速率。這個指標允許你一眼看出三個關鍵的事項:
- 如果發布的訊息數量停止增加,你就知道整個訊息處理系統的吞吐量正在受到生產者端的影響。
- 如果發布的訊息數量激增,你可以確定大量的訊息可能會壓倒消費者端的工作處理能力,產生待處理的積壓。
- 如果發布的訊息數量開始以較慢的速度增加,你可以確定進入的工作速率已經減慢,因此訊息處理系統的吞吐量也會減慢。
佇列指標
轉到系統的佇列部分,可以建立和觀察兩個主要的指標。首先是佇列的大小,這將是一個測量指標。瞭解佇列的大小可以告訴你一些關於系統行為的事情。我將這個指標稱為 messages.queue.size。看到佇列持續增長可能是消費者移動速度比生產者慢的跡象。持續增長的佇列對應用程式來說可能是災難性的。沒有一個佇列是完全無邊界的。最終,佇列將達到容量上限,然後佇列系統將開始拒絕新的訊息。
佇列延遲指標
除了佇列大小之外,佇列延遲是另一個有用的指標。佇列延遲代表了一個訊息在佇列中等待被消費者拾取和處理的平均時間。這很大程度上取決於應用程式碼,需要修改應用程式來發出這個指標。但是更改相當簡單直接。首先,需要確保發布到佇列的訊息具有某種形式的日期/時間戳與之相關聯。大多數訊息匯流排會自動執行此操作,但可以明確地為每個單獨的訊息執行此操作,以便在訊息匯流排平台上保持一致性。對生產者程式碼進行簡單的修改就可以用這些資料標記每個訊息。然後,當消費者檢索到該訊息時,它會進行一些日期數學運算,以確定現在和訊息發布欄位上的日期/時間戳之間的經過時間。現在,消費者在開始處理該訊息所需的工作之前發出該指標。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title 自動化流程設計與系統可觀測性提升
package "系統架構" {
package "前端層" {
component [使用者介面] as ui
component [API 客戶端] as client
}
package "後端層" {
component [API 服務] as api
component [業務邏輯] as logic
component [資料存取] as dao
}
package "資料層" {
database [主資料庫] as db
database [快取] as cache
}
}
ui --> client : 使用者操作
client --> api : HTTP 請求
api --> logic : 處理邏輯
logic --> dao : 資料操作
dao --> db : 持久化
dao --> cache : 快取
note right of api
RESTful API
或 GraphQL
end note
@enduml
此圖示說明瞭生產者發布訊息、訊息在佇列中等待、消費者檢索訊息並計算停留時間,最後發出佇列延遲指標的流程。
內容解密:
- 生產者發布訊息:生產者負責將包含時間戳的訊息發布到佇列中。
- 訊息在佇列中等待:訊息在被消費者檢索之前在佇列中等待。
- 消費者檢索訊息:消費者從佇列中檢索訊息,並計算該訊息在佇列中的停留時間。
- 發出佇列延遲指標:在開始處理訊息之前,消費者發出佇列延遲指標,以反映該訊息在佇列中的等待時間。
- 處理訊息:最後,消費者處理該訊息。
透過這些步驟,可以有效地監控和管理佇列系統,確保其運作效率和可靠性。