Observability
====
上篇回顧
[分布式可觀測性 Logging 淺談](https://ithelp.ithome.com.tw/articles/10277525/)
[分布式可觀測性 Structured Log](https://ithelp.ithome.com.tw/articles/10277678)
繼續淺談Observability的另兩個基石
- Metrics
- Tracing
# Metrics
在單體式架構上,主要的監控對象是OS與機器這物理節點, 所以經常直接使用OS自帶的工具.
以Linux來說```top```來看每個Process的CPU使用率、記憶體用量, ```mpstat```, ```vmstat```, ```iostat```等等的.

Windows則是Task manager.
透過這些OS提供的命令與工具來監控.
但在現在分布式架構下, 數十數百台機器或是在VM上的OS, 監控的可觀測性成了挑戰.
於是陸續誕生了Cacti、Zabbix、Prometheus等很多監控系統,
它們的特色是metrics數據的收集、數據的存放、數據的查詢展示都分離開來. 彼此透過網路協議與介面來傳遞資料.
現在常見的架構有兩種,
一種是數據的收集以Library形式, 與業務系統整合在程式專案中,
在程式碼埋點的方式, 以Client調用的角度, 把調用資源或服務的耗時、請求量、慢查詢量,
甚至能收集GC的資訊等等的送給另一個獨立出來的數據處理服務去做處理與分析.
以Go來說, Prometheus就有提供這樣的[Library](https://prometheus.io/docs/guides/go-application/)
Go自帶的[pprof](https://golang.org/doc/diagnostics)其實也是一種
另一種則是以Agent(Sidecar)或Exporter形式, 由它來負責數據收集與數據做處理 .
通常它會負責採集特定指標資訊例如, 主機資訊, 或是各Process的CPU用量, 記憶體用量.
Prometheus提供非常多[exporter](https://prometheus.io/docs/instrumenting/exporters/)來採集特定指標
之後要介紹的Fluent-bit或Promtail則是以Agent形式


# Trace
單體架構下, 基本上調用關係僅在同一個process的記憶體內做調用, 通常都是透過stack trace做調用鍊路的trace.
將這些資訊給匯出後, 再通過類似[Flame Graph](https://github.com/search?q=Flame+Graph)的工具, 進行可觀測性的分析. 也可透過圖, 來得知調用關係.

但是在Distributed System下常常, 服務之間相互調用, 其調用的機器與網路甚至不是同一個.
一樣也是要透過調用鍊路收集的工具, 把Distributed System的調用鍊路整成一個跟stack trace很像的結構與資訊. 其中也包含每個調用鍊路的耗時時長.
這就是Distributed Tracing, 能參考去年我的文章[Distributed Tracing & OpenTelemetry介紹](https://ithelp.ithome.com.tw/articles/10248469)
## Time Series Data
前面兩個維度講的資料, 都是以Time Series Data的方式呈現.
Time Series Data反應的是Metric指標在某一個時間點上的狀態.
這種資料與MySQL這類的OLTP資料有所不同.
- 資料不可變
- 只有一直生成新數據, 不會去修改舊數據, 時間過了, 改變過去沒意義
- 按照時間依序生成一系列的數據
- 必備的欄位有Timestamp, 還會加上少說一個主要欄位(服務名稱,設備名稱...)當作索引
- 通常數據量比OLTP的數據龐大非常多
- 這些指標數據, 通常會以1s的間隔做聚合, 換句話說 就是看同一秒內機器的整體效能, 或是服務的效能
- 通常只對近期數據做關注, 一陣子以前的通常非常非常少被存取
- Metric指標或Label標籤要能被Aggregation聚合, 計算平均值、Maximum、Minimum之類的
Time Series Data會有一些獨特的概念
- Metric 指標
- 被監控的對象, 溫度、速率、反應時間...
- 一個Metric可以有多個Tag
- 有幾種[Type, 可參考Prometheus給的](https://prometheus.io/docs/concepts/metric_types/)
- Label/Tag 標籤
- 對指標特徵維度的說明
- Key Value形式呈現
- path=/Order -> 表示這metric是針對api/order的可能counter可能是respone time的取樣, 要看metric是什麼
- 所以若是Log沒以Structured Log格式呈現, 不方便取Key來當這Label的Key
所以 Metric+Label決定了一個計量的單位.
如果以MySQL來存放, 那一個Metric就會是一張表了, Label則是裡面的欄位, 可能還會有其他欄位像是Timestamp.
再來MySQL這類的資料庫, 通常以B+Tree做資料存儲結構, 通常會以讀取的順序依序做排序,

因為B+Tree預設是為了對磁碟做存取操作的, 它所有資料都存在Leaf葉子節點中.
每次查詢時, 需要從Root節點查詢到Leaf節點, 在從Leaf節點對應的位子進行讀取, 其存放的順序剛好跟讀取所需要的順序是一致的. 然後Leaf節點的資料是放在磁碟內的Page, 讀取一整個page出來後放到Memory中.
但沒人說物理Page剛好位子都是相鄰的.
這樣的結構好處是插入刪除的時間複雜度是O(log2N), 查詢要看情況, 可以非常好也能很不好.
這種隨機讀寫的場景蠻常見的, 會導致時間大多花在磁盤尋址上.
大家應該組機很常去跑CrystalDisskMark這工具, 來看磁碟的隨機讀寫與順序讀寫的速度快慢.
可以發現順序讀寫的效率跟俗機讀寫的效率不是一個量級的
哪怕你是SSD

但Time Series Data的另一個特徵是```海量的資料量```, 這些資料量在寫入是挑戰,
如果幾十萬筆, Log2N才多少, 但若是1億筆就可怕了
所以有下面結構的資料庫
## LSM-Tree
所以有令一種資料庫很適合存放Time Series Data, 它叫LSM-Tree (Log Structured Merge Tree)
核心思想是 將離散的```隨機```寫入請求都轉成批量的```順序```寫入請求
透過在記憶體整理後, 只要確保在記憶體時, 資料是按照順序排列的,
當記憶體的資料累積到一個量時, 會做一些歸併整理, 在直接寫到硬碟中.
這樣子就不用一直的寫入了, 畢竟寫到記憶體是非常高效率的.
為了避免資料在資料庫當機後遺失, 也是會採取WAL(Write Ahead Log)的機制.
雖然它沒解決掉查找還是隨機位置的問題,
但記得 監控在意的是過去短時間內的聚合資料而已. 近期的資料會在記憶體中, 查詢依然非常高效率.

這類的介紹, 明年看有否機會深入.