结合本周分享的《comsat 监控使用》,和以前听过的《comsat插件开发》,总结一下。
一.comsat 是什么?
comsat 是基于FLEX 和 J2EE开发的监控系统,能够承接系统监控和应用监控的需求,对于系统监控,主要监控内存使用,JVM状态,cpu使用率等,系统监控侵入性较小,而对于应用监控,可以监控你自定义的一些key-value值,根据log打点来监控线程启动状况,通过覆盖log4j的expetionApender来监控异常等,以及通过AOP的方式,监控一些数据库连接异常等。同样,也可以很方便的开发自己的插件。
二.特性。
目前实现:
1.添加新的应用,需要comsat服务端配置,客户端web.xml配置监听器,并在本地classpath下配置comsat.xml(配置对应到comsat服务端的应用名称、协议和开放的端口名称)。
2.提供了基础的key-value监控,runtime监控,客户端需要加入plugin、collector等依赖等才能实现。
3.key-value监控需要依赖于日志的<CC>开头的纪录进行获取。
4.可以发送手机报警和旺旺等报警,并进行报警规则的设定。
----
不足
1.发送的exception信息较多,但是可以显示的统计信息不多。
2.客户端启动任务监听,启动task,对客户端性能有影响。
三.目前我们主要应用场景
1.监控系统运行情况
2.通过AOP方式监控数据库运行情况,在数据库断开时,不进行重试。
四.结合日志分析运行情况
启动客户端时,日志如下:
1.启动本地配置,本地没有comsat配置则启动服务端配置,采用w3c解析xml如下:
URL url = PluginConfigurer.class.getResource("/comsat.xml"); if (url == null) { url = PluginConfigurer.class.getResource("/META-INF/comsat-default.xml"); } logger.info("Bootstrap " + url); Document doc = DomHelper.build(url); Element root = doc.getDocumentElement(); // init global setting application = getSingleSubTextByName(root, "application", "unknown"); String cfg = getSingleSubTextByName(root, "global-config", "true"); globalConfig = Boolean.parseBoolean(cfg); serverUrl = getSingleSubTextByName(root, "server-url", "tcp://localhost:5843");
这部分是采用了static的方法,是最先被初始化的
2. web.xml中配置的监听的servlet 容器的ComsatListener 启动
public void contextInitialized(ServletContextEvent sce) { try { this.launcher = new Launcher(); this.launcher.startup(); } catch (Exception e) { logger.error("Fail to startup comsat collector!", e); } }
public class Launcher { private static final Log logger = LogFactory.getLog(Launcher.class); private static final PluginConfigurer configurer = (PluginConfigurer)SimpleBeanFactory.findService(PluginConfigurer.class); private static final SimpleScheduler scheduler = (SimpleScheduler)SimpleBeanFactory.findService(SimpleScheduler.class); private static final PluginLauncher plugins = (PluginLauncher)SimpleBeanFactory.findService(PluginLauncher.class); public void startup() { logger.info("Ready to launch monitor's collector... "); scheduler.startup(); startHeartBeat(); startMsgSender(); if (!(configurer.findGlobalConfig())) startPlugins(); }
可以看到,先后启动了心跳的task,心跳一般是60s发送一次,和kv的task 一样,隔一段时间发送一次当前时间和应用给comsat;然后启动message发送task,这里把消息进行过滤并发往相应的ip端口?(为什么配置是tcp?)-tcp 只是标识,是一个标准的写法,其实没有用到和协议有关的东西,建立的是nio的socket连接
最后是启动你自己扩展的plugin。
3. task启动完成后,在MessageSender这里做了如下事情,启动socket的连接,建立连接通道,并在失败后重试。session的作用 - 保持了当前会话的状态,即本次连接的状态,由于没有建立在物理资源消耗上,没有做session的释放。
public void connect() throws IOException { channel = ChannelBuilder.newSocketChannel(ip, port); session = new Session(this, channel, protocolChain, handlerChain); channel.register(selector, SelectionKey.OP_CONNECT, session); selector.select(DEFAULT_SELECT_TIMEOUT); super.read(session); }
4.在如上所述的建立的通道里会启动消息发送的方法,发送的消息采用了特有的标识<CC>。
五.项目应用,aop方式监控数据库异常。
<aop:aspect ref="dataAccessAspect"> <!-- 配置pointcut,即切入点,对哪些类的哪些方法起到AOP的作用 --> <aop:pointcut id="chargeDao" expression="execution(* com.alibaba.itbu.billing.biz.charge.dao.*.*(..))" /> <aop:pointcut id="collectDao" </aop:aspect>
public class DataAccessAspect { public Object monitorDataAccess(ProceedingJoinPoint joinPoint) throws Throwable{ try{ return joinPoint.proceed(joinPoint.getArgs()); }catch(DataAccessException err){ try { DataAccessFailMonitor task = new DataAccessFailMonitor(); List<KVItem> items = task.getKVItems(err); Date collectTime = new Date(); for (KVItem item : items) { item.setCollectTime(collectTime); task.send(item); } } catch (Exception e) { } throw err; }catch(Exception err){ throw err; } } }
这样可以实现在数据库发生DataAceess异常时,保证能够收到异常的报警。
六.插件开发
其实上面的应用部分已经基本展示了插件开发的过程,只是没有在数据格式上扩展,数据格式扩展可以通过继承monitor_item去做,并且可以扩展DAO,将你要监控的数据纪录到监控端。总结起来就是四步
1.扩展数据格式,继承monitorItem
2.定义信息收集器
3.定义发送task,
4.可以初始化的监控端(如果你需要)继承MonitorPersistor