CAT中实现异步请求的调用链查看

举报
万猫学社 发表于 2021/05/29 12:01:38 2021/05/29
【摘要】 CAT简介 CAT(Central Application Tracking),是美团点评基于 Java 开发的一套开源的分布式实时监控系统。美团点评基础架构部希望在基础存储、高性能通信、大规模在线访问、服务治理、实时监控、容器化及集群智能调度等领域提供业界领先的、统一的解决方案,CAT 目前在美团点评的产品定位是应用层的统一监控组件,在中间件(RPC、数据库、...

CAT简介

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

准备工作

对于同步请求API,CAT服务端自然是可以看到的。同步请求API的实例可以参考之前的文章《五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链》。但对于异步请求API,因为不在同一线程中,在子线程中无法获取到父线程消息树,所以在CAT服务端是无法看到的对应请求。

首先,写一个类实现Cat.Context接口,用于存放消息树的上下文信息:

public class CatContext implements Cat.Context { private Map<String, String> properties = new HashMap<>(); @Override public void addProperty(String key, String value) { properties.put(key, value); } @Override public String getProperty(String key) { return properties.get(key); } @Override public String toString() { return "CatContext{" + "properties=" + properties + '}'; }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

我们可以先父线程消息树的上下文信息保存下来,然后在子线程使用。先写一个存放上下文信息的地方:

public class ContextWarehouse { private static ThreadLocal<CatContext> contextThreadLocal = new ThreadLocal(); public static void setContext(final CatContext context) { contextThreadLocal.set(context); } public static CatContext getContext() { //先从ContextWarehouse中获取上下文信息 CatContext context = contextThreadLocal.get(); if (context == null) { context = new CatContext(); Cat.logRemoteCallClient(context); } return context; }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

实现Callable接口,创建一个自定义的类,实现了在子线程中存放父线程的上下文信息的功能:

public class OneMoreCallable<V> implements Callable<V> { private CatContext catContext; private Callable<V> callable; public DdCallable(final Callable<V> callable) { this.callable = callable; this.catContext = new CatContext(); //获取父线程消息树的上下文信息 Cat.logRemoteCallClient(this.catContext); } @Override public V call() throws Exception { //保存父线程消息树的上下文信息到子线程 ContextWarehouse.setContext(this.catContext); return callable.call(); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

定义一些常量,在调用API时作为header中的key:

public class CatHttpConstants { public static final String CAT_HTTP_HEADER_CHILD_MESSAGE_ID = "DD-CAT-CHILD-MESSAGE-ID"; public static final String CAT_HTTP_HEADER_PARENT_MESSAGE_ID = "DD-CAT-PARENT-MESSAGE-ID"; public static final String CAT_HTTP_HEADER_ROOT_MESSAGE_ID = "DD-CAT-ROOT-MESSAGE-ID";
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

埋点时,在调用API的HttpClient工具类中统一增加代码,以GET方式为例:

public class HttpClientUtil { public static String doGet(String url) throws IOException { HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = null; CloseableHttpClient httpClient = HttpClientBuilder.create().build(); String content = null; Transaction t = Cat.newTransaction(CatConstants.TYPE_CALL, url); try { CatContext context = ContextWarehouse.getContext(); httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID, context.getProperty(Cat.Context.ROOT)); httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID, context.getProperty(Cat.Context.PARENT)); httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID, context.getProperty(Cat.Context.CHILD)); response = httpClient.execute(httpGet); if (response.getStatusLine().getStatusCode() == 200) { content = EntityUtils.toString(response.getEntity(), "UTF-8"); t.setStatus(Transaction.SUCCESS); } } catch (Exception e) { Cat.logError(e); t.setStatus(e); throw e; } finally { if (response != null) { response.close(); } if (httpClient != null) { httpClient.close(); } t.complete(); } return content; }
}

  
 
  • 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

异步请求实例

下面写一个异步请求的实例,通过多个商品ID异步获取对应的商品详细信息:

public class ProductService { /** * 声明一个大小固定为10的线程池 */ private static ExecutorService executor = Executors.newFixedThreadPool(10); /** * 通过商品ID列表异步获取对应的商品详细信息 * * @param productIds 商品ID列表 * @return 对应的商品详细信息 */ public List<String> findProductInfo(List<Long> productIds) { List<Future<String>> futures = new ArrayList<>(); for (Long productId : productIds) { futures.add(executor.submit(new DdCallable(() -> { try { //调用获取商品详细信息的API return HttpClientUtil.doGet("http://api.product/get?id=" + productId); } catch (Exception e) { return ""; } }))); } List<String> productInfos = new ArrayList<>(); for (Future<String> future : futures) { try { //异步获取对应商品详细信息 productInfos.add(future.get()); } catch (Exception e) { productInfos.add(""); } } return productInfos; }
}

  
 
  • 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

这样写以后,在CAT服务端的Transaction报表中就可以查看到异步请求了。

文章来源: blog.csdn.net,作者:万猫学社,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/heihaozi/article/details/103603360

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。