监控告警系统始终遵循:和业务系统整合,采集业务系统数据,然后上报,进行数据处理,然后在界面展示的过程。Cat作为点评开源的项目,起源于ebay的Cal,由吴其敏和尤勇开发。这个项目在2011年就开源了,从代码的提交记录看,但依然不妨碍它作为一个优秀的监控工具。下面的内容基于V3.0.0进行说明。
从整体的架构可以看到,首先会构建消息树的上下文,基于threadLocal实现,放入到MessageQueue,而其数据结构是ArrayBlockingQueue。然后进行发送到Server,然后会经过相关的分析器analyzer进行处理,然后呈现在界面上。这个过程其实是一个埋点,采集数据,获取数据后,进行处理,然后呈现到界面的过程。
1.首先在java的resource里面加上META-INF文件夹,然后新增app.properties文件,比如:app.name=springboot-cat
2.在业务中整合cat
public void testNormal() {
Transaction t = Cat.getProducer().newTransaction("URL", "MyPage");
try {
// do your business here
t.addData("k1", "v1");
t.addData("k2", "v2");
t.addData("k3", "v3");
Thread.sleep(30);
t.setStatus(Message.SUCCESS);
} catch (Exception e) {
t.setStatus(e);
} finally {
t.complete();
}
}
可以看到会首先创建一个新的Transaction,重要的方法是t.complete(),记录事件,此时会将信息放入到队列中,最终可以看到会走到
public void add(Message message) {
if (m_stack.isEmpty()) {
MessageTree tree = m_tree.copy();
//设置消息树
tree.setMessage(message);
//进行刷新操作
flush(tree, true);
} else {
//否则说明当前的事务为父级,添加事务child
Transaction parent = m_stack.peek();
addTransactionChild(message, parent);
}
}
调用刷新接口进行数据入队列到m_atomicQueue或者m_queue,但是m_atomicQueue会最终将数据入队到m_queue。
m_queue.offer(tree)
可以看到队列的数据结构为ArrayBlockingQueue。
入了队列,必然就需要进行出队列,因此可以猜想到会执行poll()操作:
MessageTree tree = queue.poll()
入了队列,经过分析处理器,会进入相关的处理器AbstractMessageAnalyzer中analyze方法。相关的分析器如下:
一条线是可以看到执行器执行的过程是在PeriodTask中执行的,因此可以从PeriodTask中找到一些线索:
可以看到其基于RealtimeConsumer会随其初始化方法进行启动。
另一条入队的路线可以看到是基于enqueue的
可以看到在cat的源码中,cat-home的代码启动后,可以看到messageReceiver.init()这个方法会执行,而其属于setup方法,那必然需要在启动的时候需要启动它,此时才可以执行task,然后完成分析器的业务分析相关操作。
为什么这么说:如果下载了frameworks和foundition代码的话,可以看到这个init方法的源头在frameworks的HttpServlet接口,我们知道DispatcherServlet就是继承了这个方法实现的扩展。而在这里我们可以找到execute(ModuleContext ctx)和setup(ModuleContext ctx)可想而知就会随着服务的启动而执行。
源头代码:
public abstract class AbstractContainerServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
try {
if (m_container == null) {
m_container = ContainerLoader.getDefaultContainer();
}
m_logger = m_container.getLogger();
initComponents(config);
} catch (Exception e) {
if (m_logger != null) {
m_logger.error("Servlet initializing failed. " + e, e);
} else {
System.out.println("Servlet initializing failed. " + e);
e.printStackTrace(System.out);
}
throw new ServletException("Servlet initializing failed. " + e, e);
}
}
}
这个方法是Servlet留给我们扩展的,这里可以看到会初始化一些组件,此时会调用((AbstractModule)module).setup(ctx)。而这个正是我们想要找的方法,此时会启动netty服务。可以看到里面添加了一个解码和一个编码到pipeline中。
在cat-home里面同时我们可以看到execute(ModuleContext ctx):
这个方法会启动报表重新加载task、task消费、启动告警、执行检查点操作
重新加载的task:
task消费:进行task处理
告警的相关渠道
短信、微信、邮件、短信
EventAnalyzer 事件分析器
ProblemAnalyzer 问题分析器
BusinessAnalyzer 业务分析器
TransactionAnalyzer 事务分析器
StateAnalyzer 状态分析器
StorageAnalyzer 存储分析器
TopAnalyzer top分析器
HeartbeatAnalyzer 心跳分析器
CrossAnalyzer 交叉分析器
DumpAnalyzer dump分析器
DependencyAnalyzer 依赖分析器
MatrixAnalyzer matrix分析器