監控即服務:微服務架構的模塊化系統
除了單體應用的代碼,我們的項目還由幾十個微服務組成。這些微服務都需要加以監控,而這些事情全部讓 DevOps 工程師來做是不太可能的。所以我們開發了一個監控系統,為開發者提供服務。他們可以自由的配置監控系統,使用它們構建多維度的報表,設置閾值觸發報警。DevOps 工程師只需要提供基礎設施的信息和文檔。
這篇博文是我在 RIT++ 的演講稿。我們收到很多希望獲取文字版本的 RIT++ 演講的材料。如果你參加了會議或者看過錄屏,你會發現本文和視頻內容是一致的,如果沒有參加或者看過,那么請參考本文,我會告訴您我們是如何演進到現在的方案,如何實現以及未來的計劃。
過去:布局和計劃
我們是如何演進到現在的監控系統的?為了回答這個問題,我們需要回到2015,當時是這樣的:
我們有24個節點的用來負責監控,其中有大量的定時任務、腳本、后臺進程用于監控和發消息、執行任務等等。我們意識到如果我們沿著這個方向走得越遠,我們的系統會變得越難以維護,繼續開發這個系統變得沒有意義,太容易失控了。
我們決定在現有的系統中挑選一些能夠重用的模塊繼續開發和維護,另外的都拋棄。這樣我們選出了19個應用繼續開發。這些僅僅包含了Graphites、數據聚合器、Grafana 儀表盤。那么我們的新系統長什么樣?如下圖所示:
我們有一個 metrics 倉庫 — 高速 SSD 磁盤的圖形化展示和指標聚合。同時,Grafana 負責儀表盤顯示,Moira負責報警。我們也需要開發一個系統來捕獲所有的異常信息。
標準: Monitoring 2.0
這是我們2015年的狀態。但我們不僅僅需要開發基礎架構和服務本身,我們還需要寫文檔。我們開發了一個協作標準,叫做 Monitoring 2.0。 系統需求如下:
- 24/7 高可用,
- 指標存儲間隔 = 10秒,
- 結構化存儲指標和報表,
- SLA > 99.99%,
- 通過 UDP 收集所有事件數據。
我們需要 UDP,因為我們有海量的流量和很多指標產生的事件。如果他們都實時存儲到 Graphite,那么倉庫會被壓垮。我們還為所有指標選定了第一層前綴。
每個前綴都有一些屬性,我們有服務器、網絡、容器、資源、應用等等的監控數據。我們通過記錄第一段前綴,去掉其他部分的方式來提供清晰的、嚴格的、基于類型的過濾。這就是我們看到的 2015 年的狀態。而今天系統是什么樣的?
今天: 監控組件之間的交互
第一,我們監控應用,包括我們的 PHP 代碼、應用、微服務等等, 總而言之,即所有開發者所寫的代碼。所有應用通過 UDP 發送數據到 Brubeck 聚合器 (statsd, C 語言實現). 在綜合測試中它性能最好。Brubecks 通過 TCP 發送聚合數據到 Graphite。
它有一類獨特的指標叫 — timers。它們非常方便。例如,每個用戶連接到服務,你可以發送服務的響應時間到 Brubeck。甚至發送1百萬個響應時間的時候,Brubeck 聚合器也只生成10條數據。你可以知道訪問人數的最大,最小值,平均響應時間。然后數據被轉發到 Graphite,這樣大家都能夠看到。
我們也聚合硬件和軟件的監控指標,系統指標和傳統的監控系統 Munin (我們一直用到2015年)的指標。我們使用 CollectD 收集所有的數據(它內嵌了很多插件,可以查詢出任何主機安裝的資源,你只需要指定數據應該存到哪里) 然后發送數據到 Graphite。它也支持 python 插件和 Shell 腳本,所有你可以開發自定義的方案: CollectD 會從本地或者遠程收集數據 (假設已有 Curl) 發送數據到 Graphite。然后,所有收集的數據會發送到 Carbon-c-relay。這是 Graphite 的 Carbon Relay 方案,用 C 語言修改。它作為一個路由收集所有聚合器發送過來的數據以及路由到這些節點。在路由的時候,它會檢查所有監控數據。第一,他們必須匹配前綴,第二,他們必須符合 Graphite 的規范。否則就丟棄掉。
隨后 Carbon-c-relay 發送數據到 Graphite 集群。作為主要的監控數據倉庫,我們用 Go 修改了 Carbon-cache。因為它的多線程能力,Go-carbon 比 Carbon-cache 要強大很多。它獲取數據,使用 whisper package 寫入磁盤(python 實現的標準包)。從我們的數據倉庫讀取數據,我們使用 Graphite API。它會比標準的 Graphite WEB 要效率高很多。數據接下來會如何處理?
數據會被發送到 Grafana。作為主要的數據源,我們使用 Graphite 集群,用 Grafana 作為統一的門戶來顯示監控數據,構建儀表盤。對于每個服務,開發者構建自己獨有的報表。然后二維圖形會顯示來自他們應用的監控數據。除了 Grafana,我們還用 SLAM。這是一個用來基于 Graphite 的數據分析 SLA 的 python 進程。正如我所說,我們有幾十個微服務,每個都有定制化的需求。我們使用 SLAM查看文檔,對比 Graphite 的數據,并且評估服務的可用性是不是達到了指標。
報警是下一步。它是基于 Moira 構建的強大系統。它內置了 Graphite,由 SKB Kontur 團隊研發,使用 Python 和 Go 語言進行開發, 并且它是 100% 開源的。Moira 獲取和 Graphites 相同結構的數據。如果出于某種原因倉庫宕機,報警功能仍然能夠工作。
我們將 Moira 部署在 Kubernetes,用 Redis 集群作為主要的數據庫。因此,我們的系統是具備容錯能力的。它依據一些列觸發器來對比監控數據:如果監控數據項沒有被匹配,則丟棄這些數據,所以它具備每分鐘處理 GB 級別的數據。
我們也做了和 LDAP 的對接,得益于此,公司內部所有的員工都能夠為已有的觸發器設立報警。因為 Moira 已經自帶 Graphite,它支持所有 Moira 的功能。所以,你可以選擇一行代碼拷貝到 Grafana,看看數據展示的如何,如果結果不錯,你可以將這行代碼拷貝到 Moira。設計閾值你就可以有一個報警了。你不需要特殊的技能就能做得到。Moira 可以通過 SMS, email, Jira, Slack, 等等發送消息。它也支持執行用戶的腳本。當它被觸發,且被腳本或二進制包訂閱了,它會執行這個二進制文件,并且發送 JSON 到二進制的 stdin 里。你的程序需要解析這些數據,這取決于你想要怎么處理這些數據,例如發送數據到 Telegram,在 Jira 里自動創建任務等等。
對于報警功能,我們使用自己專有的方案 — Imagotag。我們支持了商場里的電子價簽的需求。我們用它顯示 Moira 的觸發器。它會顯示它們的時間和狀態。一些開發者取消了 Slack 消息和郵件的訂閱,而以此儀表盤取而代之了。
因為我們的業務是靠產品功能驅動的,我們也用這套系統監控 Kubernetes,我們使用 Heapster 引入了這套系統,部署到集群環境里收集數據,發送到 Graphite, 從而實現kubernetes 的監控。結果如下圖所示:
監控組件
下面是我們使用到的所有組件,他們都是開源的。
Graphite:
- go-carbon: github.com/lomik/go-carbon
- whisper: github.com/graphite-project/whisper
- graphite-api: github.com/brutasse/graphite-api
Carbon-c-relay:
github.com/grobian/carbon-c-relay
Brubeck:
github.com/github/brubeck
Collectd:
collectd.org
Moira:
github.com/moira-alert
Grafana:
grafana.com
Heapster:
github.com/kubernetes/heapster
統計數據
這里有一些我們系統的性能數據:
Aggregator (brubeck)
數據條數: ~ 300,000/秒
發送數據到 Graphite 的時間間隔: 30 秒
物理資源使用率: ~ 6% CPU (這里指的是包含全服務集合的服務器); ~ 1 Gb 內存; ~ 3 Mbps 內網帶寬
Graphite (go-carbon)
數據條數: ~ 1,600,000/分鐘
數據刷新時間間隔: 30 秒
數據持久化時長: 30秒 35天, 5分鐘 90天, 10分鐘 365天 (可以了解服務在一段持續時間內表現的如何)
物理資源使用率: ~ 10% CPU; ~ 20 Gb 內存; ~ 30 Mbps 內網帶寬
靈活性
我們十分受益于靈活的監控服務。為什么它如此靈活?第一,它的組件是可以變化的,包括它的組件本身和版本。第二,它具備很好的可維護性。因為整個項目是基于開源方案搭建的,你自己可以修改代碼,變更,實現需要的功能。我們使用的是非常常見的軟件棧,以Go和 Python為主,所以很容易實現新功能。
這有一個實際的例子。在Graphite中一項指標是一個文件,都有一個名字。文件名即為指標名。另外它還有一個路徑,在 Linux 里,文件名被限制在 255 個字符內。有些來自數據庫團隊的內部用戶,他們說:“我們要監控我們的 SQL查詢,這些查詢并不止 255 個字符,而是有 8 MB 那么大。我們需要讓它顯示在 Grafana里,查看查詢的參數,或者更進一步,查詢所有 SQL語句的熱度。如果能實時顯示這些信息將會更好,理論上,它們也應該集成報警功能。”
這有一個來自postgrespro.ru SQL查詢的例子:
我們搭建了一個 Redis 服務,然后使用我們的 Collectd-plugins 連接到Postgres,并獲取數據,發送數據到 Graphite。但我們使用哈希碼替換了數據名。同樣的哈希碼會被發送到 Redis 作為數據的 Key,將整個 SQL 查詢作為值。剩下的事情交給 Grafana 去連接 Redis,并獲取數據。我們開放了 Graphite API, 因為它是所有監控模塊和 Graphite 之間的主要接口。當進入到 Grafana的一個新方法 aliasByHash (),我們可以獲取數據的名字,將名字作為 Redis查詢的 Key,返回值即是我們的 “SQL 查詢”。因此,本來理論上不能顯示的 SQL 查詢,我們也可以顯示,并且能夠顯示其他數據,包括調用次數,行數,總時間等等。
總結
可用性。對于任何應用,任何代碼,我們的監控服務是24/7高可用的。如果你有權限訪問數據倉庫,你可以自行寫入數據,不用關心語言和方案,你只需要知道如何開啟 Socket 通信,上傳數據,然后關閉 Socket。
可靠性。所有組件都具備容錯性,在我們的現有的壓力下表現的不錯。
低門檻。如果想使用這個系統,你不需要了解 Grafana 的語言以及如何查詢。你只需開發你的應用,建立 Socket連接到 Graphite 并發送數據,然后關閉 Socket,打開 Grafana,新建儀表盤,然后就可以通過Moira的消息通知監控你的應用指標了。
自助式。所有這些都可以被自助式的使用,而不需要 DevOps工程師的協助。這是一個顯而易見的好處,因為你可以立刻開始監控你的項目,而不需要尋求其他人的幫助,既可以直接使用,也可以自定義開發。
我們追求的是什么?
下面列出的不僅僅是大概的想法,而是實際的目標,以及目前實現了的內容。
- 異常捕捉。我們希望建立一個連接到 Graphite數據倉庫的服務,使用不同的算法檢查監控數據。我們已有算法來顯示我們想要查看的東西,我們有數據,知道如何處理。
- 元數據。我們有很多服務,它們隨時會更新,支持,使用它們的人也會變好。人工維護文檔并不可行,因此,我們將很多元數據注入我們的微服務。元數據會記錄誰開發了這個服務,支持什么語言,SLA 的要求,通知回執以及地址。一旦服務被部署,所有數據實體都會被獨立地創建。因此,你會得到兩個鏈接,一個是觸發器,另一個是 Grafana 的儀表盤。
- 自助式的監控系統。我們認為所有開發者都應該使用這個系統。在這里,你可以隨時知道你應用的流量壓力在哪,發生了什么,問題和瓶頸在哪。如果服務中的某些部分掛掉了,通知你的不是來自客戶服務提供商的電話,而是來自你的報警系統,并且可以立刻打開日志查看發生了什么。
- 高性能。我們的項目在持續的增加,目前已經產生將近每分鐘 2,000,000 條監控數據,一年前,這個數字是500,000。同時,我們仍在增加,過一陣 Graphite (whisper) 將會引爆子系統的磁盤。正如我所說,由于組件的易變性,我們的監控系統是非常通用的。某些人特別為 Graphite選擇擴容機器,但我們選擇了另一條路,使用 ClickHouse 作為數據倉庫來存儲監控數據。這個轉變即將完成,關于這部分我會很快介紹更多細節,包括我們做了什么,如何做的 —遇到什么挑戰,如何解決,如何做遷移;我會介紹基礎組件和他們如何配置。
來自:http://www.infoq.com/cn/articles/monitoring-as-a-service