深入詳解美團點評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服務端部署
    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項目的開源地址: https://github.com/dianping/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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM