JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

可觀測性 vs 監控,以及指標/日誌/追蹤

你早已會在自己機器上除錯一支程式。正式環境(production)不一樣:臭蟲時有時無、機器在凌晨三點起火,而你無法掛上除錯器。這篇導引重新框定整個問題——讓一個正在運行的系統「自己把自己說清楚」是什麼意思,以及你用來建起這份解釋的三種訊號。

從除錯一台機器,到除錯一個你無法暫停的系統

你在除錯那一級學到的一切,都預設了一個你在正式環境不會有的奢侈:你能把程式停下來。你設一個中斷點、讀一條回溯(backtrace)、單步執行、用某個 sanitizer重跑。那在你的桌面行得通,因為行程由你掌控。一個運行中的服務是相反的世界。它此刻正在服務真實使用者、那個故障十分鐘前才發生而現在已消失、它可能散佈在四十台機器上,而把它凍結起來戳一戳,本身就是一次停機。問題從「讓我單步走過它」變成「在我趕到之前,系統已經把關於自己的什麼記了下來?」

可觀測性(observability)是一個系統的一種性質:它讓你純粹從系統向外發出的訊號,就能回答關於它內部狀態的問題——不必上線新程式碼、不必重現臭蟲、不必掛上任何東西。這個詞老實地借自控制理論:若一個系統的內部狀態能從它的輸出重建出來,它就是可觀測的。套用到軟體上,可觀測性問的是:當一件沒人預料到的怪事發生時,你手上記下來的輸出是否足以推敲出為什麼,還是你得重新部署一個多加一行印出敘述的建置,再等它又發生一次?一個事後能盤問的系統是可觀測的;一個只能重跑的系統不是。

為什麼監控不是同一個詞

人們把「監控」與「可觀測性」當同義詞混用,而這種混為一談藏起了一個值得清楚把握的真正區別。監控(monitoring)盯著一組固定、預先定義好、你早已認定重要的東西——CPU 超過 90%、錯誤率超過 1%、磁碟快滿了——並在某一項越過門檻時呼叫你。它回答的是你事先寫下的問題。那確實有價值:監控是你得知「系統問題」的途徑。但它在結構上對你沒預見到的故障是盲的,因為沒人想到要問的問題,是不會有儀表板的。

可觀測性是更寬廣的那個性質,它讓你事後問出新的問題——你寫系統時並未預料的問題。監控告訴你結帳延遲飆高了;可觀測性接著讓你發現:那只發生在某一個區域的請求、只在新的資料庫複本上、只對超過某個大小的購物車。誠實的說法不是「可觀測性取代監控」。監控是那個常駐的警報;可觀測性是那份豐富的紀錄,讓你在警報響起後得以調查。兩者你都要,而它們共用同一份原料——下一節為它命名。

三根支柱:指標、日誌、追蹤

慣用的詞彙把這些原始訊號叫做三根支柱——指標、日誌與追蹤——而理解它們最乾淨的方式,是看每一種各自捨棄了什麼。指標(metric)是一個隨時間量測的數字:每秒請求數、第 99 百分位延遲、剩餘位元組數。它又小又便宜,因為它是聚合過的——你保留的是計數,而非個別事件——所以你能永久儲存它、畫出一整年的圖,但你已扔掉了任何單一請求的細節。指標讓你便宜地看見趨勢與門檻,這正是監控建在它們之上的原因。

日誌(log)是一筆離散事件的紀錄,典型上是一行文字:「2026-06-24T03:14:07 ERROR payment failed for order 4192, code 0x2」。日誌保留了指標扔掉的細節,但代價翻轉了——日誌量大,而且寫成自由文字時很難查詢。成熟的形式是結構化日誌(structured logging):你發出的不是一個句子,而是一筆有命名欄位的紀錄(event、order_id=4192、code=0x2、latency_ms=812),好讓機器能過濾與聚合它們。這篇導引的後續篇章會重重倚靠這個想法;眼下的重點是:日誌回答的是這一個事件裡究竟發生了什麼,代價是量。

