隨着 微服務 的流行,相比較之前一個大型應用程序搞定全部需求,咱們如今更傾向於把大型應用程序切分紅多個微服務,服務之間經過 RPC 調用。微服務架構的好處很是多,例如穩定的服務變化較少,不會被非穩定服務所影響;不一樣的服務更方便交給不一樣的人管理;發佈、擴容等操做也更加有針對性。不過這也不是沒有代價的,額外的成本最主要的可能就是運維成本。html
咱們維護的一個產品,由 7 個微服務構成,它們各司其職,承擔上行、下行、同步等各種職責,我很是喜歡這種架構,但也面臨一個小小的煩惱。每次咱們發佈其中一個或者多個服務,就須要去驗證服務的健康度,極限狀況下,7 個服務 x (國內環境 + 國外環境)x (預發佈環境 + 生產環境),總共須要驗證 28 次!我但願有簡單、標準、自動的方式去驗證這些服務是否健康。固然,驗證健康也不是跑一個完整的迴歸測試,那是在測試環境就須要完成的事情,健康檢查基本只是關注環境是否 OK,最核心的一兩個用例是否 OK。因爲部署到預發佈或者線上的代碼,和線下測試的代碼是一致的,所以就不須要重複驗證各類功能了,關注點應該在環境上,這一點線上和線下是有明顯區別的。至於環境區別,一般就是磁盤、數據庫、其餘分佈式服務等等。java
此外,我還但願全部服務的健康檢查接口是徹底一致的,沒有人但願檢查服務 A 的時候用 url /ok,檢查服務 B 的時候用 url /good。spring
我曾嘗試定義一個健康檢查協議,讓全部服務都暴露一個HTTP接口http://172.20.10.2/health.json ,返回的內容就包含這個這個服務的基本狀態。數據庫
這幾天看 Spring Boot ,發現它已經很好地集成了我想要的功能,並且看起來更簡單,所以我就直接扔掉了本身定義的協議,改而使用 Spring Boot 的方式,Spring Boot 有一個稱之爲 endpoint 的概念,每一個 endpoint 是一個很是簡單的 HTTP 接口,用戶能夠經過 endpoint 監控 Spring Boot 應用,甚至與之交互。這其中,最簡單的 endpoint 就是 health,只要加入必要的 Spring Boot 依賴,用戶就能經過 health 查看 Spring Boot 應用的基本狀態。json
$ curl http://localhost:8080/health { "status":"UP" }
這裏咱們看到服務的狀態是 UP,不過也許這個檢查太簡單了,例如個人服務依賴其餘外部服務,其中一個 Tair,一個是 TFS,這兩個都是強依賴,若是它們有問題,個人服務就應該是 DOWN 的狀態,在 Spring Boot 中,能夠這麼擴展:緩存
@Component
public class MyHealth implements HealthIndicator { @Override public Health health() { return new Health.Builder() .withDetail("tair", "timeout") // some logic check tair .withDetail("tfs", "ok") // some logic check tfs .status("500") .down() .build(); } }
只要加入一個 bean 實現 HealthIndicator 就能實現更加全面的檢查,如今訪問 health endpoint 是這樣的:ruby
$ curl http://localhost:8080/health { "status": "DOWN", "tair": "timeout", "tfs": "ok" }
只要在每一個服務稍微實現一些基本的環境檢查,那我就能夠用幾行腳本快速地完成 7 個服務 x (國內環境 + 國外環境)x (預發佈環境 + 生產環境)的健康檢查,若是有哪一個服務出問題了,定位環境問題也是很是方便的。網絡
這種監控是實時的,這一點很是重要。在實際工做中咱們其實有很是完善的系統監控平臺,平臺能提供 CPU、內存、磁盤、網絡IO、JVM 等等各類各樣很是全面的信息,這種平臺的優點有歷史趨勢記錄,有彙總,有比較,劣勢就是不夠實時,一般只能看到 5 分鐘前的數據。所以,在發佈服務,擴容的時候,等待這樣的系統監控平臺反饋就不夠了。架構
除了 health endpoint 以外,Spring Boot 還提供了 其它10多個 endpoint ,它們都是針對運維設計的,例如能夠用 shutdown endpoint 來關閉服務、用 beans endpoint 來查看全部的 Spring Bean,下面我想詳細講一下 metrics 這個 endpoint。運維
默認訪問 metrics 咱們能獲得不少信息,包括 JVM 的線程數、內存、GC 數據等等……,這些都是系統級別的數據,但其實咱們能夠經過 metrics 收集實時的業務數據,例如每分鐘用戶登錄數量、每分鐘文件同步數量、實時的緩存命中率……等等。
實現是這樣的:
@Component
public class MyMetric { private final CounterService counterService; private final GaugeService gaugeService; @Autowired public MyMetric(CounterService counterService, GaugeService gaugeService) { this.counterService = counterService; this.gaugeService = gaugeService; } public void exampleCounterMethod() { this.counterService.increment("login.count"); // reset each minute } public void exampleGaugeMethod() { this.gaugeService.submit("cache.hit", 80.0); } }
Spring Boot 內置了兩個 Service,CounterService 能夠用來作簡單的累加累減,GaugeService 能夠用來存放簡單的 double 值,數據都存放在內存中。
如今訪問 metrics endpoint 的效果是這樣的:
$ curl http://localhost:8080/metrics { "counter.login.count": 42, "counter.status.200.beans": 1, "counter.status.200.metrics": 9, "counter.status.200.root": 4, "gauge.cache.hit": 80.0, "gauge.response.beans": 55, "gauge.response.health": 12, "gauge.response.metrics": 4, ... }
Spring Boot 的 metrics endpoint 帶了不少的信息,這裏咱們只關注自定義的數據。
若是全部服務的核心業務數據都經過 metrics 暴露,咱們接下來要作的無非就是經過一些數據可視化的 JavaScript 組件訪問這些數據,作成一個 Dashboard,那咱們就能經過這樣一個 Dashboard 查看系統的實時狀態。
Spring Boot 的 Endpoints 帶着強烈的 DevOps 色彩, 「you build it, you run it」 ,開發不只要關心如何實現功能,還須要關心服務在線上運行的狀態,若是缺少實時監控,維護線上服務必然是一場噩夢。若是基於 Spring Boot 開發服務,那隻須要稍做擴展,實時監控就足夠用了,就算不使用 Spring Boot,相似的思路本身實現也並不複雜。
參考連接 http://docs.spring.io/spring-boot/docs/1.1.x/reference/htmlsingle/#production-ready-endpoints