1. 程式人生 > >深入詳解美團點評CAT跨語言服務監控(一) CAT簡介與部署

深入詳解美團點評CAT跨語言服務監控(一) CAT簡介與部署

前言: CAT是一個實時和接近全量的監控系統,它側重於對Java應用的監控,除了與點評RPC元件融合的很好之外,他將會能與Spring、MyBatis、Dubbo 等框架以及Log4j 等結合,支援PHP、C++、Go等多語言應用,基本接入了美團點評上海側所有核心應用。目前在中介軟體(MVC、RPC、資料庫、快取等)框架中得到廣泛應用,為美團點評各業務線提供系統的效能指標、健康狀況、監控告警等,在微服務監控領域也是非常有用的一套元件。支撐這美團每天450億的訊息,50TB的資料監控,應用於 7000+應用伺服器,2000+的業務,單臺機器能15W qps,15臺CAT物理叢集,有著極高的效能,同時CAT支援豐富的報表,架構擁有靈活的擴充套件性,使用者可以定製自己的監控、報表需求,本文將就CAT的部署、架構原始碼以及多語言支援等方面展開剖析。CAT在攜程、陸金所、獵聘網、找鋼網、平安銀行等多家網際網路公司生產環境應用。

目錄:

    介紹
    背景介紹
    Cat系統的特性
    訊息樹
    CAT服務端部署
    CAT客戶端Demo

(二) CAT服務端初始化
    Cat模組
    Cat-servlet初始化
    plexus - IOC容器
    模組的載入 - 模型模式
    cat-home的setup
    TcpSocketReceiver--- netty reactor 模式的應用
    訊息的解碼
    
(三) CAT客戶端原理
    cat客戶端部分核心類
    訊息的組織 - 訊息樹
    客戶端的初始化
    訊息生產 -- 入棧
    Context 執行緒本地變數
    Transaction事務的開啟
    其他型別訊息組合
    訊息的完成-出棧
    訊息的傳送-佇列化
    訊息的序列化
    MessageId的設計
    

(四) 服務端訊息分發
    分發架構
    分析管理器的初始化
    消費者與週期管理器的初始化
    什麼是週期?
    週期任務-任務佇列
    訊息分發
    週期策略
    
(五) 配置與資料庫操作
    CAT配置
    程式碼自動生成
    資料庫操作
    資料庫連線管理
    
(六) 訊息分析器與報表(一)
    訊息分析器的構建
    TopAnalyzer
    EventAnalyzer - 事件發生次數分析
    MetricAnalyzer - 業務分析
    ProblemAnalyzer -異常分析
    TransactionAnalyzer - 事務分析
    
(七)訊息分析器與報表(二)

    CrossAnalyzer-呼叫鏈分析
    StorageAnalyzer  --資料庫/快取分析
    StateAnalyzer -- CAT狀態分析
    HeartbeatAnalyzer  -- 心跳分析
    DumpAnalyzer -- 原始訊息LogView儲存
    自定義分析器與報表
    
(八) 報表持久化
    週期結束
    分析器的結束 -- 報表持久化
    報表預處理
    報表的檔案儲存 -- 重入鎖
    報表的資料庫儲存
    定時任務
    
(九) 管理平臺MVC框架
    Servlet容器與請求生命週期
    頁面路由初始化
    請求處理流程
    
(十)與JAVA框架的整合
    與Spring MVC整合
    與Spring Boot 整合
    與Spring Cloud 整合
    與dubbo整合
    與MyBatis整合
    與Log4j整合
    
(十一) 其他語言支援
    PHP語言
    C++語言
    LUA語言
    Go語言
    Python語言
    Node.js語言
    Android埋點

    Object  C -- IOS 埋點

(十二) 報警與監控提醒

    簡訊通知

    郵件通知

(十三) CAT與實時計算
    hadoop模組

    spark實時計算模組

介紹

        大眾點評CAT系統原型和理念來源於eBay的CAL的系統,CAT系統第一代設計者吳其敏在eBay工作長達十幾年,對CAL系統有深刻的理解。CAT不僅增強了CAL系統核心模型,還添加了更豐富的報表。自2014年開源以來,CAT在攜程、陸金所、獵聘網、找鋼網等多家網際網路公司生產環境應用。

    CAT是一個實時和接近全量的監控系統,它側重於對Java應用的監控,除了與點評RPC元件融合的很好之外,他將會能與Spring、MyBatis、Dubbo 等框架以及Log4j 等結合,不久將會支援PHP、C++、Go等多語言應用,基本接入了美團點評上海側所有核心應用。目前在中介軟體(MVC、RPC、資料庫、快取等)框架中得到廣泛應用,為美團點評各業務線提供系統的效能指標、健康狀況、監控告警等,在微服務監控領域也是非常有用的一套元件。

    在詳細瞭解CAT的整體設計細節之後,我們可以在CAT基礎之上輕鬆擴充套件我們自己的監控和資料收集模組。

背景介紹

    CAT整個產品研發是從2011年底開始的,當時正是大眾點評App Net遷移Java的核心起步階段。當初大眾點評App已經有核心的基礎中介軟體、RPC元件Pigeon、統一配置元件lion。整體Java遷移已經在服務化的路上。隨著服務化的深入,整體Java在線上部署規模逐漸變多,同時,暴露的問題也越來越多。典型的問題有:

  • 大量報錯,特別是核心服務,需要花很久時間才能定位。

  • 異常日誌都需要線上許可權登陸線上機器排查,排錯時間長。

  • 有些簡單的錯誤定位都非常困難(一次將線上的庫配置到了Beta,花了整個通宵排錯)。

  • 很多不了了之的問題都懷疑是網路問題(從現在看,內網真的很少出問題)。

    雖然那時候也有一些簡單的監控工具(比如Zabbix,自己研發的Hawk系統等),可能單個工具在某方面的功能還不錯,但整體服務化水平參差不齊、擴充套件能力相對較弱,監控工具間不能互通互聯,使得查詢問題根源基本都需要在多個系統之間切換,有時候真的是靠“人品”才能找出根源。適逢吳其敏從eBay加入大眾點評成為首席架構師,eBay的CAL系統在內部非常成功,就在這樣天時地利與人和的情況下,我們開始研發了大眾點評App第一代監控系統——CAT。

Cat系統的特性

  • 實時處理:資訊的價值會隨時間銳減,尤其是事故處理過程中。
  • 全量資料:最開始的設計目標就是全量採集,全量的好處有很多。
  • 高可用:所有應用都倒下了,需要監控還站著,並告訴工程師發生了什麼,做到故障還原和問題定位。
  • 故障容忍:CAT本身故障不應該影響業務正常運轉,CAT掛了,應用不該受影響,只是監控能力暫時減弱。
  • 高吞吐:要想還原真相,需要全方位地監控和度量,必須要有超強的處理吞吐能力。
  • 可擴充套件:支援分散式、跨IDC部署,橫向擴充套件的監控系統。
  • 不保證可靠:允許訊息丟失,這是一個很重要的trade-off,目前CAT服務端可以做到4個9的可靠性,可靠系統和不可靠性系統的設計差別非常大。

CAT支援的監控訊息型別包括:

  • Transaction 適合記錄跨越系統邊界的程式訪問行為,比如遠端呼叫,資料庫呼叫,也適合執行時間較長的業務邏輯監控,Transaction用來記錄一段程式碼的執行時間和次數。
  • Event 用來記錄一件事發生的次數,比如記錄系統異常,它和transaction相比缺少了時間的統計,開銷比transaction要小。
  • Heartbeat 表示程式內定期產生的統計資訊, 如CPU%, MEM%, 連線池狀態, 系統負載等。
  • Metric 用於記錄業務指標、指標可能包含對一個指標記錄次數、記錄平均值、記錄總和,業務指標最低統計粒度為1分鐘。
  • Trace 用於記錄基本的trace資訊,類似於log4j的info資訊,這些資訊僅用於檢視一些相關資訊

訊息樹

    CAT監控系統將每次URL、Service的請求內部執行情況都封裝為一個完整的訊息樹、訊息樹可能包括Transaction、Event、Heartbeat、Metric和Trace資訊,各個訊息樹之間,通過 rootMessageId以及parentMessageId串聯起來,形成整個呼叫鏈條。

完整的訊息樹:

視覺化的訊息樹:

分散式訊息樹【一臺機器呼叫另外一臺機器】:


 

CAT服務端部署

