# 8

將系統拆分成更小的、細粒度的微服務會帶來許多好處，但也增加了生產系統監控的複雜性。我們提供給客戶的功能，是由許多小的服務組合起來的，其中一些服務需要呼叫更多的服務來完成功能。這樣很好，但在監控的世界，這也會變得很複雜。

我們現在有許多服務需要監控，有多個Log 需要篩選，多個地方有可能因為網路延遲而出現問題。而我們又該如何應對呢?

**監控小的服務，然後聚合看整體。**

當我們查看一個複雜系統的指標、Log 時，很難知道什麼是好的、正常、異常。要想知道什麼時候該緊張、什麼時候該放鬆，秘訣是： **收集系統指標足夠長的時間，直到有清晰的模式浮現**

## 要先埋事件、關聯ID

## 單一服務，單一服務器

一台主機 運行 一個服務，現在要對它進行監控，這樣出現問題時就能及時發現，以便對它進行修復。

### 監控主機本身

CPU、RAM 等所有主機的數據都有用。 我們想知道系統健康時，會呈現什麼樣子。這樣我們就可以在超出邊界值時發出警告。 (Nagios 自行監控 , New Relic 託管服務 幫我們監控主機)

### 查看服務器本身的日誌。

如果用戶報告了一個錯誤，這些日誌應該可以告訴我們，在何時何地發生這個錯誤。 可以登入到主機上，使用指令查看Log，甚至使用 logrotate 移除舊的日誌，避免佔用太多硬碟空間。

### 監控應用程序本身

最低限度是要監控程序的響應時間。 可以透過查看 web server、服務本身 的Log 做到這一點。

## 單一服務，多個服務器

我們現在 一個服務 有 多台主機，利用 **負載平衡** 去分發 request 到當前比較不忙的主機。

我們依然要監控之前的內容，但因為 定位問題，需要改變一下做法。

**當CPU使用率過高，如果發生在所有主機，可能是服務的問題。** **如果只發生在一台主機上面，可能是主機本身的問題，也許是中毒了?**

## 監控各主機

先把各主機的數據聚合起來，又想深入分析各主機。 Nagios 允許以這樣的方式組織主機，**類似的方式也可以滿足我們對應用程序的監控。**

## 查看Log

1. 登入到每一台去查看
2. 利用像 ssh-multiplexers 的工具

## 響應時間

對於這樣的監控，我們可以在負載平衡器中追蹤，也很容易蒐集聚合後的數據。不過 負載平衡器 本身也需要監控，如果它發生異常，也會產生問題。 對於服務的監控，我們要先知道正常的服務是什麼樣子，這樣我們配置負載平衡器時，就可以從中移除異常的節點。

## 多個服務，多個服務器

事情變得更歡樂了 \~ 這些服務運行在多個物理或虛擬主機上。 要如何在多個主機，成千上萬的Log 中，定位錯誤的原因? 到底是一個主機的異常，還是一個系統性的問題? 如何在多個主機之間，追蹤彼此之間是怎麼呼叫的 (調用鍊)，找出引發錯誤的原因?

ANS：**從Log 到應用程序指標，盡可能集中、收集更多的數據到手中**

## Log \~\~ Log \~\~\~ 更多的日誌

