美团点评Cat业务实践

项目背景

CAT(Central Application Tracking),是基于 Java 开发的分布式实时监控系统。CAT在基础存储、高性能通信、大规模在线访问、服务治理、实时监控、容器化及集群智能调度等领域提供业界领先的、统一的解决方案。CAT 目前在美团的产品定位是应用层的统一监控组件,基本接入了美团所有核心应用,在中间件(RPC、数据库、缓存、MQ 等)框架中得到广泛应用,为各业务线提供系统的性能指标、健康状况、实时告警等。

项目地址:https://github.com/dianping/cat

优势
  • 实时处理:信息的价值会随时间锐减,尤其是事故处理过程中
  • 全量数据:全量采集指标数据,便于深度分析故障案例
  • 高可用:故障的还原与问题定位,需要高可用监控来支撑
  • 故障容忍:故障不影响业务正常运转、对业务透明
  • 高吞吐:海量监控数据的收集,需要高吞吐能力做保证
  • 可扩展:支持分布式、跨 IDC 部署,横向扩展的监控系统

监控模型

CAT主要支持以下四种监控模型:

  • Transaction 适合记录跨越系统边界的程序访问行为,比如远程调用,数据库调用,也适合执行时间较长的业务逻辑监控,Transaction用来记录一段代码的执行时间和次数

  • Event 用来记录一件事发生的次数,比如记录系统异常,它和transaction相比缺少了时间的统计,开销比transaction要小

  • Heartbeat 表示程序内定期产生的统计信息, 如CPU利用率, 内存利用率, 连接池状态, 系统负载等

  • Metric 用于记录业务指标、指标可能包含对一个指标记录次数、记录平均值、记录总和,业务指标最低统计粒度为1分钟

    消息树

    CAT监控系统将每次URL、Service的请求内部执行情况都封装为一个完整的消息树、消息树可能包括Transaction、Event、Heartbeat、Metric等信息。

    完整的消息树

在这里插入图片描述

功能模块
  • cat-client: 客户端,上报监控数据
  • cat-consumer: 服务端,收集监控数据进行统计分析,构建丰富的统计报表
  • cat-alarm: 实时告警,提供报表指标的监控告警
  • cat-hadoop: 数据存储,logview 存储至 Hdfs
  • cat-home: 管理端,报表展示、配置管理等

报表介绍

Transaction报表

监控一段代码运行情况:运行次数、QPS、错误次数、失败率、响应时间统计(平均影响时间、Tp分位值)等等

在这里插入图片描述

监控一段核心代码执行情况,通过 Transaction进行埋点。

public void flowService() {        
    service1();
    Transaction transaction = Cat.newTransaction("flowService", "Service3");
    try {
        service3();
        
        transaction.setStatus(Transaction.SUCCESS);
    } catch (Exception e) {
        transaction.setStatus(e); // catch 到异常,设置状态,代表此请求失败
        Cat.logError(e); // 将异常上报到cat上
        // 也可以选择向上抛出: throw e;
    } finally {
        transaction.complete();
    }
}
Event报表

监控一段代码运行次数:例如记录程序中一个事件记录了多少次,错误了多少次。Event报表的整体结构与Transaction报表几乎一样,只缺少响应时间的统计。

在这里插入图片描述

想记录在某个方法中一个条件分支中分支1中的函数调用了多少次,分支2中的函数调用了多少次,又失败了多少次
public void testEvent() {
    for (int i = 0; i < 100; i++) {
        Transaction t = Cat.newTransaction("Trans", "test");

        for (int j = 0; j < 6000; j++) {
            if (j % 3 == 0) {
                func1();
                Cat.logEvent("Func", "Func1");
            } else {
                boolean result = func2();
                Event e = Cat.newEvent("Func", "Func2");

                if (result) {
                    e.setSuccessStatus();
                } else {
                    e.setStatus("False");
                }
                e.complete();

            }
        }
        t.setStatus(Transaction.SUCCESS);
        t.complete();
    }
}
private void func1() {

}
private boolean func2() {
    Random random = new Random();
    int res = random.nextInt(100);
    if (res % 2 == 0)
        return false;
    return true;
}
Problem报表