追蹤(trace)跟著單一一個請求,看它如何貫穿整個系統流動,把它碰過的每一個階段縫成一個有因果的故事。在一個由許多片段組成的服務裡,一次使用者點擊可能打到 web 層、兩個內部服務、一個快取與一個資料庫;一條分散式追蹤把這些每一段都記成一個 span,帶有起點、持續時間與父節點,並把它們全綁在同一個 trace id 之下。這就是回答時間花到哪去了哪一跳失敗了的那根支柱——這個問題指標(太聚合)與單一一行日誌(太局部)都無法獨力回答。這一級最後一篇導引就專講它。

one request -> one trace, several spans:

  [trace 0x7af...]
   |-- span web-frontend        12 ms
   |    |-- span auth-service    3 ms
   |    |-- span cart-service   45 ms   <-- the time went here
   |         |-- span db-query  41 ms   <-- and really, here

metric:  cart_p99_latency_ms = 812   (a number, no story)
log:     ERROR db-query slow order=4192 ms=41  (one event)
trace:   the tree above            (the whole causal path)
同一個慢請求的三種看法。指標告訴你它慢,一行日誌捕捉到一個症狀,而追蹤秀出因果路徑,讓你能指著實際出問題的那一跳。每根支柱在細節與成本之間有不同的取捨;你伸手去拿與當下問題相稱的那一根。

關聯才是整場戲

以下這一點,把真正的可觀測性和三座彼此不相連的資料湖區分開來:唯有當你能在支柱之間樞轉(pivot)時,它們才強大。一個指標呼叫你說 p99 延遲跳高了。從那個尖峰,你想直接跳到那段時間裡那些慢請求的追蹤;從一條慢追蹤裡失敗的那個 span,你想直接跳到那個 span 發出的日誌。若你的指標、日誌與追蹤沒有共通的鍵——沒有請求 id、沒有 trace id、沒有一致的服務名稱——每一個就都是各自的死胡同,而你又回到了加一行印出敘述重新部署的老路。讓從症狀跳到根因成為可能的,是關聯,而不是蒐集。

這就是為什麼這個領域收斂到了共通的慣例:一個沿每一跳傳播的 trace id、有共識欄位名的結構化欄位、一個時鐘。為此而生的開放標準是 OpenTelemetry——一種廠商中立的方式,用一致的中介資料來產生、標記並傳送全部三根支柱,好讓它們能夠被接合。你不需要它也能理解這個想法,但正是它讓一套現代堆疊能秀給你一張延遲圖、讓你點下那個尖峰、看見出問題的那條追蹤、再打開它的日誌,全程帶著同一個 trace id。那一個貫穿一切的 id,就是把三堆資料變成一份解釋的脊樑。

誠實的代價:觀察者效應,以及這一級往哪裡去

可觀測性不是免費的,假裝它免費會養出糟糕的工程師。你發出的每一個訊號,產生它要花 CPU、傳送它要花網路、儲存它要花磁碟——更糟的是,量測這個動作本身可能擾動你所量測的東西。這就是觀察者效應(observer effect):熱路徑上的一行日誌多了一次系統呼叫與一把鎖;一個追蹤 span 要配置記憶體並做序列化;打開詳盡的儀器化(instrumentation)本身就可能讓一個服務慢到足以改變它的行為,於是你追的那個臭蟲位移或消失了。你在除錯那一級已見過它的表親——海森堡蟲(heisenbug)。紀律在於讓常見情況保持便宜:聚合成指標、取樣(sample)追蹤而非每一條都記、並讓最熱的路徑保持安靜。

貫穿這一級其餘部分的張力恰恰就是這個:你要怎麼深入看見一個運行中的正式系統的內部,卻嚴重擾動它、甚至根本不停下它?答案就是接下來的各章。eBPF讓核心在選定的事件上以極低的額外負擔執行小小的安全程式。ftrace、kprobes 與 uprobes 掛進核心與你的二進位檔,活生生地觀察它們。硬體效能計數器讀取 CPU 本來就在數的週期與快取統計,幾乎免費。連續剖析器(continuous profiler)橫跨整個機群取樣呼叫堆疊,找出 CPU 與記憶體實際花到哪裡去。每一個都是在嚴格的擾動預算下、從一個運行中系統榨出訊號的不同方式——而它們全都服務於你如今清楚握住的那個目標:把一個無法暫停的系統,變成一個會自己把自己說清楚的系統。