CAT中实现异步请求的调用链查看
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
- 点赞
- 收藏
- 关注作者
评论(0)