CAT 是美团点评开源的实时应用监控平台,提供了 TracsactionEventProblemBusiness 等丰富的指标项。在官方的 Issue 经常遇到以下几个问题

  1. 为什么 CAT 启动不起来?
  2. 能不能支持链路跟踪?
  3. 如何配置告警?
  4. 能不能接入钉钉、飞书机器人推送?

基于上面的需求,笔者 fork 了官方最新的源码进行二次开发,并打包镜像到 Docker Hub,方便大家使用。

改进了什么?

  • Docker 部署更方便,不需要额外挂载配置文件,只需要提供 JVM 参数和 MySQL 配置即可完成部署。

    1
    docker run -e MYSQL_URL="127.0.0.1" -e MYSQL_PORT="3306" -e MYSQL_SCHEMA="cat" -e MYSQL_USERNAME="数据库账号" -e MYSQL_PASSWD="数据库密码" -p 8080:8080 --name=cat-home -d shiyindaxiaojie/cat-home
  • 新增了链路跟踪支持,您可以通过日志打印的 TraceId 查找整个请求路径的 HTTP 请求耗时、RPC 调用情况、Log4j2 业务日志、SQL 和缓存执行耗时。

  • 不需要额外实现告警接口,直接开箱即用,您可以直接在后台配置邮件、钉钉、微信、飞书机器人。如下图,触发告警后,钉钉将推送相关信息,您可以点击 查看告警 直达异常位置,也可以点击 告警规则 设置告警阈值,避免多次干扰。

  • 告警流程一体化,当生产故障触发告警时,自动录入 Jira Software,便于研发内部跟进问题。

如何部署?

运行环境建议

  • JDK 版本 >= 7
  • MySQL 5.7(亲测 8.0 会报错)
  • Tomcat 8.0+(使用容器部署时可忽略)
  • Linux 内核版本 >= 2.6

在 Tomcat 下部署

Release 下载相关文件,
拷贝 client.xmldatasources.xml 到用户目录 ~/.cat/appdatas/cat 中,根据实际情况调整数据库配置。

cat.war 部署在目标 Tomcatwebapps 目录下,启动 Tomcat,访问 http://localhost:8080/cat 即可。原则上请保持 Tomcat 的端口为 8080,遇到项目启动失败的情况,建议查看 ~/.cat/applog/ 目录下的日志。

在 Docker 下部署

本项目已发布稳定的镜像到 Docker Hub,您可以直接使用如下命令,提供 JVM 参数和 MySQL 配置,完成部署。

1
docker run -e MYSQL_URL="127.0.0.1" -e MYSQL_PORT="3306" -e MYSQL_SCHEMA="cat" -e MYSQL_USERNAME="数据库账号" -e MYSQL_PASSWD="数据库密码" -p 8080:8080 --name=cat-home -d shiyindaxiaojie/cat-home

在 Kubernetes 下部署

建议使用 StatefulSet 部署,YAML 示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: cat-home
namespace: monitoring
spec:
podManagementPolicy: OrderedReady
replicas: 1
serviceName: ""
template:
spec:
affinity: {}
containers:
- env:
- name: TZ
value: Asia/Shanghai
- name: JAVA_OPTS
value: -Xmx1536m -Xms1536m -Xmn1024m
- name: MYSQL_URL
value: 数据库地址
- name: MYSQL_PORT
value: "3306"
- name: MYSQL_USERNAME
value: 数据库账号
- name: MYSQL_PASSWORD
value: 数据库密码
- name: MYSQL_SCHEMA
value: CAT 数据库名称
- name: SERVER_URL
value: CAT 运行地址
- name: JVM_XMS
value: 1536m
- name: JVM_XMX
value: 1536m
- name: JVM_XMN
value: 1024m
image: shiyindaxiaojie/cat-home:v3.4.0
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- curl http://localhost:8080/cat/r/home?op=checkpoint && sleep 30
name: cat-home
resources:
limits:
cpu: 250m
memory: 2Gi
requests:
cpu: 250m
memory: 2Gi
volumeMounts:
- mountPath: /data/appdatas/cat/bucket
name: data
subPath: appdatas
- mountPath: /data/applogs
name: log
subPath: applogs
volumes:
- name: data
nfs: # 此处省略,请根据实际情况配置
- name: log
nfs: # 此处省略,请根据实际情况配置

如何部署生产集群?