Problem记录整个项目在运行过程中出现的问题,包括一些异常、错误、访问较长的行为。Problem报表是由logview存在的特征整合而成,方便用户定位问题。 来源:

  • 业务代码显示调用Cat.logError(e) API进行埋点,具体埋点说明可查看埋点文档。
  • 与LOG框架集成,会捕获log日志中有异常堆栈的exception日志。
  • long-url,表示Transaction打点URL的慢请求
  • long-sql,表示Transaction打点SQL的慢请求
  • long-service,表示Transaction打点Service或者PigeonService的慢请求
  • long-call,表示Transaction打点Call或者PigeonCall的慢请求
  • long-cache,表示Transaction打点Cache.开头的慢请求

自定义阈值 对于较长耗时,也认为是problem错误,cat可以选择不同的耗时阈值。例如:接入cat-filter后,此处可以选择long-url不同的阈值,筛选不同的时长URL

在这里插入图片描述

Heartbeat报表

Heartbeat报表是CAT客户端,以一分钟为周期,定期向服务端汇报当前运行时候的一些状态

在这里插入图片描述

实践如上图通过自定义收集器实现线程池监控

@Component
public class CatFlowThreadCollector  extends AbstractCollector {

    /**
     * 处理大数据推荐普通数据线程池
     * */
    @Autowired
    @Qualifier("threadPoolExecutor")
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public String getId() {
        return "flowExecutor_pool_monitor";
    }

    @PostConstruct
    public void init(){
        StatusExtensionRegister instance = StatusExtensionRegister.getInstance();
        instance.register(this);
    }

    @Override
    public Map<String, String> getProperties() {
        Map<String,String> map = new LinkedHashMap<>();
        //主线程池指标
        map.put("flowExecutor.core-pool-size", String.valueOf(threadPoolExecutor.getCorePoolSize()));
        map.put("flowExecutor.max-pool-size", String.valueOf(threadPoolExecutor.getMaximumPoolSize()));
        map.put("flowExecutor.current-pool-size", String.valueOf(threadPoolExecutor.getPoolSize()));
        map.put("flowExecutor.active-count", String.valueOf(threadPoolExecutor.getActiveCount()));
        map.put("flowExecutor.queue-size", String.valueOf(threadPoolExecutor.getQueue().size()));
        map.put("flowExecutor.completed-task-count", String.valueOf(threadPoolExecutor.getCompletedTaskCount()));
        //线程池曾经创建过的最大线程数量
        map.put("flowExecutor.largest-pool-size", String.valueOf(threadPoolExecutor.getLargestPoolSize()));
        return map;
    }
}

Quickstart

Transaction t = Cat.newTransaction("URL", "pageName");

try {
  	//记录事件
    Cat.logEvent("URL.Server", "serverIp", Event.SUCCESS, "ip=${serverIp}");
    //记录业务指标的总和或平均值
    //如果你在同一秒调用 count 三次(相同的 name),我们会累加他们的值,并且一次性上报给服务端。
    //在 duration 的情况下,用平均值来取代累加值。
    Cat.logMetricForCount("metric.key");
    Cat.logMetricForDuration("metric.key", 5);

    yourBusiness();
    t.setStatus(Transaction.SUCCESS);
} catch (Exception e) {
    t.setStatus(e);
  //
    Cat.logError(e);
} finally {
    t.complete();
}

主流框架集成

spring-boot
@Configuration
public class CatFilterConfigure {
   @Bean
   public FilterRegistrationBean catFilter() {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    CatFilter filter = new CatFilter();
    registration.setFilter(filter);
    registration.addUrlPatterns("/*");
    registration.setName("cat-filter");
    registration.setOrder(1);
    return registration;
  }
}
spring-aop
@Retention(RUNTIME)
@Target(ElementType.METHOD)
public @interface CatAnnotation {
}

@Aspect
public class CatAopService {
	@Around(value = "@annotation(CatAnnotation)")
	public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
		MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
		Method method = joinPointObject.getMethod();
		Transaction t = Cat.newTransaction("method", method.getName());
		try {
			Object res = pjp.proceed();
			t.setSuccessStatus();
			return res;
		} catch (Throwable e) {
			t.setStatus(e);
			Cat.logError(e);
			throw e;
		} finally {
			t.complete();
		}
	}
}

我们通过spring-boot方式+aop 方式记录了 url 请求耗时及业务service方法耗时 方便做优化

业务url接口耗时

在这里插入图片描述

业务service方法接口耗时

在这里插入图片描述

其他如log4j2,logback、mybatis集成方案参考以下地址

https://github.com/dianping/cat/tree/master/integration

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值