欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-07 10:59:46
CAT(Central Application Tracking),是美团点评基于 Java 开发的一套开源的分布式实时监控系统。在SpringBoot项目中如何集成CAT的分布式调用链功能呢? ......

买买买结算系统

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

一年一度的双十一购物狂欢节就要到了,又到剁手党们开始表演的时刻了。当我们把种草很久的商品放入购物车以后,点击“结算”按钮时,就来到了买买买必不可少的结算页面了。让我们虚拟一个买买买结算系统,为结算页面提供商品、促销、库存等结算信息,就此系统展开如何在springboot项目中集成cat调用链。买买买结算系统包含以下4个项目:

  1. 结算ui:为前端页面提供结算的基础数据。
  2. 购物车api:获取用户购物车中有哪些商品。
  3. 商品api:获取商品详细信息
  4. 商品促销api:获取商品的促销信息
  5. 商品库存api:获取商品的库存信息

时序图如下:
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链

通过maven添加依赖

<dependency>
    <groupid>com.dianping.cat</groupid>
    <artifactid>cat-client</artifactid>
    <version>3.0.0</version>
</dependency>

配置client.xml

创建/data/appdatas/cat/目录,并创建client.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2001/xmlschema" xsi:nonamespaceschemalocation="config.xsd">
    <servers>
        <server ip="127.0.0.1" port="2280" http-port="8080" />
    </servers>
</config>

注意:把127.0.0.1替换成cat服务端的ip。

配置项目名称

买买买结算系统中一共有5个项目,每个项目都需要配置各自的项目名称。
首先,在每个项目中创建如下文件:
src/main/resources/meta-inf/app.properties
然后,在每个项目里添加如下内容:

  1. 结算ui:
    app.name=buy-buy-buy-checkout
  2. 购物车api:
    app.name=buy-buy-buy-cart
  3. 商品api:
    app.name=buy-buy-buy-product
  4. 商品促销api:
    app.name=buy-buy-buy-promotion
  5. 商品库存api:
    app.name=buy-buy-buy-store

注意:项目名称只能包含英文字母 (a-z, a-z)、数字 (0-9)、下划线 (_) 和中划线 (-)

准备埋点

在埋点之前,需要先写两个公共类,方便之后埋点时调用。

  1. 第一个类实现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. 第二个类中定义一些常量,在调用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";
}

开始埋点

使用cat进行分布式调用链监控,需要修改项目中的代码进行埋点:

  1. 在刚刚接收到请求时进行埋点。
  2. 在准备调用api时进行埋点。

那么在买买买结算系统中需要做哪些代码修改呢?看一下时序图的变化就明白了:
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链

第一个埋点,在刚刚接收到请求时,这里使用filter实现,代码如下:

public class catservletfilter implements filter {

    @override
    public void init(filterconfig filterconfig) throws servletexception {

    }

    @override
    public void dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain) throws ioexception, servletexception {

        httpservletrequest request = (httpservletrequest) servletrequest;

        catcontext catcontext = new catcontext();
        catcontext.addproperty(cat.context.root, request.getheader(cathttpconstants.cat_http_header_root_message_id));
        catcontext.addproperty(cat.context.parent, request.getheader(cathttpconstants.cat_http_header_parent_message_id));
        catcontext.addproperty(cat.context.child, request.getheader(cathttpconstants.cat_http_header_child_message_id));
        cat.logremotecallserver(catcontext);

        transaction t = cat.newtransaction(catconstants.type_url, request.getrequesturi());

        try {
            
            cat.logevent("service.method", request.getmethod(), message.success, request.getrequesturl().tostring());
            cat.logevent("service.client", request.getremotehost());

            filterchain.dofilter(servletrequest, servletresponse);

            t.setstatus(transaction.success);
        } catch (exception ex) {
            t.setstatus(ex);
            cat.logerror(ex);
            throw ex;
        } finally {
            t.complete();
        }
    }

    @override
    public void destroy() {

    }
}

filter已经写好了,接下来还需要把filter注册到springboot中:

@configuration
public class catconfiguration {
    @bean
    public filterregistrationbean catservletfilter() {
        filterregistrationbean registration = new filterregistrationbean();
        catservletfilter filter = new catservletfilter();
        registration.setfilter(filter);
        registration.addurlpatterns("/*");
        registration.setname("cat-servlet-filter");
        registration.setorder(1);
        return registration;
    }
}

第两个埋点,在调用api的httpclient工具类中统一增加代码,以get方式为例:

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 {
        context ctx = new catcontext();
        cat.logremotecallclient(ctx);
        httpget.setheader(cathttpconstants.cat_http_header_root_message_id, ctx.getproperty(cat.context.root));
        httpget.setheader(cathttpconstants.cat_http_header_parent_message_id, ctx.getproperty(cat.context.parent));
        httpget.setheader(cathttpconstants.cat_http_header_child_message_id, ctx.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;
}

结语

以上便是springboot集成cat调用链的整个实例了,可以灵活应用,更加优雅的集成到实际项目中。
另外,cat还有很多丰富的功能,可参见。