推荐使用 Kubernetes 部署生产集群,假设部署三个节点,一个节点为监控节点,另外两个节点为消费节点,如下配置:

  • 监控节点:10.1.1.1
  • 消费节点:10.1.1.2
  • 消费节点:10.1.1.3
  1. 请复制上面的 YAML,将 SERVER_URL 参数调整为 10.1.1.1,10.1.1.2,10.1.1.3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: cat-home
namespace: monitoring
spec:
podManagementPolicy: OrderedReady
replicas: 1
serviceName: ""
template:
spec:
affinity: {}
containers:
- env:
- name: SERVER_URL
value: 10.1.1.1,10.1.1.2,10.1.1.3
  1. 启动后,点击顶部导航栏 配置,从左侧 系统配置 设置 服务端配置

配置内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="utf-8"?>
<server-config>
<!-- 默认不开启监控 -->
<server id="default">
<properties>
<property name="local-mode" value="false"/>
<property name="job-machine" value="false"/>
<property name="send-machine" value="false"/>
<property name="alarm-machine" value="false"/>
<property name="hdfs-enabled" value="false"/>
<property name="remote-servers" value="10.1.1.1:8080,10.1.1.2:8080,10.1.1.3:8080"/>
</properties>
<storage local-base-dir="/data/appdatas/cat/bucket/" max-hdfs-storage-time="15" local-report-storage-time="30" local-logivew-storage-time="30" har-mode="true" upload-thread="5">
<hdfs id="dump" max-size="128M" server-uri="hdfs://127.0.0.1/" base-dir="/user/cat/dump"/>
<harfs id="dump" max-size="128M" server-uri="har://127.0.0.1/" base-dir="/user/cat/dump"/>
<properties>
<property name="hadoop.security.authentication" value="false"/>
<property name="dfs.namenode.kerberos.principal" value="hadoop/dev80.hadoop@testserver.com"/>
<property name="dfs.cat.kerberos.principal" value="cat@testserver.com"/>
<property name="dfs.cat.keytab.file" value="/data/appdatas/cat/cat.keytab"/>
<property name="java.security.krb5.realm" value="value1"/>
<property name="java.security.krb5.kdc" value="value2"/>
</properties>
</storage>
<consumer>
<long-config default-url-threshold="1000" default-sql-threshold="100" default-service-threshold="50">
<domain name="cat" url-threshold="500" sql-threshold="500"/>
<domain name="OpenPlatformWeb" url-threshold="100" sql-threshold="500"/>
</long-config>
</consumer>
</server>
<!-- 将 10.1.1.1 设置为监控节点,其他节点设置为消费节点 -->
<server id="10.1.1.1">
<properties>
<property name="job-machine" value="true"/>
<property name="send-machine" value="true"/>
<property name="alarm-machine" value="true"/>
</properties>
</server>
</server-config>
  1. 再从左侧 系统配置 设置 客户端路由

配置内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<router-config backup-server="10.1.1.1" backup-server-port="2280">
<!-- 监控节点不开启消费,其他节点开启消费,可以根据实际情况调整 weight 权重 -->
<default-server id="10.1.1.1" weight="1.0" port="2280" enable="false"/>
<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"/>
<network-policy id="default" title="default" block="false" server-group="default_group">
</network-policy>
<server-group id="default_group" title="default-group">
<group-server id="10.1.1.2"/>
<group-server id="10.1.1.3"/>
</server-group>
<domain id="cat">
<group id="default">
<server id="10.1.1.2" port="2280" weight="1.0"/>
<server id="10.1.1.3" port="2280" weight="1.0"/>
</group>
</domain>
</router-config>

配置完成后,查看首页系统状态,集群配置已生效,如下图,监控节点只负责控制台的数据展示和告警通知,不消费客户端的数据。

数据消费节点会消费客户端发送的数据,根据客户端路由设置的权重策略均摊数据。

链路跟踪怎么用?

为了减少客户端集成的工作,推荐您使用eden-architect框架,这个框架内置实现了链路ID的记录,只需要根据以下两步就可以完成 CAT 的集成。

  1. 引入 CAT 依赖

    1
    2
    3
    4
    <dependency>
    <groupId>io.github.shiyindaxiaojie</groupId>
    <artifactId>eden-cat-spring-boot-starter</artifactId>
    </dependency>
  2. 开启 CAT 配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    cat:
    enabled: false # 默认关闭,请按需开启
    trace-mode: true # 开启访问观测
    support-out-trace-id: false # 允许异构子系统间透传链路ID
    home: /tmp
    servers: localhost # CAT 地址
    tcp-port: 2280
    http-port: 8080

    # 如果您使用 Dubbo 组件,请增加对应的过滤器,确保 CAT 埋点正常工作
    dubbo:
    provider:
    filter: cat-tracing
    consumer:
    filter: cat-tracing,cat-consumer
  3. 启动您的项目,调用接口,查看控制台输出的日志内容,红圈中就是 CAT 的链路ID。