CAT安裝環境:

    • Linux 2.6以及之上(2.6核心才可以支援epoll),線上服務端部署請使用Linux環境,Mac以及Windows環境可以作為開發環境,美團點評內部CentOS 6.5
    • Java 6,7,8,服務端推薦是用jdk7的版本,客戶端jdk6、7、8都支援
    • Maven 3.3.3
    • MySQL 5.6,5.7,更高版本MySQL都不建議使用,不清楚相容性
    • J2EE容器建議使用tomcat,建議版本7.0.70
    • Hadoop環境可選,一般建議規模較小的公司直接使用磁碟模式,可以申請CAT服務端,500GB磁碟或者更大磁碟,這個磁碟掛載在/data/目錄上

目前我司線上環境:

    Distributor ID: CentOS
    Description: CentOS release 6.5 (Final)
    Release: 6.5
    Codename: Final
    Server version: Apache Tomcat/8.0.30
    Server built:   Dec 1 2015 22:30:46 UTC
    Server number:  8.0.30.0
    OS Name:        Linux
    OS Version:     2.6.32-431.el6.x86_64
    Architecture:   amd64
    JVM Version:    1.8.0_111-b14
    JVM Vendor:     Oracle Corporation
    Maven 3.3.3
    Mysql 5.6
    Tomcat  7.0.70  建議使用此版本

我的開發環境:

    作業系統: Windows 7
    IDE: Intelij IDEA
    JDK版本:1.8
    Mysql: 5.6
    Maven: 3.3.3
    Server version:Apache Tomcat/8.0.30

