深入详解美团点评CAT跨语言服务监控(五)配置与数据库操作

时间:2022-09-25 23:50:28

CAT配置

在CAT中,有非常多的配置去指导监控的行为,每个配置都有相应的配置管理类来管理,都有一个配置名, 配置在数据库或者配置文件中都是以xml格式存储,在运行时会被解析到具体实体类存储。我们选取一个配置的初始化代码来分析:

public class ServerFilterConfigManager implements Initializable {
@Inject
protected ConfigDao m_configDao; private volatile ServerFilterConfig m_config; private static final String CONFIG_NAME = "serverFilter"; @Override
public void initialize() throws InitializationException {
try {
Config config = m_configDao.findByName(CONFIG_NAME, ConfigEntity.READSET_FULL);
String content = config.getContent(); m_configId = config.getId();
m_modifyTime = config.getModifyDate().getTime();
m_config = DefaultSaxParser.parse(content);
} catch (DalNotFoundException e) {
try {
String content = m_fetcher.getConfigContent(CONFIG_NAME);
Config config = m_configDao.createLocal(); config.setName(CONFIG_NAME);
config.setContent(content);
m_configDao.insert(config);
m_configId = config.getId();
m_config = DefaultSaxParser.parse(content);
} catch (Exception ex) {
Cat.logError(ex);
}
} catch (Exception e) {
Cat.logError(e);
}
if (m_config == null) {
m_config = new ServerFilterConfig();
}
Threads.forGroup("cat").start(new ConfigReloadTask());
}
}

以上代码是serverFilter配置的初始化逻辑,该配置的管理类是ServerFilterConfigManager,可以看到他实现了Initializable接口,所以,在ServerFilterConfigManager被plexus容器实例化之后,就会调用initialize()做一些初始化的工作,咱们看看他的初始化逻辑。

1、他首先读取cat数据库的config表,如果根据配置名 CONFIG_NAME 找到相关的配置信息。

2、如果 config 表中存在配置信息,则通过 DefaultSaxParser.parse(content) 方法解析xml配置信息,并将解析后的配置信息写入实体对象ServerFilterConfig m_config,我们的xml配置文件必须遵守CAT的解析规则,他们才会被正确的解析成对应的XxxConfig对象,具体配置规则大家在有需要的时候一步步摸索。

3、如果 config 表中不存在配置信息,就会去读取默认 xml 文件, 解析后写入到数据库和实体对象,下次再初始化的时候就是直接从数据库读取了,xml一般存在于cat-core/src/main/resources/config/ 和 cat-home/src/main/resources/config/ 两个目录。

4、其中有两个配置 serverFilter 和 aggreationConfig, 开启了检查更新线程,线程每隔1分钟检查配置是否更新,有更新就重新加载配置。

5、server.xml 配置文件的目录是由环境变量 CAT_HOME指定的,由CatHomeModule在setup安装的时候初始化。

我们来列一列cat有哪些配置

深入详解美团点评CAT跨语言服务监控(五)配置与数据库操作

代码自动生成

上一节 ServerFilterConfigManager 类代码中的配置实体ServerFilterConfig的定义为 public class ServerFilterConfig extends BaseEntity<ServerFilterConfig>,所有的实体类都继承自BaseEntity<T>,这些实体类代码不是自己写的,而是通过插件生成的,插件在cat-home/pom.xml,cat-core/pom.xml,cat-consumer/pom.xml 中都会有定义,用以添加需要的实体,包括后面数据库的操作相关的实体,也是通过类似方式生成,这有点类似mybatis的数据库表对象生成器generator,我们来看看cat-core中的一个插件的定义:

<plugins>
<plugin>
<groupId>org.unidal.maven.plugins</groupId>
<artifactId>codegen-maven-plugin</artifactId>
<executions>
<execution>
<id>generate data model</id>
<phase>generate-sources</phase>
<goals>
<goal>dal-model</goal>
</goals>
<configuration>
<manifest>${basedir}/src/main/resources/META-INF/dal/model/server-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/command-format-manifest.xml,
...
${basedir}/src/main/resources/META-INF/dal/model/server-filter-config-manifest.xml,
</manifest>
</configuration>
</execution>
<execution>
<id>generate dal jdbc model</id>
<phase>generate-sources</phase>
<goals>
<goal>dal-jdbc</goal>
</goals>
<configuration>
<manifest>${basedir}/src/main/resources/META-INF/dal/jdbc/report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/jdbc/config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/jdbc/app-manifest.xml, <![CDATA[,
${basedir}/src/main/resources/META-INF/dal/jdbc/report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/jdbc/config-manifest.xml,
,]]></manifest>
</configuration>
</execution>
</executions>
</plugin>
<plugins>

插件在pom.xml中定义后,会在Maven Projects功能中展现出来,如图5:

深入详解美团点评CAT跨语言服务监控(五)配置与数据库操作

插件会根据xml中的描述,生成相应的类,比如 ServiceFilterConfig实体类的描述文档为: ${basedir}/src/main/resources/META-INF/dal/model/server-filter-config-manifest.xml,这个文档是个父文档,它将引入文档server-filter-config-codegen.xml和server-filter-config-model.xml,这两个文档有对将要生成的类的成员变量、成员函数的描述。

