CAT简介

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

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

准备工作

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

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

首先,写一个类实现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 + '}';
}
}

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

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;
}
}

实现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();
}
}

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

定义一些常量,在调用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";
}

埋点时,在调用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;
}
}

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

异步请求实例

下面写一个异步请求的实例,通过多个商品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;
}
}

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

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

CAT中实现异步请求的调用链查看的更多相关文章

  1. Springmvc中 同步/异步请求参数的传递以及数据的返回

    转载:http://blog.csdn.net/qh_java/article/details/44802287 注意: 这里的返回就是返回到jsp页面 **** controller接收前台数据的方 ...

  2. springmvc中同步/异步请求参数的传递以及数据的返回

    注意: 这里的返回就是返回到jsp页面 **** controller接收前台数据的方式,以及将处理后的model 传向前台***** 1.前台传递数据的接受:传的属性名和javabean的属性相同 ...

  3. iOS中POST异步请求

    POST异步请求(代理) 1.遵循<NSURLConnectionDataDelegate> @interface ViewController ()<NSURLConnection ...

  4. Jquery中Ajax异步请求中的async参数的作用

    之前不知道这个参数的作用,上网找了前辈的博客,在此收录到自己的博客,希望能帮到更多的朋友: test.html <a href="javascript:void(0)" on ...

  5. for循环中嵌套异步请求问题

    for循环中嵌套了异步请求会导致顺序错乱,用递归代替for循环,可以保证正常执行顺序:

  6. vue 中promise 异步请求数据

    export function getTypes(type) { return listDictItems({ code: type }).then((res) => { if (res.cod ...

  7. 在Mvc中进行异步请求是出现(没有为该对象定义无参数的构造函数)

    解决办法就是给相应的类添加无参数的构造函数:

  8. 五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链

    买买买结算系统 一年一度的双十一购物狂欢节就要到了,又到剁手党们开始表演的时刻了.当我们把种草很久的商品放入购物车以后,点击"结算"按钮时,就来到了买买买必不可少的结算页面了.让我 ...

  9. 异步请求中jetty处理ServletRequestListener的坑

    标题起得比较诡异,其实并不是坑,而是jetty似乎压根就没做对异步request的ServletRequestListener的特殊处理,如果文中有错误欢迎提出,可能自己有所疏漏了. 之前遇到了一个b ...

随机推荐

  1. 在编译内核的最后阶段出现sdhci_esdhc_imx_pdata未定义的错误

    遇到下面这种错误 在网上查找资料后,发现一篇好文,提出了良好的找错误的策略: (1)利用grep命令查看该变量在何处使用: (2)查看相应的头文件是否在Kconfig中被定义且在make menuco ...

  2. Android JSBridge原理与实现

    在Android中,JSBridge已经不是什么新鲜的事物了,各家的实现方式也略有差异.大多数人都知道WebView存在一个漏洞,详细信息见你不知道的 Android WebView 使用漏洞,虽然该 ...

  3. c# Queue 类

  4. 日志管理与ftp。samba,nfs

    1.描述rsyslog日志服务,并提供带web展示的日志服务器 rsyslog日志服务简介 ​ 日志的概念好理解,日志作用可用于排障和追溯审计的等 ​ 1.rsyslog是一个C/S架构的服务,可监听 ...

  5. IP positioning check position

    1.如何找到网上散布不法言论的人的地理位置 比方像微博发布的时候都会自动添加主机网络地址,需要对头文件进行分析 找到IP地址 然后进行反查IP地址的位置 , 如果是可以与要查的终端可以进行通信 ,可以 ...

  6. [ike][ipsec] child sa rekey机制的细节分析

    子标题:ipsec rekey是否会导致丢包 author: classic_tong 前言 什么叫rekey. rekey是指ipsec的通信两端定期更换加密信道秘钥的机制. 为了安全性考虑,随着秘 ...

  7. ipsec][strongswan] ipsec SA创建失败后的错误处理分析

    〇 ike协商的过程最终是为了SA的建立, SA的建立后, 在底层中管理过程,也是相对比较复杂的. 这里边也经常会出现失败的情况. 我们以strongswan为例, 在strongswan的底层SA管 ...

  8. oracle更改数据库字符集

    shutdown immediate; startup mount; alter system enable restricted session; alter system set job_queu ...

  9. React系列,初识

    学习react对于新手来说,还没有学react往往就会被webpack,npm等搞的晕头转向,所以我们今天就从最简单的方式入手 <script src="react.js"& ...

  10. Java精通并发-死锁检测与相关工具详解

    关于死锁其实在之前https://www.cnblogs.com/webor2006/p/10659938.html的jvm学习中已经详细举过例子了,不过这里再来复习一下,另外是从并发这个专题领域的角 ...