安裝CAT叢集大致步驟

    初始化Mysql資料庫,一套CAT叢集部署一個數據庫,初始化指令碼在script下的Cat.sql
    準備三臺CAT伺服器,IP比如為10.1.1.1,10.1.1.2,10.1.1.3,下面的例子會以這個IP為例子
    初始化/data/目錄,配置幾個配置檔案/data/appdatas/cat/*.xml 幾個配置檔案,具體下面有詳細說明
    打包cat.war 放入tomcat容器

    修改一個路由配置,重啟tomcat

Tomcat啟動引數調整,修改 catalina.sh檔案【服務端】

    需要每臺CAT叢集10.1.1.1,10.1.1.2,10.1.1.3都進行部署
    建議使用cms gc策略
    建議cat的使用堆大小至少10G以上,開發環境啟動2G堆啟動即可

CATALINA_OPTS="$CATALINA_OPTS -server -Djava.awt.headless=true -Xms25G -Xmx25G -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewSize=10144m -XX:MaxNewSize=10144m -XX:SurvivorRatio=10 -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:MaxTenuringThreshold=13 -XX:+UseConcMarkSweepGC -XX:+DisableExplicitGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+ScavengeBeforeFullGC -XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelRemarkEnabled -XX:CMSFullGCsBeforeCompaction=9 -XX:CMSInitiatingOccupancyFraction=60 -XX:+CMSClassUnloadingEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:-ReduceInitialCardMarks -XX:+CMSPermGenSweepingEnabled -XX:CMSInitiatingPermOccupancyFraction=70 -XX:+ExplicitGCInvokesConcurrent -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.EPollSelectorProvider -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="%CATALINA_HOME%\conf\logging.properties" -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationConcurrentTime -XX:+PrintHeapAtGC -Xloggc:/data/applogs/heap_trace.txt -XX:-HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/applogs/HeapDumpOnOutOfMemoryError -Djava.util.Arrays.useLegacyMergeSort=true"

    修改中文亂碼 tomcat conf 目錄下 server.xml:

<Connector port="8080" protocol="HTTP/1.1"
           URIEncoding="utf-8"    connectionTimeout="20000"
           redirectPort="8443" />  增加  URIEncoding="utf-8"

程式對於/data/目錄具體讀寫許可權【包括客戶端&服務端】

  • 注意無論是CAT客戶端和服務端都要求/data/目錄能進行讀寫操作,如果/data/目錄不能寫,建議使用linux的軟連結連結到一個固定可寫的目錄,軟連結的基本命令請自行搜尋google

  • 此目錄會存一些CAT必要的配置檔案,執行時候的快取檔案,建議不要修改,如果想改,請自行研究好原始碼裡面的東西,在酌情修改,此目錄不支援進行配置化

  • mkdir /data

  • chmod 777 /data/ -R

  • 如果是Windows開發環境則是對程式執行盤下的/data/appdatas/cat和/data/applogs/cat有讀寫許可權,如果cat服務執行在e盤的tomcat中,則需要對e:/data/appdatas/cat和e:/data/applogs/cat有讀寫許可權

  • 如果windows實在不知道哪個盤,就所有盤都建好,最後看哪個盤多檔案,就知道哪個了,當然你也可以通過配置系統環境變數CAT_HOME來指定伺服器日誌儲存的路徑,不過好像資料庫連線xml資訊等好像不太好自己配置,最好還是採用系統預設的 /data 目錄。

配置/data/appdatas/cat/client.xml【包括客戶端&服務端】

  • 此配置檔案的作用是所有的客戶端都需要一個地址指向CAT的服務端,比如CAT服務端有三個IP,10.1.1.1,10.1.1.2,10.1.1.3,2280是預設的CAT服務端接受資料的埠,不允許修改,http-port是Tomcat啟動的埠,預設是8080,建議使用預設埠。
  • 此檔案可以通過運維統一進行部署和維護,比如使用puppert等運維工具。
  • 不同環境這份檔案不一樣,比如區分prod環境以及test環境,在美團點評內部一共是2套環境的CAT,一份是生產環境,一份是測試環境
<?xml version="1.0" encoding="utf-8"?>
    <config mode="client">
        <servers>
                <server ip="10.1.1.1" port="2280" http-port="8080"/>
                <server ip="10.1.1.2" port="2280" http-port="8080"/>
                <server ip="10.1.1.3" port="2280" http-port="8080"/>
        </servers>
    </config>

安裝CAT的資料庫

  • 資料庫的指令碼檔案 script/Cat.sql
  • MySQL的一個系統引數:max_allowed_packet,其預設值為1048576(1M),修改為1000M,修改完需要重啟mysql
  • 注意:一套獨立的CAT叢集只需要一個數據庫(之前碰到過個別同學在每臺cat的服務端節點都安裝了一個數據庫)

配置/data/appdatas/cat/datasources.xml【服務端配置】

需要每臺CAT叢集10.1.1.1,10.1.1.2,10.1.1.3都進行部署

注意:此xml僅僅為模板,請根據自己實際的情況替換jdbc.url,jdbc.user,jdbc.password的實際值。 app資料庫和cat資料配置為一樣,app庫不起作用,為了執行時候程式碼不報錯。

<?xml version="1.0" encoding="utf-8"?>

<data-sources>
	<data-source id="cat">
		<maximum-pool-size>3</maximum-pool-size>
		<connection-timeout>1s</connection-timeout>
		<idle-timeout>10m</idle-timeout>
		<statement-cache-size>1000</statement-cache-size>
		<properties>
			<driver>com.mysql.jdbc.Driver</driver>
			<url><![CDATA[${jdbc.url}]]></url>
			<user>${jdbc.user}</user>
			<password>${jdbc.password}</password>
			<connectionProperties><![CDATA[useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&socketTimeout=120000]]></connectionProperties>
		</properties>
	</data-source>
	<data-source id="app">
		<maximum-pool-size>3</maximum-pool-size>
		<connection-timeout>1s</connection-timeout>
		<idle-timeout>10m</idle-timeout>
		<statement-cache-size>1000</statement-cache-size>
		<properties>
			<driver>com.mysql.jdbc.Driver</driver>
			<url><![CDATA[${jdbc.url}]]></url>
			<user>${jdbc.user}</user>
			<password>${jdbc.password}</password>
			<connectionProperties><![CDATA[useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&socketTimeout=120000]]></connectionProperties>
		</properties>
	</data-source>
</data-sources>


配置/data/appdatas/cat/server.xml【服務端配置】
    需要每臺CAT叢集10.1.1.1,10.1.1.2,10.1.1.3都進行部署
    CAT節點一共有四個職責

    控制檯 - 提供給業務人員進行資料檢視【預設所有的cat節點都可以作為控制檯,不可配置】
    消費機 - 實時接收業務資料,實時處理,提供實時分析報表【預設所有的cat節點都可以作為消費機,不可配置】
    告警端 - 啟動告警執行緒,進行規則匹配,傳送告警(目前僅支援單點部署)【可以配置】
    任務機 - 做一些離線的任務,合併天、周、月等報表 【可以配置】
    線上做多叢集部署,比如說10.1.1.1,10.1.1.2,10.1.1.3這三臺機器


    建議選取一臺10.1.1.1 負責角色有控制檯、告警端、任務機,建議配置域名訪問CAT,就配置一臺機器10.1.1.1一臺機器掛在域名下面
    10.1.1.2,10.1.1.3 負責消費機處理,這樣能做到有效隔離,任務機、告警等問題不影響實時資料處理
    預設script下的server.xml為

<?xml version="1.0" encoding="utf-8"?>
<config local-mode="false" hdfs-machine="false" job-machine="true" alert-machine="false">
	<storage  local-base-dir="/data/appdatas/cat/bucket/" max-hdfs-storage-time="15" local-report-storage-time="7" local-logivew-storage-time="7">
		<hdfs id="logview" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="logview"/>
		<hdfs id="dump" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="dump"/>
		<hdfs id="remote" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="remote"/>
	</storage>
	<console default-domain="Cat" show-cat-domain="true">
		<remote-servers>127.0.0.1:8080</remote-servers>
	</console>
</config>

配置說明:

  • local-mode : 建議在開發環境以及生產環境時,都設定為false
  • hdfs-machine : 定義是否啟用HDFS儲存方式,預設為 false
  • job-machine : 定義當前服務是否為報告工作機(開啟生成彙總報告和統計報告的任務,只需要一臺服務機開啟此功能),預設為 false
  • alert-machine : 定義當前服務是否為報警機(開啟各類報警監聽,只需要一臺服務機開啟此功能),預設為 false;
  • storage : 定義資料儲存配置資訊
  • local-report-storage-time : 定義本地報告檔案存放時長,單位為(天)
  • local-logivew-storage-time : 定義本地日誌檔案存放時長,單位為(天)
  • local-base-dir : 定義本地資料儲存目錄,建議直接使用/data/appdatas/cat/bucket目錄
  • hdfs : 定義HDFS配置資訊
  • server-uri : 定義HDFS服務地址
  • console : 定義服務控制檯資訊
  • remote-servers : 定義HTTP服務列表,(遠端監聽端同步更新服務端資訊即取此值)
  • ldap : 定義LDAP配置資訊(這個可以忽略)
  • ldapUrl : 定義LDAP服務地址(這個可以忽略)

按照如上的說明,10.1.1.1 機器/data/appdatas/cat/serverm.xml配置,注意hdfs配置就隨便下了一個,請忽略

<?xml version="1.0" encoding="utf-8"?>
<config local-mode="false" hdfs-machine="false" job-machine="true" alert-machine="true">
	<storage  local-base-dir="/data/appdatas/cat/bucket/" max-hdfs-storage-time="15" local-report-storage-time="7" local-logivew-storage-time="7">
	<hdfs id="logview" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="logview"/>
		<hdfs id="dump" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="dump"/>
		<hdfs id="remote" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="remote"/>
	</storage>
	<console default-domain="Cat" show-cat-domain="true">
		<remote-servers>10.1.1.1:8080,10.1.1.2:8080,10.1.1.3:8080</remote-servers>
	</console>
</config>

10.1.1.2,10.1.1.3 機器/data/appdatas/cat/serverm.xml配置如下,僅僅job-machine&alert-machine修改為false

<?xml version="1.0" encoding="utf-8"?>
<config local-mode="false" hdfs-machine="false" job-machine="false" alert-machine="false">
	<storage  local-base-dir="/data/appdatas/cat/bucket/" max-hdfs-storage-time="15" local-report-storage-time="7" local-logivew-storage-time="7">
	<hdfs id="logview" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="logview"/>
		<hdfs id="dump" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="dump"/>
		<hdfs id="remote" max-size="128M" server-uri="hdfs://10.1.77.86/user/cat" base-dir="remote"/>
	</storage>
	<console default-domain="Cat" show-cat-domain="true">
		<remote-servers>10.1.1.1:8080,10.1.1.2:8080,10.1.1.3:8080</remote-servers>
	</console>
</config>

war打包

    1、在cat的原始碼目錄,執行mvn clean install -DskipTests
    2、如果發現cat的war打包不通過,CAT所需要依賴jar都部署在 http://unidal.org/nexus/
    3、可以配置這個公有云的倉庫地址到本地的settings路徑,理論上不需要配置即可,可以參考cat的pom.xml配置

 4、如果自行打包仍然問題,請使用下面連結進行下載http://unidal.org/nexus/service/local/repositories/releases/content/com/dianping/cat/cat-home/2.0.0/cat-home-2.0.0.war

    5、官方的cat的master版本,重新命名為cat.war進行部署,注意此war是用jdk8,服務端請使用jdk8版本
    6、如下是個人本機電腦的測試,下載的jar來自於repo1.maven.org 以及 unidal.org

Downloading: http://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils/3.0.24/plexus-utils-3.0.24.jar
Downloaded: http://repo1.maven.org/maven2/org/apache/commons/commons-email/1.1/commons-email-1.1.jar (30 KB at 9.8 KB/sec)
Downloaded: http://repo1.maven.org/maven2/javax/servlet/jstl/1.2/jstl-1.2.jar (405 KB at 107.7 KB/sec)
Downloaded: http://repo1.maven.org/maven2/com/google/code/javaparser/javaparser/1.0.8/javaparser-1.0.8.jar (235 KB at 55.4 KB/sec)
Downloaded: http://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils/3.0.24/plexus-utils-3.0.24.jar (242 KB at 46.9 KB/sec)
Downloaded: http://repo1.maven.org/maven2/org/freemarker/freemarker/2.3.9/freemarker-2.3.9.jar (789 KB at 113.3 KB/sec)
Downloading: http://unidal.org/nexus/content/repositories/releases/org/unidal/webres/WebResServer/1.2.1/WebResServer-1.2.1.jar
Downloading: http://unidal.org/nexus/content/repositories/releases/org/unidal/webres/WebResTagLibrary/1.2.1/WebResTagLibrary-1.2.1.jar
Downloading: http://unidal.org/nexus/content/repositories/releases/org/unidal/webres/WebResTag/1.2.1/WebResTag-1.2.1.jar
Downloading: http://unidal.org/nexus/content/repositories/releases/org/unidal/webres/WebResRuntime/1.2.1/WebResRuntime-1.2.1.jar
Downloading: http://unidal.org/nexus/content/repositories/releases/org/unidal/webres/WebResApi/1.2.1/WebResApi-1.2.1.jar
Downloaded: http://unidal.org/nexus/content/repositories/releases/org/unidal/webres/WebResApi/1.2.1/WebResApi-1.2.1.jar (21 KB at 82.7 KB/sec)
Downloading: http://unidal.org/nexus/content/repositories/releases/org/unidal/webres/WebResBase/1.2.1/WebResBase-1.2.1.jar
```
[INFO] parent ............................................. SUCCESS [ 40.478 s]
[INFO] cat-client ......................................... SUCCESS [03:47 min]
[INFO] cat-core ........................................... SUCCESS [ 31.740 s]
[INFO] cat-hadoop ......................................... SUCCESS [02:50 min]
[INFO] cat-consumer ....................................... SUCCESS [  3.197 s]
[INFO] cat-home ........................................... SUCCESS [ 58.964 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
``` 

war部署

    1、將cat.war部署到10.1.1.1的tomcat的webapps下,啟動tomcat,注意webapps下只允許放一個war,僅僅為cat.war
    2、如果發現重啟報錯,裡面有NPE等特殊情況,可以檢查當前java程序,ps aux | grep java,可能存在之前的tomcat的程序沒有關閉,又新啟動了一個,導致出問題,建議kill -9 幹掉所有的java程序
    3、開啟控制檯的URL,http://10.1.1.1:8080/cat/s/config?op=routerConfigUpdate
    4、注意10.1.1.1這個IP需要替換為自己實際的IP連結,修改路由配置只能修改一次即可

    5、修改路由配置為如下,當為如下配置時,10.1.1.1 正常不起消費資料的作用,僅當10.1.1.2以及10.1.1.3都掛掉才會進行實時流量消費

<?xml version="1.0" encoding="utf-8"?>
<router-config backup-server="10.1.1.1" backup-server-port="2280">
   <default-server id="10.1.1.2" weight="1.0" port="2280" enable="true"/>
   <default-server id="10.1.1.3" weight="1.0" port="2280" enable="true"/>
</router-config>

    6、重啟10.1.1.1的機器的tomcat
    7、將cat.war部署到10.1.1.2,10.1.1.3這兩臺機器中,啟動tomcat
    8、cat叢集部署完畢,如果有問題,歡迎在微信群諮詢,如果文件有誤差,歡迎指正以及提交pullrequest

重啟保證資料不丟

    請在tomcat重啟之前呼叫當前tomcat的儲存資料的連結 http://${ip}:8080/cat/r/home?op=checkpoint,重啟之後資料會恢復。【注意重啟時間在每小時的整點10-55分鐘之間】
 線上部署時候,建議把此連結呼叫存放於tomcat的stop指令碼中,這樣不需要每次手工呼叫

開發環境CAT的部署

    1、請按照如上部署/data/環境目錄,資料庫配置client.xml ,datasources.xml,server.xml這三個配置檔案,注意server.xml裡面的節點角色,job-machine&alert-machine都可以配置為true
    2、在cat目錄中執行 mvn eclipse:eclipse,此步驟會生成一些程式碼檔案,直接匯入到工程會發現找不到類
    3、將原始碼以普通專案到入eclipse中,注意不要以maven專案匯入工程
    4、執行com.dianping.cat.TestServer 這個類,即可啟動cat伺服器
    5、這裡和叢集版本唯一區別就是服務端部署單節點,client.xml server.xml以及路由地址配置為單臺即可

CAT客戶端Demo

   cat客戶端的配置:

    cat客戶端也需要配置 /data 目錄,程式對於/data/目錄具體讀寫許可權可以參考上一節,

    然後通過maven引入cat客戶端包,在pom.xml 加入:

<dependency>
  <groupId>com.dianping.cat</groupId>
  <artifactId>cat-core</artifactId>
  <version>2.0.0</version>
</dependency>
<dependency>
  <groupId>com.dianping.cat</groupId>
  <artifactId>cat-client</artifactId>
  <version>2.0.0</version>
</dependency>

    引入之後:

    以上配置會通過maven從網上引入 cat-core和cat-client 包,如果無法配置引入,也可以手動引入 cat-client.jar 包。

    CAT預設會將/data/appdatas/cat 作為CAT Home目錄,這個目錄至關重要,CAT客戶端配置檔案 client.xml 是在這個目錄內,當然,如果你是在 windows 下除錯, 你也可以在src/main/resources/ 目錄下新建 META-INF/cat 目錄, 並將 client.xml 配置檔案放入 src/main/resources/META-INF/cat 目錄裡,你可以為你的監控配置domain,即專案名,如下配置 <domain id="translate"/> 。

<?xml version="1.0" encoding="utf-8"?>
 
<config mode="client" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
    <domain id="translate"/>
    <servers>
        <!-- Local mode for development -->
        <server ip="127.0.0.1" port="2280" http-port="8080" />
        <!-- If under production environment, put actual server address as list. -->
        <!-- 
            <server ip="192.168.7.71" port="2280" /> 
            <server ip="192.168.7.72" port="2280" /> 
        -->
    </servers>
</config>

第一個監控程式:

    所有都配置好了,接下來我們來寫第一個監控程式,監控都是由使用者自己埋點,當然,在本書最後,我們將會講解CAT監控如何與各個流行框架之間更好的融合,以幫助使用者達到無侵入式的監控埋點,假設我們對使用者提供了一個翻譯服務,其中有個介面就是HelloWorld,在下面程式中,我們將以事務日誌形式記錄使用者呼叫行為:

public Object helloWorld(HttpServletRequest request, HttpServletResponse response) {
    MessageProducer cat = Cat.getProducer();
    Transaction t = cat.newTransaction("URL", "Translate/HelloWorld");  //type=URL的事務記錄: 你的介面/方法名稱
    try{
        //do your business
    
        t.setStatus(Message.SUCCESS);
    } catch (Exception e) {
        Cat.getProducer().logError(e);
        t.setStatus(e);
    } finally {
        t.complete();
    }
    
    return null;
}

    好了,我們再去管理平臺去看看報表資訊把,Transaction事務報表中,type=URL的事務有3條,我們通常用URL型別的事務訊息標誌著介面服務的開始,展開之後,我們看到這個裡面該專案提供的3個服務被呼叫了,其中就有我們的 Translate/HelloWorld:

再點開某個介面的[::show::]進入詳細統計,包括耗時分佈、每分鐘的資料、以及該服務叢集下各個機器的統計情況,我們可以通過這個看出是不是某臺機器出了問題:

點選LogView進入最近一條事務的原始日誌(problem報表才會記錄全部的原始日誌):

    接下來,我們來看一個更復雜的案例,涉及服務的呼叫以及資料庫、快取的呼叫,如下:

@Controller
public class Translate {
    public Map<String, String> maps = new HashMap<String, String>();

    public Cat.Context context;
    
    @RequestMapping(value = "/translate/getWordMean", produces = "application/json")
    @ResponseBody
    //獲取翻譯釋義
    public Object getWordMean(HttpServletRequest request, HttpServletResponse response) {
        context = new Cat.Context() {
            @Override
            public void addProperty(String key, String value) {
                maps.put(key, value);
            }

            @Override
            public String getProperty(String key) {
                return maps.get(key);
            }
        }; //服務呼叫訊息上下文

        MessageProducer cat = Cat.getProducer();
        Transaction t = cat.newTransaction("URL", "translate/getWordMean");  //你的介面/方法名稱

        cat.logEvent("ClientInfo", "RemoteIp=127.0.0.1&Referer=...");  //記錄遠端呼叫端資訊
        cat.logEvent("Payload", "HTTP/GET /translate/getWordMean?client=3&clientVersion=0&v=9.5&uid=3214567...."); //呼叫端引數

        //使用者校驗
        authCheck();

        //先從快取Redis獲取結果
        Transaction cacheT = cat.newTransaction("Cache.memcached.redis", "translate_result:get");
        cat.logEvent("Cache.memcached.redis.server", "127.0.0.1:6379");

        //do your cache operation

        cacheT.setStatus(Message.SUCCESS);
        cacheT.complete();

        //do your translate operation

        //記錄遠端語音服務呼叫
        Transaction callT = cat.newTransaction("Call", "voice:getVoice");
        Cat.logEvent("Call.server","localhost");  //遠端服務地址
        Cat.logEvent("Call.app","voice");   //語音服務
        Cat.logEvent("Call.port","8080");   //語音服務埠
        Cat.logRemoteCallClient(context); //生成訊息呼叫上下文,主要是幾個messageId的建立。

        voiceService(context); 

        callT.setStatus(Message.SUCCESS);
        callT.complete();

        OutputData result = new OutputData();
        result.setErrno(0);
        result.setErrmsg("success");
        result.setTranslateResult("translate result ...");

        t.setStatus(Message.SUCCESS);
        t.complete();

        return result;
    }

    public boolean authCheck() {
        MessageProducer cat = Cat.getProducer();
        Transaction checkUser = cat.newTransaction("Method", "checkAuth");

        //從資料庫查詢使用者資訊
        Transaction sqlT = cat.newTransaction("SQL", "Select");

        cat.logEvent("SQL.Database", "jdbc:mysql://127.0.0.1:3306/user");
        cat.logEvent("SQL.Method", "select");
        cat.logEvent("SQL.Statement", "SELECT", Message.SUCCESS, "select * from user_info");

        //to do your SQL query

        sqlT.setStatus(Message.SUCCESS);
        sqlT.complete();

        //to do your auth check

        checkUser.setStatus(Message.SUCCESS);
        checkUser.complete();
        return true;
    }
    
    //執行緒模擬語音服務
    protected void voiceService(final Cat.Context context) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                //伺服器埋點,Domain為 voice 提供語音服務
                Cat.getManager().getThreadLocalMessageTree().setDomain("voice");
                MessageProducer cat = Cat.getProducer();
                Transaction voiceService = Cat.newTransaction("URL", "voice/getVoice"); //你的介面/方法名稱
                cat.logEvent("ClientInfo", "RemoteIp=127.0.0.1&Referer=...");  //記錄遠端呼叫端資訊
                cat.logEvent("Payload", "HTTP/GET /voice/getVoice?client=3&clientVersion=0&v=9.5&uid=3214567...."); //呼叫端引數

                //記錄服務資訊
                Transaction child = Cat.newTransaction("Service", "voice:getVoice");
                Cat.logEvent("Service.client", "localhost"); //客戶端地址
                Cat.logEvent("Service.app", "translate"); //客戶端domain
                Cat.logRemoteCallServer(context); //記錄訊息上下文

                //to do your business

                child.setStatus(Message.SUCCESS);
                child.complete();

                voiceService.setStatus(Message.SUCCESS);
                voiceService.complete();

            }
        };

        thread.start();

        // wait for it to complete
        try {
            thread.join();
        } catch (InterruptedException e) {
            // ignore it
        }
    }
}

    這是我們一個對外提供的翻譯服務,getWordMean為服務控制器入口,我們將原始訊息展開如下,整個服務處理耗時571ms,一進來我們會記錄URL型別事務,以及呼叫引數,然後記錄使用者校驗函式,在函式內部,有查詢使用者資訊的資料庫操作,也會被記錄下,查詢耗時150ms,接下來我們會先從快取獲取結果, 快取查詢耗時 59ms,隨後我們翻譯內容,翻譯之後我們會呼叫語音服務提供的發音介面,voice/getVoice,發音介面呼叫一共耗時 361 ms。