在下一章节的消息分析器中,和报表相关的非常多的实体类 EventReport、EventType、EventName、TransactionReport、TransactionType、TransactionName、Machine等等,都是由CAT代码生成插件根据配置 cat-sonsumer/src/main/resources/META-INFO/dal/model/*.xml 自动生成的,我们可以通过修改xml文件为我们的报表添加新的成员变量。

数据库操作

在上一节插件中,还有一个是与数据库操作相关类的生成有关的,比如上边config表相关数据库操作类的描述文档为${basedir}/src/main/resources/META-INF/dal/jdbc/config-manifest.xml,插件会根据xml文档生成Config、ConfigDao、ConfigEntity三个类放在下图目录中:
深入详解美团点评CAT跨语言服务监控(五)配置与数据库操作

那么config表有什么作用呢?这三个类分别有什么用途?在上一节我们多次用到这张表,例如我们初始化配置的时候,读取config表的记录,如果没有初始数据的话,配置管理类会从xml读取配置信息并插入config表了。

现在我们来讲一讲cat的数据库操作,先看看数据库操作的类图:
深入详解美团点评CAT跨语言服务监控(五)配置与数据库操作

对数据库表的操作位于Dao类中,比如Config表的操作类就是 ConfigDao,所有Dao继承自AbstractDao,每个Dao都会拥有数据库执行引擎(QueryEngine)的指针,用以执行所有的SQL语句,QueryEngine在Dao初始化函数initialize()中被实例化,

每个执行引擎QueryEngine都拥有实体信息管理(EntityInfoManager),以及查询解析器(QueryResolver),查询执行器(QueryExecutor),事务管理器(TransactionManager),

实体信息管理类(EntityInfoManager)管理每个表的Entity信息,Entity中描述对数据库的具体操作,Config表的实体对象就是ConfigEntity,他会在AbstractDao.initialize()函数中向EntityInfoManager注册。

另外还有一个关键的类,就是Config类,继承自DataObject,是对config表的所有字段的描述。

我们来看几个数据库操作的案例,下面源码,

public class ConfigDao extends AbstractDao {
public List<Config> findAllConfig(Readset<Config> readset) throws DalException {
Config proto = new Config(); List<Config> result = getQueryEngine().queryMultiple(
ConfigEntity.FIND_ALL_CONFIG,
proto,
readset); return result;
} public Config findByName(String name, Readset<Config> readset) throws DalException {
Config proto = new Config(); proto.setName(name); Config result = getQueryEngine().querySingle(
ConfigEntity.FIND_BY_NAME,
proto,
readset); return result;
} public int insert(Config proto) throws DalException {
return getQueryEngine().insertSingle(
ConfigEntity.INSERT,
proto);
} @Override
protected Class<?>[] getEntityClasses() {
return new Class<?>[] { ConfigEntity.class };
}
}

函数功能:

1、findAllConfig函数是获取所有的配置,返回的对象,是Config的List列表,调用查询引擎QueryEngine的queryMultiple 查询多条记录方法,传入的参数分别是实体操作方法ConfigEntity.FIND_ALL_CONFIG、查询条件数据proto、readset。

2、findByName函数则是按名字查询Config配置,逻辑跟上一个类似。

3、insert函数是插入一条config记录,调用查询引擎的insertSingle方法,参数分别是实体方法ConfigEntity.INSERT, 插入数据 proto。

4、getEntityClasses函数获取实体类

接下来我们以查询单条记录作为例子来看看查询引擎的实现逻辑,如下源码:

public class DefaultQueryEngine extends ContainerHolder implements QueryEngine {
public <T extends DataObject> T querySingle(QueryDef query, T proto, Readset<?> readset) throws DalException {
QueryContext ctx = this.createContext(query, proto);
ctx.setReadset(readset);
ctx.setFetchSize(1);
this.m_queryResolver.resolve(ctx);
List<T> results = this.m_queryExecutor.executeQuery(ctx);
if(results.isEmpty()) {
throw new DalNotFoundException("No record has been found for " + proto);
} else {
return (DataObject)results.get(0);
}
} protected <T extends DataObject> QueryContext createContext(QueryDef query, T proto) {
QueryContext ctx = new DefaultQueryContext();
EntityInfo enityInfo = this.m_entityManager.getEntityInfo(query.getEntityClass());
Map<String, Object> queryHints = this.getQueryHints(query, proto);
ctx.setQuery(query);
ctx.setProto(proto);
ctx.setEntityInfo(enityInfo);
ctx.setQueryHints(queryHints);
return ctx;
}
}

1、数据库引擎首先为该查询和对应条件数据proto创建查询上下文(QueryContext),

2、然后会设置readset,并设置查询条数为1条,

3、然后将上下文交给查询解析器(QueryResolver),解析器会根据查询上下文解析成对应的sql状态语,复制到上下文的 m_sqlStatement字段

4、最后将上下文交给执行器QueryExecutor去执行。并返回结果,如果没有找到结果,引擎会抛出DalNotFoundException异常。

数据库连接管理

数据库记录的更新与插入最终会由 MysqlWriteHandler 执行,而查询则由 MysqlReadHandler执行,两个Handler都会通过TransactionManager 的 getConnection 函数获取数据库的连接。
深入详解美团点评CAT跨语言服务监控(五)配置与数据库操作

数据库连接是由DataSource管理,DataSource是由数据源管理器(DataSourceManager)管理,TransactionManager 拥有DataSourceManager的指针,DataSourceManager 提供函数getDataSource(String name)获取DataSource对象;

getDataSource函数首先会从DataSourceManager 自身 m_dataSources 中寻找指定数据源,如果没有找到,再从数据源描述管理器(JdbcDataSourceDescriptorManager) 中获取数据库数据源描述信息(JdbcDataSourceDescriptor),然后利用描述信息去初始化连接池。

描述管理器也是先从自身 m_descriptors 中看是否存在指定描述信息(JdbcDataSourceDescriptor),如果没有,则会通过 DataSourceProviver 生成描述信息。

DataSourceProviver可以认为是初始数据源描述信息(JdbcDataSourceDescriptor)的提供者,JdbcDataSourceDescriptorManager初始化的时候,Plexus容器会基于xml文档实例化 DataSourceProviver,这些xml文档有 cat-home/....../META-INF/plexus/components-cat-home.xml,cat-consumer/....../META-INF/plexus/components-cat-consumer.xml, cat-core/....../META-INF/plexus/components-cat-core.xml, 文档中的 datasourceFile 就是数据源配置路径,例如下面xml文档:

<component>
<role>org.unidal.dal.jdbc.datasource.DataSourceProvider</role>
<implementation>org.unidal.dal.jdbc.datasource.DefaultDataSourceProvider</implementation>
<configuration>
<datasourceFile>/data/appdatas/cat/datasources.xml</datasourceFile>
</configuration>
</component>

JdbcDataSourceDescriptorManager是如何通过DataSourceProviver获取数据源描述信息(JdbcDataSourceDescriptor)?实际上是通过DataSourceProviver读取并解析datasourceFile文件,例如上面的/data/appdatas/cat/datasources.xml,然后将解析后的数据写入 DataSourceDef 对象,然后JdbcDataSourceDescriptorManager调用 buildDescriptor(DataSourceDef ds) 创建描述信息,下面是buildDescriptor的源码:

public class JdbcDataSourceDescriptorManager extends ContainerHolder implements Initializable {
private Map<String, JdbcDataSourceDescriptor> m_descriptors = new HashMap();
private List<DataSourceProvider> m_providers;
private String m_datasourceFile; protected JdbcDataSourceDescriptor buildDescriptor(DataSourceDef ds) {
JdbcDataSourceDescriptor d = new JdbcDataSourceDescriptor();
PropertiesDef properties = ds.getProperties();
String url = properties.getUrl();
String connectionProperties = properties.getConnectionProperties();
if(connectionProperties != null && connectionProperties.length() > 0) {
d.setProperty("url", url + "?" + connectionProperties);
} else {
d.setProperty("url", url);
} d.setId(ds.getId());
d.setType(ds.getType());
d.setProperty("driver", properties.getDriver());
d.setProperty("user", properties.getUser());
d.setProperty("password", properties.getPassword());
d.setProperty("login-timeout", Integer.valueOf(this.toTime(ds.getConnectionTimeout())));
d.setProperty("max-idle-time", Integer.valueOf(this.toTime(ds.getIdleTimeout())));
d.setProperty("min-pool-size", ds.getMinimumPoolSize());
d.setProperty("max-pool-size", ds.getMaximumPoolSize());
d.setProperty("checkout-timeout", ds.getCheckoutTimeoutInMillis());
return d;
}
}

数据源描述信息包含哪些内容呢,我们结合上面源码和下面的 datasources.xml配置来看,

每个data-source都有一个id; type默认jdbc; driver 默认为 com.mysql.jdbc.Driver、url、用户名、密码,登陆超时、连接池大小、超时检测等等。

<data-source id="cat">
<maximum-pool-size>3</maximum-pool-size>
<connection-timeout>1s</connection-timeout>
<idle-timeout>10m</idle-timeout>
<statement-cache-size>1000</statement-cache-size>
<properties>
<driver>com.mysql.jdbc.Driver</driver>
<url><![CDATA[jdbc:mysql://192.168.20.67:3306/cat]]></url>
<user>root</user>
<password>f63hiccVEv0mMXi</password>
<connectionProperties><![CDATA[useUnicode=true&autoReconnect=true]]></connectionProperties>
</properties>
</data-source>

深入详解美团点评CAT跨语言服务监控(五)配置与数据库操作的更多相关文章

  1. 深入详解美团点评CAT跨语言服务监控(一) CAT简介与部署

    前言: CAT是一个实时和接近全量的监控系统,它侧重于对Java应用的监控,除了与点评RPC组件融合的很好之外,他将会能与Spring.MyBatis.Dubbo 等框架以及Log4j 等结合,支持P ...

  2. 深入详解美团点评CAT跨语言服务监控(七)消息分析器与报表&lpar;二&rpar;

    CrossAnalyzer-调用链分析 在分布式环境中,应用是运行在独立的进程中的,有可能是不同的机器,或者不同的服务器进程.那么他们如果想要彼此联系在一起,形成一个调用链,在Cat中,CrossAn ...

  3. 深入详解美团点评CAT跨语言服务监控(六)消息分析器与报表&lpar;一&rpar;

    大众点评CAT微服务监控架构对于消息的具体处理,是由消息分析器完成的,消息分析器会轮训读取PeriodTask中队列的消息来处理,一共有12类消息分析器,处理后的结果就是生成各类报表. 消息分析器的构 ...

  4. 深入详解美团点评CAT跨语言服务监控(四)服务端消息分发

    这边首先介绍下大众点评CAT消息分发大概的架构如下: 图4 消息分发架构图 分析管理器的初始化 我们在第一章讲到服务器将接收到的消息交给解码器(MessageDecoder)去做解码最后交给具体的消费 ...

  5. 深入详解美团点评CAT跨语言服务监控(三)CAT客户端原理

    cat客户端部分核心类 message目录下面有消息相关的部分接口 internal目录包含主要的CAT客户端内部实现类: io目录包含建立服务端连接.重连.消息队列监听.上报等io实现类: spi目 ...

  6. 深入详解美团点评CAT跨语言服务监控(二) CAT服务端初始化

    Cat模块 Cat-client : cat客户端,编译后生成 cat-client-2.0.0.jar ,用户可以通过它来向cat-home上报统一格式的日志信息,可以集成到 mybatis.spr ...

  7. 深入详解美团点评CAT跨语言服务监控(九)CAT管理平台MVC框架

    在第2章我们讲到,服务器在初始化CatServlet 之后, 会初始化 MVC,MVC也是继承自AbstractContainerServlet , 同样也是一个 Servlet 容器,这是一个非常古 ...

  8. 深入详解美团点评CAT跨语言服务监控(八)报表持久化

    周期结束 我们从消息分发章节知道,RealtimeConsumer在初始化的时候,会启动一个线程,每隔1秒钟就去从判断是否需要开启或结束一个周期(Period),如下源码,如果 value < ...

  9. 美团点评CAT监控平台研究

    1. 美团点评CAT监控平台研究 1.1. 前言 此文根据我对官方文档阅读并记录整理所得,中间可能会穿插一些自己的思考和遇坑 1.2. 简介 CAT 是基于 Java 开发的实时应用监控平台,为美团点 ...

随机推荐

  1. chrome升级54以后,显示Adobe Flash Player 因过期而遭到阻止

    请直接下载 最新的Adobe flash player 离线安装包.经测试,在线安装不管用. 百度云地址: install_flash_player_23_ppapi.exe  密码:8c2i

  2. &lbrack;HDU 1520&rsqb; Anniversary party

    Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  3. js 实现tab选项卡

    最近一直在研究js  如果不及时复习的话前边学到的东西很快就会忘掉,所以把前段时间的一个简单的tab选项卡的思路写出来也算复习了一下吧, 第一步:先把布局写出来: <div id="d ...

  4. &lbrack;1&rsqb; 插件架构&lpar;PLUG-IN&rpar;

    网上的一种比较好对插件的定义是:插件(Plug-in,又称addin.add-in.addon或add-on,又译外挂)也称为扩展,是一种遵循一定规范的应用程序接口编写出来的程序,主要是用来扩展软件功 ...

  5. asp&period;net core 自定义认证方式--请求头认证

    asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...

  6. 如何实现Activiti的分支条件的自定义配置&lpar;转&rpar;

    如何实现Activiti的分支条件的自定义配置 博客分类: Activiti Java SaaS   一.Activiti的流程分支条件的局限 Activiti的流程分支条件目前是采用脚本判断方式,并 ...

  7. SQLite的文件锁、并发与pager---&lpar;SQLite学习手册&lpar;锁和并发控制&rpar;&rpar;

    一.概述: 在SQLite中,锁和并发控制机制都是由pager_module模块负责处理的,如ACID(Atomic, Consistent, Isolated, and Durable).在含有数据 ...

  8. ES6中Promise的入门&lpar;结合例子&rpar;

    一.Promise的前言 解决回调地狱 //以往回调方式 函数1(function(){ //代码执行...(ajax1) 函数2(function(){ //代码执行...(ajax2) 函数3(f ...

  9. spring security的简单应用

    本文只包涵spring security配置部分,不是一个完整项目,不过可以任意添加到一个web项目中,不需要对原来的程序做任何修改 部分内容来源于网络,如有雷同,毫无意外 1.xml配置文件 &lt ...

  10. jquery 对象的 height、innerHeight、outerHeight 的区别以及DOM 元素的 clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTop

    前言:jquery 对象的 height.innerHeight.outerHeight,还有 DOM 元素的 clientHeight.offsetHeight.scrollHeight.offse ...