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```等等的. ![linuxperf](https://ithelp.ithome.com.tw/upload/images/20211004/201049301Byy7jttuK.png) 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形式 ![fluent-bit agent](https://fluentbit.io/assets/img/blog/2020-12-03-common/blog-forwarder-aggregator.png) ![promtail](https://miro.medium.com/max/1838/1*gTD64wp0vn2AZ5SazChi_w.png) # Trace 單體架構下, 基本上調用關係僅在同一個process的記憶體內做調用, 通常都是透過stack trace做調用鍊路的trace. 將這些資訊給匯出後, 再通過類似[Flame Graph](https://github.com/search?q=Flame+Graph)的工具, 進行可觀測性的分析. 也可透過圖, 來得知調用關係. ![FlameGraph](https://camo.githubusercontent.com/eecfbf00e6cc5baf6ae2b66283573d765f8fe29f1d3df10f4ce3423d942c0af3/687474703a2f2f7777772e6272656e64616e67726567672e636f6d2f466c616d654772617068732f6370752d626173682d666c616d6567726170682e737667) 但是在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做資料存儲結構, 通常會以讀取的順序依序做排序, ![](https://sqlhints.com/wp-content/uploads/2018/05/Structure-of-Clustered-Index.jpg) 因為B+Tree預設是為了對磁碟做存取操作的, 它所有資料都存在Leaf葉子節點中. 每次查詢時, 需要從Root節點查詢到Leaf節點, 在從Leaf節點對應的位子進行讀取, 其存放的順序剛好跟讀取所需要的順序是一致的. 然後Leaf節點的資料是放在磁碟內的Page, 讀取一整個page出來後放到Memory中. 但沒人說物理Page剛好位子都是相鄰的. 這樣的結構好處是插入刪除的時間複雜度是O(log2N), 查詢要看情況, 可以非常好也能很不好. 這種隨機讀寫的場景蠻常見的, 會導致時間大多花在磁盤尋址上. 大家應該組機很常去跑CrystalDisskMark這工具, 來看磁碟的隨機讀寫與順序讀寫的速度快慢. 可以發現順序讀寫的效率跟俗機讀寫的效率不是一個量級的 哪怕你是SSD ![](https://p6-tt.byteimg.com/origin/pgc-image/b465e4d2c4424c2aa9bd5ffe5c18671d?from=pc) 但Time Series Data的另一個特徵是```海量的資料量```, 這些資料量在寫入是挑戰, 如果幾十萬筆, Log2N才多少, 但若是1億筆就可怕了 所以有下面結構的資料庫 ## LSM-Tree 所以有令一種資料庫很適合存放Time Series Data, 它叫LSM-Tree (Log Structured Merge Tree) 核心思想是 將離散的```隨機```寫入請求都轉成批量的```順序```寫入請求 透過在記憶體整理後, 只要確保在記憶體時, 資料是按照順序排列的, 當記憶體的資料累積到一個量時, 會做一些歸併整理, 在直接寫到硬碟中. 這樣子就不用一直的寫入了, 畢竟寫到記憶體是非常高效率的. 為了避免資料在資料庫當機後遺失, 也是會採取WAL(Write Ahead Log)的機制. 雖然它沒解決掉查找還是隨機位置的問題, 但記得 監控在意的是過去短時間內的聚合資料而已. 近期的資料會在記憶體中, 查詢依然非常高效率. ![](https://img-blog.csdnimg.cn/20190521200208933.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQwMzA=,size_16,color_FFFFFF,t_70) 這類的介紹, 明年看有否機會深入.