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的属性、MonitorConfigMap<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动态重写MonitorConfigclass

在应用启动时,使用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存入MonitorConfigMap<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>节点的分析处理类

http://code.alibabatech.com/schema/youyue/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

至此,配置好<dubbo:registry interval="10000" xxx />启动应用,可以看到上报周期由60秒变成了10秒。

DUBBO监控,设置接口调用数据的上报周期的更多相关文章

  1. Dubbo -- 关于 api接口调用不使用强依赖

    首先,我们都知道  Dubbo 调用api 需要提供暴露  接口,   消费端才通过 ZK 可以调用 通常我们都会使用 提供 api  jar包 的方式 使用  这样既方便又快捷 简单 只需要在spr ...

  2. webService 客户端接口调用【java】

    最近实际项目中使用到了WebService,简单总结下使用方式: 1.拿到接口:http://*******:8080/osms/services/OrderWebService?wsdl 我们可以将 ...

  3. EasyNVR流媒体服务器网页兼容调试:ie浏览器下的接口调用成功但页面无法显示实时的数据

    许多问题很难在开发的过程中就想的面面俱到,都是在实际应用.调试的过程中一一的优化的.由于easynvr的受众越来越多,因此也出现了好多在开发之初并没有留意的一些细节.我这次发现的问题就是给客户远程解决 ...

  4. 一行代码搞定Dubbo接口调用

    本文来自网易云社区 作者:吕彦峰 在工作中我们经常遇到关于接口测试的问题,无论是对于QA同学还是开发同学都会有远程接口调用的需求.针对这种问题我研发了一个工具包,专门用于远程Dubbo调用,下面就让我 ...

  5. 借助Anyproxy实时监控接口调用次数和流量

    监控接口调用次数,是为了测试客户端可能会异常频繁的调用服务端接口,出现性能问题. AnyProxy是一个开放式的HTTP代理服务器. github: https://github.com/alibab ...

  6. java接口对接——别人调用我们接口获取数据

    java接口对接——别人调用我们接口获取数据,我们需要在我们系统中开发几个接口,给对方接口规范文档,包括访问我们的接口地址,以及入参名称和格式,还有我们的返回的状态的情况, 接口代码: package ...

  7. page分页问题,根据页码获取对应页面的数据,接口调用

    添加一个log.js文件,进行接口调用. import axios from '@/libs/api.request' const MODULE_URL = '/log'; export const ...

  8. SAP调用RestfulApi接口POST数据到外部系统

    作者:明光烁亮 出处:http://www.cnblogs.com/hezhongxun/ 微信号:HEme922 欢迎加好友一起交流SAP! 视频资料共享. 本文版权归作者和博客园共有,欢迎转载,但 ...

  9. Vue单页面中进行业务数据的上报

    为什么要在标题里加上一个业务数据的上报呢,因为在咱们前端项目中,可上报的数据维度太多,比如还有性能数据.页面错误数据.console捕获等.这里我们只讲解业务数据的埋点. 业务数据的上报主要分为: 各 ...

随机推荐

  1. 【cocos2d-x + Lua(1) 绑定Lua并使用tolua++】

    为什么要使用Lua进行游戏开发?转载请注明出处http://www.cnblogs.com/zisou/p/cocos2dx-lua1.html 上面一个问题我觉得在我们使用Lua之前需要深入思考的, ...

  2. C++ const 和static的总结以及使用

    一  static的使用 (作用域和存储方式) 1.作用域---------->隐藏 静态函数跟静态全局变量的作用类似 (静态函数不能被其它文件所用: 其它文件中可以定义相同名字的函数,不会发生 ...

  3. 队列(链式队列)----C语言

    链式队列----用链表实现,链式队列就是一个操作受限的单向链表,如果读者了解单向链表的建立过程,那理解链式队列就很容易了,先回顾一下单向链表的建立过程 (不熟悉单向链表的可以先看看另一片随笔,再回来看 ...

  4. 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 ...

  5. 基于Spring Boot的Logback日志轮转配置

    在生产环境下,日志是最好的问题调试和跟踪方法,因此日志的地位是十分重要的.我们平时经常使用的log4j,slf4j,logback等等,他们的配置上大同小异.这里就结合Spring Boot配置一下L ...

  6. 北大POJ题库使用指南

    原文地址:北大POJ题库使用指南 北大ACM题分类主流算法: 1.搜索 //回溯 2.DP(动态规划)//记忆化搜索 3.贪心 4.图论 //最短路径.最小生成树.网络流 5.数论 //组合数学(排列 ...

  7. SpringBoot入门之事件监听

    spring boot在启动过程中增加事件监听机制,为用户功能拓展提供极大的便利,sptingboot支持的事件类型有以下五种: ApplicationStartingEvent Applicatio ...

  8. LC-BLSTM结构快速解读

    参考文献如下: (1) A Context-Sensitive-Chunk BPTT Approach to Training Deep LSTM/BLSTM Recurrent Neural Net ...

  9. vector.clear()不能用来清零

    vector.clear()函数并不会把所有元素清零,笔者就曾经这样幻想过这个函数的作用,然而事实证明并不是. vector有两个参数,一个是size,表示当前vector容器内存储的元素个数,一个是 ...

  10. 平衡二叉树(AVL)的理解和实现(Java)

    AVL的定义 平衡二叉树:是一种特殊的二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1.从平衡二叉树的名字中可以看出来,它是一种高度平衡的二叉排序树.那么什么叫做高度平衡呢?意思就是要么它 ...