根据链路ID,在 CAT 中查看详细链路信息。

当然,如果你不希望依赖 eden-architect,则可以参考相关代码实现自己的需求。关于相关代码的实现原理,笔者将在后面的文章中给出。

如何配置告警通知?

目前 CAT 经过二次开发,实现了告警通知的开箱即用,您只需要微调相关配置,即可开启告警通知功能。

内置告警通知支持以下方式:邮件、钉钉、飞书、微信、Jira Software,配置步骤如下:

  1. 进入 配置,点击 系统配置告警渠道,如下图:

邮件钉钉Jira Software 为例,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<sender-config>
<sender id="mail" url="smtp.qq.com:25" type="post" successCode="200" batchSend="true">
<par id="username=发件人邮箱地址"/>
<par id="password=发件人邮箱密码"/>
</sender>
<sender id="dingtalk" url="https://oapi.dingtalk.com/robot/send?access_token=" type="post" successCode="200" batchSend="false">
</sender>
<sender id="jira" url="http://localhost:8080" type="post" successCode="200" batchSend="false">
<par id="reporter_token=凭据"/>
</sender>
</sender-config>
  1. 设置 系统配置告警策略,即 CAT 埋点达到告警阈值时发送的接收对象,例如 dingtalkmailjira,如下图:

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="utf-8"?>
<alert-policy>
<type id="Transaction">
<group id="default">
<level id="warning" send="dingtalk,mail" suspendMinute="5"/>
<level id="error" send="dingtalk,mail" suspendMinute="10"/>
</group>
</type>
<type id="Event">
<group id="default">
<level id="warning" send="dingtalk,mail" suspendMinute="5"/>
<level id="error" send="dingtalk,mail" suspendMinute="10"/>
</group>
</type>
<type id="Exception">
<group id="default">
<level id="warning" send="dingtalk,mail,jira" suspendMinute="5"/>
<level id="error" send="dingtalk,mail,jira" suspendMinute="10"/>
</group>
</type>
<type id="Business">
<group id="default">
<level id="error" send="dingtalk,mail" suspendMinute="5"/>
<level id="warning" send="dingtalk,mail" suspendMinute="10"/>
</group>
</type>
<type id="Heartbeat">
<group id="default">
<level id="warning" send="dingtalk,mail" suspendMinute="5"/>
<level id="error" send="dingtalk,mail" suspendMinute="10"/>
</group>
</type>
<type id="default">
<group id="default">
<level id="warning" send="dingtalk,mail" suspendMinute="5"/>
<level id="error" send="dingtalk,mail" suspendMinute="10"/>
</group>
</type>
</alert-policy>
  1. 设置 系统配置告警对象,即告警通知接收对象,如下图:

内容如下,笔者设置了 Exception 类型的告警:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<alert-config>
<receiver id="Transaction" enable="true">
</receiver>
<receiver id="Event" enable="true">
</receiver>
<receiver id="Exception" enable="true">
<email>您的邮箱</email>
<jira>reporterName=monitor&amp;issueType=故障&amp;components=架构&amp;fixVersionNames=待定</jira>
<dingtalk>您的钉钉机器人Token</dingtalk>
</receiver>
<receiver id="Heartbeat" enable="true">
</receiver>
<receiver id="Business" enable="true">
</receiver>
<receiver id="default" enable="true">
</receiver>
</alert-config>
  1. 接下来设置 Server异常告警配置,如下图:

配置界面如下,应用名称填写 default 表示监控所有服务,您可以指定自己的服务名称独立监控。异常名称建议填写 Total,表示监控所有异常,如果您需要监控某个异常,则填写该异常名称即可:

如果有些异常是不需要监控的,请在异常过滤列表添加。

  1. 配置完成,笔者设置了所有异常出现 5 次时发送告警,10 次时发送告警。达到这个阈值时,邮件会发送到 告警对象 设置的接收对象,Jira Software 会创建一个故障,钉钉会发送告警通知: