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


    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技术干货。

  • 相关阅读:
    oracle linux 7.3 dtrace 安装
    ubuntn 内核升级到LINUX v4.11.8:
    ubuntu上安装systemtap
    ubuntu systemtap-sdt-dev
    ubuntu 内核调试符号 网址
    apt-get和apt-cache命令实例展示
    软件包管理 rpm yum apt-get dpkg
    让VIM支持Python2 by update-alternatives
    在Ubuntu中通过update-alternatives切换软件版本
    Ubuntu 11.04安装GCC 4.6.1
  • 原文地址:https://www.cnblogs.com/heihaozi/p/12061705.html
Copyright © 2020-2023  润新知