運行的主機數量太多啦 \~\~\~ 現在繼續使用 SSH multiplexing 檢索日誌，已經無法緩解問題惹。 我們會選擇使用專門獲取Log 的子系統來代替它，讓日誌可以集中在一起方便使用。 logstash ([http://logstash.net](http://logstash.net)) 可以解析多種 Log，並將它們發給下游系統進行調查、處理。

Kibana ([http://www.elastic.co/products/kibana](http://www.elastic.co/products/kibana)) 是一個基於 ElasticSearch 查看日誌的系統。 它可以使用查詢語法來搜索日誌，例如指定 時間、日期 範圍，或使用正則表達式去匹配字串。 它甚至可以把日誌生成圖表，只需要看一眼就知道有多少錯誤發生。

## 多個服務的指標跟蹤

我們需要尋找更好的方式來收集、查看指標。 只有收集夠長的時間，多到足夠能讓我們清晰的了解 什麼是正常、什麼是異常，有了清晰的模式之後，我們就知道什麼時候該鬆，什麼時候該緊。

在更複雜的環境中，我們會頻繁的重建服務的新實例，所以我們希望選擇一個系統 能夠方便的從新的主機 收集指標。 我們希望能夠看到整個系統聚合後的指標 (例如：平均後的CPU負載)，但也會想要給定的一些 服務實例聚合後 的指標，這就代表我們需要將指標的元數據關聯，用來幫助推導出這樣的結構。

**Graphite** 提供一個非常簡單的API，允許你發送數據給它。 然後你可以通過查看這些指標生成的圖表和其他展示方式來了解當前情況。 它處理容量的方式很有趣。通過有效的配置，可以減少舊指標的精度，以確保容量不要太大。 例如：最近十分鐘，每十秒記錄一次CPU的指標。 過去一天，以分鐘為單位對數據進行聚合。 而在過去幾年，以每三十分鐘為單位進行聚合。 (通過這種方式，不需要大量的儲存空間，就可以保存很長一段時間內的信息)

Graphite 也允許你跨樣本聚合，或深入到某個部分，這樣就可以查看整個系統、一組服務、或一個主機的響應時間。

如果由於一些原因，而不能使用 Graphite，至少要確保這些工具具備跟Graphite 類似的功能。而且要確保自己能獲得原始的數據，以便隨時可以生成自己的報告或儀表板。

**了解趨勢的另外一個好處，是可以幫助我們做容量規劃** 我們的系統到極限了嗎? 多久之後需要更多主機? 在供應商提供按需求計算的 IaaS 的新時代，我們可以在幾分鐘內實現擴容和縮容。 利用我們的數據，去使用剛剛好的服務，使用的越智能，我們的系統就越省錢。

## 服務指標

作為Web 服務，最低限度應該暴露像 響應時間、錯誤率 這樣的一些指標。 如果主機前面沒有一個 web server 來幫忙做的話，這就更重要了。 但我們應該做的更多、暴露更多接口去提供更多資訊。

有一句老話，80%的軟體功能從來沒有被使用過。如果我們有方法知道像這樣的資訊，在一些權衡上就可以派上用場。

由於我們永遠無法知道什麼數據是有用的。很多次，直到機會錯過很久後，我才發現當初如果有數據，事情就會比較好理解。 所以可以的話，暴露一切數據，然後依靠指標系統去進行處理。

很多平台都存在一些功能來幫助服務發送數據到一個標準系統中。 Codahale 的 Metrics 功能 ([http://metrics.codahale.com/](http://metrics.codahale.com/)) 就是這樣一個運行在JVM的功能。 它允許你儲存一些指標，例如計數器、計時器、計量表(gauge)； 支持帶時間限制的指標(例如過去五分鐘的訂單)； 還會將數據發送到 Graphite 和其他匯總報告系統。

## 綜合監控

我們可以通過定義正常的CPU，或者可接受的響應時間，去定義 "正常" 的服務。 當系統超出我們的定義，則觸發警告，通知異常發生。

我們想知道的是，系統是否正常工作? 當程式之間交互的越複雜，則越難回答這個問題。

**合成事務** 用來確保系統行為在語意上的正確性的這種技術，通常被稱為 **語意監控**。

### 實現語意監控

如果系統中已經存在指定服務的端到端測試，甚至是整個系統的端到端測試，仔細看看會發現這就是實現語意監控所需要的。 而且我們的系統已經開放了 啟動測試 和 查看結果 所需的鉤子(hook，工具)

**但在測試前，我們要非常小心的準備測試用的數據** 用以滿足測試的要求。 我們的測試需要找到一種方法來搭配不同的實時數據，因為這些數據會隨著時間而改變，或是設置一個不同的數據來源。 例如：在生產環境設置一組假的用戶和一些已知的數據集。

同樣，我們要非常小心的確保不會發生意料之外的副作用。 (曾經有一家公司在生產環境跑測試，直到大量的洗衣機送到總部，才意識到這個錯誤)

## 關聯標識

倘若發生錯誤，我們會想知道呼叫的上下游分別有哪些，是什麼問題導致這個錯誤的發生。

而要知道這些，有一個最簡單的方法 就是關聯標識(ID)。它必須要在被呼叫的最源頭、觸發第一個呼叫時，產生一個 GUID，之後將它傳遞給後續的所有呼叫。

這樣在記Log 的時候，每個服務可以記錄

**日期 時間 哪一個服務 Log級別(INFO、ERROR等) \[GUID] Message**

這樣在之後查Log 的時候，就會比較方便。 黨決定這樣做的時候，就要確保每個服務都會接收、傳遞該標識，強制在系統中執行，使其標準化。

Zipkin ([http://twitter.github.io/zipkin/](http://twitter.github.io/zipkin/)) 可以跨多個系統邊界跟蹤調用。 基於 Google 自己的跟蹤系統 Dapper 的創意，Zipkin 可以提供詳細的服務間調用追蹤。

## 級聯

**級聯故障特別危險**

想像一下，有兩個服務各自都是好的，但是他們之間無法溝通，如果只查看單個服務，我們根本看不出來問題。 使用合成監控(例如：模擬客戶搜尋一首歌)才會將問題暴露出來。而為了確定問題的原因，我們需要報告這一事實是一個服務無法訪問另一個服務。

監控系統之間的呼叫點是非常關鍵的。每個服務的主機都應該追蹤和顯示其後續服務的運行狀態，從資料庫\~其他服務。 並且將這些信息匯總，以得到一個整合的畫面。你會想知道後續服務的回應時間，並檢測是否有錯誤。

你可以使用一個斷路器網路呼叫，用來幫助你更加優雅的處理級聯故障和功能降級 (參考資料:[https://kknews.cc/news/o39alqm.html)。](https://kknews.cc/news/o39alqm.html\)%E3%80%82)

## 標準化

對於單個服務的規範，還是對於整個系統的規範，對於整個系統的標準化是至關重要的。 服務之間的接口，用各種方式去給客戶提供功能，這需要從整體的角度去思考整個系統。

我們應該嘗試用標準格式去記錄Log。 **關鍵是讓做正確的事情變得容易** 所以何不提供一個虛擬機鏡像，鏡像內置 logstash & collectd，還有一個公用的函式庫，讓它和Graphite很好溝通呢?

## 考慮受眾

我們在收集這些數據的時候，背後都會有一個目的。

比如有些數據可以幫維運團隊去判斷該做哪一種處理，比如最近一段時間CPU負載上升，容量規劃。 老闆會想知道最近的收入狀況如何，上次更新版本之後，收入下降25%。

1. 他們現在需要知道什麼
2. 他們之後想要知道什麼
3. 它們如何消費數據(使用資料)

提醒它們現在需要知道的東西，並讓他們可以在之後可以深入分析，也可以很方便的訪問。 花時間了解他們想要使用的數據。 討論 定量信息的圖形化顯示 及其所涉及的所有細微差別 已經超出本書範圍。

## 未來

在很多組織中，指標被孤立在各個不同的系統中。

像訂單數量這樣的應用程序級指標，只放在Omniture等 專有的分析系統上(通常只供業務的重要部分使用)，或者放在資料庫內，再也乏人問津。 通常這些系統 報告都不是實時的。

反而在維運團隊，系統指標：回應時間、錯誤率、CPU負載等，都存儲在維運團隊可以訪問的系統上。 通常這些系統提供實時報告，目的是及時觸發行動。

Riemann ([http://riemann.io](http://riemann.io)) 是一個事件服務器，允許高級的聚合和事件路由，可以做為上述問題的解決方案之一。

Suro ([https://github.com/Netflix/suro](https://github.com/Netflix/suro)) 是 Netflix 的 **數據流水線**，和前者能解決的問題類似。 Suro 明確可以處理兩種數據，用戶行為的相關指標 & 更多的營運數據(APP Log)。 這些資料會分發到不同的系統中，像 Storm 的實時分析，離線批處理的 Hadoop 或日誌分析的 Kibana。

有些組織走向另外一條路：不再為不同類型的指標提供專門的工具鏈，而是提供伸縮性很好的、更為通用的事件路由系統。這些系統可以提供更多的靈活性，還能簡化我們的架構。

## 小結

### 對每個服務而言

* 最低限度要追蹤 request 的回應時間。做好之後，可以開始追蹤錯誤率&應用程序級的指標。
* 最低限度要追蹤所有後續(下游)服務的運行狀態，包括後續呼叫的回應時間，最好能夠追蹤錯誤率。(一些像Hystrix 這樣的庫，可以在這方面提供幫助。)
* 標準化如何收集指標以及存儲指標。
* 如果可能的話，以標準的格式將 Log 記錄到一個標準的位置。如果每個服務各自使用不同的方式，整合起來會非常痛苦。
* 監控底層操作系統，這樣你就可以追蹤是否中毒和進行容量規劃。

### 對系統而言

* 整合 CPU之類的主機層級指標 & 應用程序級指標。
* 確保你選用的指標存儲工具 可以在系統、服務級別做整合，同時也允許你查看單台主機的情況。
* 確保儲存指標的工具的保留時間，你才有足夠的時間去了解、觀察系統的趨勢。
* 使用單個可查詢工具來對 Log 進行整合和儲存。
* 強烈考慮 **標準化關聯標識** 的使用。
* 了解什麼樣的情況需要行動，並根據這些信息構造相應的警報和儀表板。
* 分析 將各種指標進行整合、統一 的可能性，像 Suro、Riemann 這樣的工具會有所幫助。
