CAT(Central Application Tracking)是基於 Java 開發的實時應用監控平臺,包括實時應用監控,業務監控。git
CAT 做爲服務端項目基礎組件,提供了 Java, C/C++, Node.js, Python, Go 等多語言客戶端,已經在美團點評的基礎架構中間件框架(MVC 框架,RPC 框架,數據庫框架,緩存框架等,消息隊列,配置系統等)深度集成,爲美團點評各業務線提供系統豐富的性能指標、健康情況、實時告警等。github
CAT 很大的優點是它是一個實時系統,CAT 大部分系統是分鐘級統計,可是從數據生成到服務端處理結束是秒級別,秒級定義是 48 分鐘 40 秒,基本上看到 48 分鐘 38 秒數據,總體報表的統計粒度是分鐘級;第二個優點,監控數據是全量統計,客戶端預計算;鏈路數據是採樣計算。web
Github: https://github.com/dianping/cat[1]redis
場景一:用戶反饋 App 沒法下單,用戶反饋沒法支付,用戶反饋商品沒法搜索等問題spring
場景一的問題在於當系統出現問題後,第一反饋的老是用戶。咱們須要作的是什麼,是在出問題後研發第一時間知曉,而不是讓用戶來告訴咱們出問題了。mongodb
Cat 能夠出故障後提供秒級別的異常告警機制,不用再等用戶來反饋問題了。數據庫
場景二:出故障後如何快速定位問題後端
通常傳統的方式當出現問題後,咱們就會去服務器上看看服務是否還存活。若是存活就會看看日誌是否有異常信息。緩存
在 Cat 後臺的首頁,會展現各個系統的運行狀況,若是有異常,則會大片飄紅,很是明顯。最直接的方式仍是直接查看 Problem 報表,這裏會爲咱們展現直接的異常信息,快速定位問題。服務器
場景三:用戶反饋訂單列表要 10 幾秒才展現,用戶反饋下單一直在轉圈圈
場景三屬於優化相關,對於研發來講,優化是一個長期的過程,沒有最好只有更好。優化除了須要有對應的方案,最重要的是要對症下藥。
所謂的對症下藥也就是在優化以前,你得先知道哪裏比較慢。RPC 調用慢?數據庫查詢慢?緩存更新慢?
Cat 能夠提供詳細的性能數據,95 線,99 線等。更細粒度的就是能夠看到某個請求或者某個業務方法的全部耗時邏輯,前提是你作了埋點操做。
Cat 目前有五種報表,每種都有特定的應用場景,下面咱們來具體聊聊這些報表的做用。
適用於監控一段代碼運行狀況,好比:運行次數、QPS、錯誤次數、失敗率、響應時間統計(平均影響時間、Tp 分位值)等等場景。
埋點方式:
public void shopService() {
Transaction transaction = Cat.newTransaction("ShopService", "Service");
try {
service();
transaction.setStatus(Transaction.SUCCESS);
} catch (Exception e) {
transaction.setStatus(e); // catch 到異常,設置狀態,表明此請求失敗
Cat.logError(e); // 將異常上報到cat上
// 也能夠選擇向上拋出: throw e;
} finally {
transaction.complete();
}
}
複製代碼
能夠在基礎框架中對 Rpc, 數據庫等框架進行埋點,這樣就能夠經過 Cat 來監控這些組件了。
業務中須要埋點也可使用 Cat 的 Transaction,好比下單,支付等核心功能,一般咱們對 URL 進行埋點就能夠了,也就包含了具體的業務流程。
適用於監控一段代碼運行次數,好比記錄程序中一個事件記錄了多少次,錯誤了多少次。Event 報表的總體結構與 Transaction 報表幾乎同樣,只缺乏響應時間的統計。
埋點方式:
Cat.logEvent("Func", "Func1");
複製代碼
Problem 記錄整個項目在運行過程當中出現的問題,包括一些異常、錯誤、訪問較長的行爲。
若是有人反饋你的接口報 500 錯誤了,你進 Cat 後就直接能夠去 Problem 報表了,錯誤信息就在 Problem 中。
Problem 報表不須要手動埋點,咱們只須要在項目中集成日誌的 LogAppender 就能夠將全部 error 異常記錄,下面的段落中會講解如何整合 LogAppender。
Heartbeat 報表是 CAT 客戶端,以一分鐘爲週期,按期向服務端彙報當前運行時候的一些狀態。
系統指標有系統的負載信息,內存使用狀況,磁盤使用狀況等。
JVM 指標有 GC 相關信息,線程相關信息。
Business 報表對應着業務指標,好比訂單指標。與 Transaction、Event、Problem 不一樣,Business 更偏向於宏觀上的指標,另外三者偏向於微觀代碼的執行狀況。
這個報表我也沒怎麼用過,用的多的仍是前面幾個。
Kitty Cloud 的基礎組件是 Kitty,Kitty 裏面對須要的一些框架都進行了一層包裝,好比擴展,增長 Cat 埋點之類的功能。
Kitty 中對 Cat 封裝了一層,在使用的時候直接依賴 kitty-spring-cloud-starter-cat 便可整合 Cat 到項目中。
<dependency>
<groupId>com.cxytiandi</groupId>
<artifactId>kitty-spring-cloud-starter-cat</artifactId>
<version>Kitty Version</version>
</dependency>
複製代碼
而後在 application 配置文件中配置 Cat 的服務端地址信息,多個英文逗號分隔:
cat.servers=47.105.66.210
複製代碼
在項目的 resources 目錄下建立 META-INF 目錄,而後在 META-INF 中建立 app.properties 文件配置 app.name。此名稱是在 Cat 後臺顯示的應用名
app.name=kitty-cloud-comment-provider
複製代碼
最後須要配置一下 Cat 的 LogAppender,這樣應用在記錄 error 級別的日誌時,Cat 能夠及時進行異常告警操做。
在 logback.xml 增長下面的配置:
<appender name="CatAppender" class="com.dianping.cat.logback.CatLogbackAppender"></appender>
<root level="INFO">
<appender-ref ref="CatAppender" />
</root>
複製代碼
更詳細的內容請移步 Cat 的 Github 主頁進行查看。
基於 Spring Boot 作 Web 應用開發,咱們最經常使用到的一個 Starter 包就是 spring-boot-starter-web。
若是你使用了 Kitty 來構建微服務的框架,那麼就再也不須要直接依賴 spring-boot-starter-web。而是須要依賴 Kitty 中的 kitty-spring-cloud-starter-web。
kitty-spring-cloud-starter-web 在 spring-boot-starter-web 的基礎上進行了封裝,會對請求的 Url 進行 Cat 埋點,會對一些通用信息進行接收透傳,會對 RestTemplate 的調用進行 Cat 埋點。
在項目中依賴 kitty-spring-cloud-starter-web:
<dependency>
<groupId>com.cxytiandi</groupId>
<artifactId>kitty-spring-cloud-starter-web</artifactId>
<version>Kitty Version</version>
</dependency>
複製代碼
啓動項目,而後訪問你的 REST API。能夠在 Cat 的控制檯看到 URL 的監控信息。
點擊 URL 進去能夠看到具體的 URL 信息。
再進一步能夠看到整個 URL 的信息,好比數據庫的查詢,緩存的操做,Http 的調用等。後端同窗在優化性能的時候就直接從 URL 下手能夠將整個請求的鏈路耗時的狀況都分析清楚。
Kitty 中 Mybatis 是用的 Mybatis Plus, 主要是對數據庫相關操做的 SQL 進行了 Cat 埋點,能夠很方便的查看 SQL 的耗時狀況。
依賴 kitty-spring-cloud-starter-mybatis:
<dependency>
<groupId>com.cxytiandi</groupId>
<artifactId>kitty-spring-cloud-starter-mybatis</artifactId>
<version>Kitty Version</version>
</dependency>
複製代碼
其餘的使用方式仍是跟 Mybatis Plus 同樣,具體參考 Mybatis Plus 文檔:https://mp.baomidou.com[2]
只要涉及到數據庫的操做,都會在 Cat 中進行數據的展現。
點擊 SQL 進去還能夠看到是哪一個 Mapper 的操做。
再進一步就能夠看到具體的 SQL 語句和消耗的時間。
有了這些數據,後端研發同窗就能夠對相關的 SQL 進行優化了。
若是須要使用 Spring Data Redis 的話,直接集成 kitty-spring-cloud-starter-redis 就能夠,kitty-spring-cloud-starter-redis 中對 Redis 的命令進行了埋點,能夠在 Cat 上直觀的查看對應的命令和消耗的時間。
添加對應的 Maven 依賴:
<dependency>
<groupId>com.cxytiandi</groupId>
<artifactId>kitty-spring-cloud-starter-redis</artifactId>
<version>Kitty Version</version>
</dependency>
複製代碼
直接使用 StringRedisTemplate:
@Autowired
private StringRedisTemplate stringRedisTemplate;
stringRedisTemplate.opsForValue().set("name", "yinjihuan");
複製代碼
Cat 中能夠看到 Redis 信息。
點擊 Redis 進去能夠看到有哪些命令。
再進去能夠看到命令的詳細信息,好比操做的 key 和消耗的時間。
Kitty 中對 Spring Data Mongodb 作了封裝,只對 MongoTemplate 作了埋點。使用時須要依賴 kitty-spring-cloud-starter-mongodb。
<dependency>
<groupId>com.cxytiandi</groupId>
<artifactId>kitty-spring-cloud-starter-mongodb</artifactId>
<version>Kitty Version</version>
</dependency>
複製代碼
在發生 Mongo 的操做後,Cat 上就能夠看到相關的數據了。
點進去就能夠看到是 MongoTemplate 的哪一個方法發生了調用。
再進一步就能夠看到具體的 Mongo 參數和消耗的時間。
還有 Dubbo, Feign,Jetcache,ElasticSearch 等框架的埋點就不細講了,感興趣的能夠移步 Github 查看代碼。
若是要對業務方法進行監控,咱們通常會用 Transaction 功能,將業務邏輯包含在 Transaction 裏面,就能監控這個業務的耗時信息。
埋點的方式也是經過 Cat.newTransaction 來進行,具體能夠參考上面 Transaction 介紹時給出的埋點示列。
像這種埋點的方式最好是有一個統一的工具類去作,將埋點的細節封裝起來。
public class CatTransactionManager {
public static <T> T newTransaction(Supplier<T> function, String type, String name, Map<String, Object> data) {
Transaction transaction = Cat.newTransaction(type, name);
if (data != null && !data.isEmpty()) {
data.forEach(transaction::addData);
}
try {
T result = function.get();
transaction.setStatus(Message.SUCCESS);
return result;
} catch (Exception e) {
Cat.logError(e);
if (e.getMessage() != null) {
Cat.logEvent(type + "_" + name + "_Error", e.getMessage());
}
transaction.setStatus(e);
throw e;
} finally {
transaction.complete();
}
}
}
複製代碼
工具類使用:
public SearchResponse search(SearchRequest searchRequest, RequestOptions options) {
Map<String, Object> catData = new HashMap<>(1);
catData.put(ElasticSearchConstant.SEARCH_REQUEST, searchRequest.toString());
return CatTransactionManager.newTransaction(() -> {
try {
return restHighLevelClient.search(searchRequest, options);
} catch (IOException e) {
throw new RuntimeException(e);
}
}, ElasticSearchConstant.ES_CAT_TYPE, ElasticSearchConstant.SEARCH, catData);
}
複製代碼
經過使用工具類,再也不須要每一個監控的地方都是設置 Transaction 是否 complete,是否成功這些信息了。
爲了讓 Transaction 使用更方便,咱們能夠自定義註解來作這個事情。好比須要監控下單,支付等核心業務方法,那麼就可使用自定義的 Transaction 註解加在方法上,而後經過 AOP 去統一作監控。
定義註解:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface CatTransaction {
/**
* 類型, 默認爲Method
* @return
*/
String type() default "";
/**
* 名稱, 默認爲類名.方法名
* @return
*/
String name() default "";
/**
* 是否保存參數信息到Cat
* @return
*/
boolean isSaveParamToCat() default true;
}
複製代碼
定義切面:
@Aspect public class CatTransactionAspect { @Around("@annotation(catTransaction)") public Object aroundAdvice(ProceedingJoinPoint joinpoint, CatTransaction catTransaction) throws Throwable { String type = catTransaction.type(); if (StringUtils.isEmpty(type)){ type = CatConstantsExt.METHOD; } String name = catTransaction.name(); if (StringUtils.isEmpty(name)){ name = joinpoint.getSignature().getDeclaringType().getSimpleName() + "." + joinpoint.getSignature().getName(); } Map<String, Object> data = new HashMap<>(1); if (catTransaction.isSaveParamToCat()) { Object[] args = joinpoint.getArgs(); if (args != null) { data.put("params", JsonUtils.toJson(args)); } } return CatTransactionManager.newTransaction(() -> { try { return joinpoint.proceed(); } catch (Throwable throwable) { throw new RuntimeException(throwable); } }, type, name, data); } 複製代碼} 複製代碼
註解使用:
@CatTransaction
@Override
public Page<ArticleIndexBO> searchArticleIndex(ArticleIndexSearchParam param) {
}
複製代碼
Cat 主要是一個實時監控系統,並非一個標準的全鏈路系統,主要是 Cat 的 logview 在異步線程等等一些場景下,不太合適,Cat 自己模型並不適合這個。Cat 的 Github 上有說明:在美團點評內部,有 mtrace 專門作全鏈路分析。
可是若是在 Mvc,遠程調用等這些框架中作好了數據的無縫傳輸,Cat 也能夠充當一個鏈路跟蹤的系統,基本的場景足夠了。
Cat 也能夠構建遠程消息樹,能夠看到請求通過了哪些服務,每一個服務的耗時等信息。只不過服務之間的依賴關係圖在 Cat 中沒有。
下圖請求從網關進行請求轉發到 articles 上面,而後 articles 裏面調用了 users 的接口。
Skywalking 也是一款很是優秀的 APM 框架,我還沒用過,不過看過一些文檔,功能點挺全的 ,界面也挺好看。最大的優點是不用像 Cat 同樣須要埋點,使用字節碼加強的方式來對應用進行監控。
之因此列出這個小標題是由於若是你們尚未用的話確定會糾結要選擇落地哪一個去作監控。我我的認爲這兩個均可以,能夠本身先弄個簡單的版本體驗體驗,結合你想要的功能點來評估落地哪一個。
用 Cat 的話最好有一套基礎框架,在基礎框架中埋好點,這樣才能在 Cat 中詳細的顯示各類信息來幫助咱們快速定位問題和優化性能。
感興趣的 Star 下唄:https://github.com/yinjihuan/kitty-cloud[3]
關於做者:尹吉歡,簡單的技術愛好者,《Spring Cloud 微服務-全棧技術與案例解析》, 《Spring Cloud 微服務 入門 實戰與進階》做者, 公衆號 猿天地 發起人。我的微信 jihuan900,歡迎勾搭。
https://github.com/dianping/cat: https://github.com/dianping/cat
[2]https://mp.baomidou.com: https://mp.baomidou.com
[3]https://github.com/yinjihuan/kitty-cloud: https://github.com/yinjihuan/kitty-cloud
感興趣的能夠關注下個人微信公衆號 猿天地,更多技術文章第一時間閱讀。個人GitHub也有一些開源的代碼 github.com/yinjihuan