DUBBO监控,设置接口调用数据的上报周期
DUBBO监控,设置接口调用数据的上报周期
dubbo是目前比较好用的,用来实现soa架构的一个工具,dubbo的用法和好处,我们这里略过,今天我们来讨论跟监控有关的话题。
大家大知道,在确保系统的稳定道路上,系统监控是必不可少的,只有实时监控系统中接口的调用情况,并定期汇总统计数据,才能知道系统是否到了瓶颈,以及是否有接口异常调用情况。
dubbo已有的监控方案
dubbo中自带了dubbo-monitor模块,其作用简单来说就是:
根据配置判断是否启用
MonitorFilter
过滤器
当dubbo的xml配置文件中配置了<dubbo:monitor xxx/>
,比如:<dubbo:monitor protocol="registry" />
或<dubbo:monitor protocol="dubbo" address="dubbo://127.0.0.1:30004/MonitorService" />
等等
根据protocol配置,判断获取
MonitorService
接口方式以及获取接口地址
如果是registry
根据<dubbo:registry xxx />
配置获取,如果是dubbo
直接使用address属性配置的地址
根据protocol配置,判断使用哪个
MonitorFactory
如果是registry
,则根据最后获取到的具体通信协议来决定;
如果是dubbo
,使用默认工厂类:DubboMonitorFactroy。见dubbo默认配置文件:
META-INF/dubbo/internal/com.alibaba.dubbo.monitor.MonitorFactory
dubbo=com.alibaba.dubbo.monitor.dubbo.DubboMonitorFactroy
这里我们可以自定义协议,比如myDubbo
,然后在项目中创建一个文件:
META-INF/dubbo/com.alibaba.dubbo.monitor.MonitorFactory
myDubbo=org.rembau.dubboTest.MyDubboMonitorFactory
这时项目启动时,如果发现协议为myDubbo,会使用MyDubboMonitorFactory
执行相关操作。
问题:这里暴露了监控配置的一个问题,就是我们不能为dubbo协议重新定义一个MonitorFactory
,所以连带的不能重新实现Monitor
。
使用
MonitorFilter
过滤器处理每一个接口调用
如果我们用的dubbo协议来连接MonitorService
服务,则是使用DubboMonitor
实例来处理接口调用数据,该类实现了对调用数据的简单汇总,并每60秒调用MonitorService
服务的collect方法,把数据发送出来。
使用dubbo-monitor-simple接收数据
dubbo-monitor-simple是dubbo提供的简单监控中心,可以用来显示接口暴露,注册情况,也可以看接口的调用明细,调用时间等。
还有其他一些比较好的工具比如Dubbo-Monitor等
针对已有方案的改进
写到这里才是本文的重点,我们绝大部分使用者都是使用dubbo协议进行通信,所以也就是使用DubboMonitor
发送数据,这已经完全够用了。但是DubboMonitor
是每分钟上报一次,并且每个应用中,与之有关的所有接口都会产生一条数据,生产环境中,数据量还是挺大的。如果上报的时间间隔可以设置为10分钟或者30分钟,数据量也会相应减少10倍、30倍,如果我们自己汇聚还需要分布式服务对数据的一致性处理,会把事情变复杂。
查看
DubboMonitor
源码:
DubboMonitor
的构造方法:
this.monitorInterval = (long)monitorInvoker.getUrl().getPositiveParameter("interval", '60000');
this.sendFuture = this.scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
public void run() {
try {
DubboMonitor.this.send();
} catch (Throwable var2) {
DubboMonitor.logger.error("Unexpected error occur at send statistic, cause: " + var2.getMessage(), var2);
}
}
}, this.monitorInterval, this.monitorInterval, TimeUnit.MILLISECONDS);
其中.getPositiveParameter("interval", '60000')
方法大概意思是,在URL对象实例中找interval参数的值。那URL的参数会从什么地方获取呢?
MonitorConfig
的属性、MonitorConfig
中Map<String, String> parameters
属性的key-value
最终获取的URL是根据MonitorConfig
得来的,查看AbstractInterfaceConfig
代码:
protected URL loadMonitor(URL registryURL) {
if (monitor == null) {
String monitorAddress = ConfigUtils.getProperty("dubbo.monitor.address");
String monitorProtocol = ConfigUtils.getProperty("dubbo.monitor.protocol");
if (monitorAddress != null && monitorAddress.length() > 0
|| monitorProtocol != null && monitorProtocol.length() > 0) {
monitor = new MonitorConfig();
} else {
return null;
}
}
appendProperties(monitor);
Map<String, String> map = new HashMap<String, String>();
map.put(Constants.INTERFACE_KEY, MonitorService.class.getName());
map.put("dubbo", Version.getVersion());
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
}
appendParameters(map, monitor);
String address = monitor.getAddress();
String sysaddress = System.getProperty("dubbo.monitor.address");
if (sysaddress != null && sysaddress.length() > 0) {
address = sysaddress;
}
if (ConfigUtils.isNotEmpty(address)) {
if (! map.containsKey(Constants.PROTOCOL_KEY)) {
if (ExtensionLoader.getExtensionLoader(MonitorFactory.class).hasExtension("logstat")) {
map.put(Constants.PROTOCOL_KEY, "logstat");
} else {
map.put(Constants.PROTOCOL_KEY, "dubbo");
}
}
return UrlUtils.parseURL(address, map);
} else if (Constants.REGISTRY_PROTOCOL.equals(monitor.getProtocol()) && registryURL != null) {
return registryURL.setProtocol("dubbo").addParameter(Constants.PROTOCOL_KEY, "registry").addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map));
}
return null;
}
方案1 使用javassist动态重写
MonitorConfig
class
在应用启动时,使用javassist给MonitorConfig
添加interval字段,并设置默认值,DubboMonitor
初始化时会获取到该字段的值,并使用这个值当作发送数据的周期。
如果应用使用了spring框架,则下面代码有关在加载spring配置文件之前执行。如果应用是web应用则处理起来更麻烦,需要重写org.springframework.web.context.ContextLoaderListener
代码如下:
ClassPool pool = ClassPool.getDefault();
try {
CtClass cc = pool.get("com.alibaba.dubbo.config.MonitorConfig");
// 增加属性,这里仅仅是增加属性字段
CtField ctField = new CtField(CtClass.intType, "interval", cc);
ctField.setModifiers(Modifier.PUBLIC);
cc.addField(ctField, "10000");//设置10秒周期
CtMethod ctMethod = new CtMethod(CtClass.intType, "getInterval", null, cc);
ctMethod.setBody("return interval;");
ctMethod.setModifiers(Modifier.PUBLIC);
cc.addMethod(ctMethod);
cc.toClass();
} catch (NotFoundException | CannotCompileException e) {
logger.error("", e);
}
方案2 使用
<dubbo:registry xxx />
配置
分析源码,可以知道,如果配置<dubbo:registry interval="10000" xxx />
,dubbo解析文件时,会把interval="10000"当作一个key-value存入MonitorConfig
中Map<String, String> parameters
DubboBeanDefinitionParser
中parse方法(摘选)
NamedNodeMap attributes = element.getAttributes();
int len = attributes.getLength();
for (int i = 0; i < len; i++) {
Node node = attributes.item(i);
String name = node.getLocalName();
if (! props.contains(name)) {
if (parameters == null) {
parameters = new ManagedMap();
}
String value = node.getNodeValue();
parameters.put(name, new TypedStringValue(value, String.class));
}
}
if (parameters != null) {
beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
}
但是有个问题,如果我给<dubbo:registry xxx>
加上interval属性,应用启动时会报错。我们知道原因是dubbo的xsd文件没有放开这个限制,我们只要修改dubbo.xsd文件就可以了,但是dubbo.xsd是在jar包里,所以我们改不了。
我们可以自己写xsd配置,重命名为dubbo-youyue.xsd:
文件头改为:
<xsd:schema xmlns="http://code.alibabatech.com/schema/youyue/dubbo"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
targetNamespace="http://code.alibabatech.com/schema/youyue/dubbo">
monitorType节点添加:
<xsd:attribute name="interval" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[ The monitor interval. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
然后把dubbo.xml中关联的dubo.xsd改成我们自己写的xsd,如:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
改成
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:dubbo="http://code.alibabatech.com/schema/youyue/dubbo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://code.alibabatech.com/schema/youyue/dubbo
http://code.alibabatech.com/schema/youyue/dubbo/dubbo.xsd">
添加 spring.schemas 文件,用来使用本地文件取代远程文件
http://code.alibabatech.com/schema/youyue/dubbo/dubbo.xsd=META-INF/dubbo-youyue.xsd
添加 spring.handlers 文件,用来标记分析dubbo.xml中<dubbo:xx xx>
节点的分析处理类
至此,配置好<dubbo:registry interval="10000" xxx />
启动应用,可以看到上报周期由60秒变成了10秒。
DUBBO监控,设置接口调用数据的上报周期的更多相关文章
- Dubbo -- 关于 api接口调用不使用强依赖
首先,我们都知道 Dubbo 调用api 需要提供暴露 接口, 消费端才通过 ZK 可以调用 通常我们都会使用 提供 api jar包 的方式 使用 这样既方便又快捷 简单 只需要在spr ...
- webService 客户端接口调用【java】
最近实际项目中使用到了WebService,简单总结下使用方式: 1.拿到接口:http://*******:8080/osms/services/OrderWebService?wsdl 我们可以将 ...
- EasyNVR流媒体服务器网页兼容调试:ie浏览器下的接口调用成功但页面无法显示实时的数据
许多问题很难在开发的过程中就想的面面俱到,都是在实际应用.调试的过程中一一的优化的.由于easynvr的受众越来越多,因此也出现了好多在开发之初并没有留意的一些细节.我这次发现的问题就是给客户远程解决 ...
- 一行代码搞定Dubbo接口调用
本文来自网易云社区 作者:吕彦峰 在工作中我们经常遇到关于接口测试的问题,无论是对于QA同学还是开发同学都会有远程接口调用的需求.针对这种问题我研发了一个工具包,专门用于远程Dubbo调用,下面就让我 ...
- 借助Anyproxy实时监控接口调用次数和流量
监控接口调用次数,是为了测试客户端可能会异常频繁的调用服务端接口,出现性能问题. AnyProxy是一个开放式的HTTP代理服务器. github: https://github.com/alibab ...
- java接口对接——别人调用我们接口获取数据
java接口对接——别人调用我们接口获取数据,我们需要在我们系统中开发几个接口,给对方接口规范文档,包括访问我们的接口地址,以及入参名称和格式,还有我们的返回的状态的情况, 接口代码: package ...
- page分页问题,根据页码获取对应页面的数据,接口调用
添加一个log.js文件,进行接口调用. import axios from '@/libs/api.request' const MODULE_URL = '/log'; export const ...
- SAP调用RestfulApi接口POST数据到外部系统
作者:明光烁亮 出处:http://www.cnblogs.com/hezhongxun/ 微信号:HEme922 欢迎加好友一起交流SAP! 视频资料共享. 本文版权归作者和博客园共有,欢迎转载,但 ...
- Vue单页面中进行业务数据的上报
为什么要在标题里加上一个业务数据的上报呢,因为在咱们前端项目中,可上报的数据维度太多,比如还有性能数据.页面错误数据.console捕获等.这里我们只讲解业务数据的埋点. 业务数据的上报主要分为: 各 ...
随机推荐
- 【cocos2d-x + Lua(1) 绑定Lua并使用tolua++】
为什么要使用Lua进行游戏开发?转载请注明出处http://www.cnblogs.com/zisou/p/cocos2dx-lua1.html 上面一个问题我觉得在我们使用Lua之前需要深入思考的, ...
- C++ const 和static的总结以及使用
一 static的使用 (作用域和存储方式) 1.作用域---------->隐藏 静态函数跟静态全局变量的作用类似 (静态函数不能被其它文件所用: 其它文件中可以定义相同名字的函数,不会发生 ...
- 队列(链式队列)----C语言
链式队列----用链表实现,链式队列就是一个操作受限的单向链表,如果读者了解单向链表的建立过程,那理解链式队列就很容易了,先回顾一下单向链表的建立过程 (不熟悉单向链表的可以先看看另一片随笔,再回来看 ...
- Good Bye 2017 C. New Year and Curling
Carol is currently curling. She has n disks each with radius r on the 2D plane. Initially she has al ...
- 基于Spring Boot的Logback日志轮转配置
在生产环境下,日志是最好的问题调试和跟踪方法,因此日志的地位是十分重要的.我们平时经常使用的log4j,slf4j,logback等等,他们的配置上大同小异.这里就结合Spring Boot配置一下L ...
- 北大POJ题库使用指南
原文地址:北大POJ题库使用指南 北大ACM题分类主流算法: 1.搜索 //回溯 2.DP(动态规划)//记忆化搜索 3.贪心 4.图论 //最短路径.最小生成树.网络流 5.数论 //组合数学(排列 ...
- SpringBoot入门之事件监听
spring boot在启动过程中增加事件监听机制,为用户功能拓展提供极大的便利,sptingboot支持的事件类型有以下五种: ApplicationStartingEvent Applicatio ...
- LC-BLSTM结构快速解读
参考文献如下: (1) A Context-Sensitive-Chunk BPTT Approach to Training Deep LSTM/BLSTM Recurrent Neural Net ...
- vector.clear()不能用来清零
vector.clear()函数并不会把所有元素清零,笔者就曾经这样幻想过这个函数的作用,然而事实证明并不是. vector有两个参数,一个是size,表示当前vector容器内存储的元素个数,一个是 ...
- 平衡二叉树(AVL)的理解和实现(Java)
AVL的定义 平衡二叉树:是一种特殊的二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1.从平衡二叉树的名字中可以看出来,它是一种高度平衡的二叉排序树.那么什么叫做高度平衡呢?意思就是要么它 ...