26. Dubbo原理解析-监控

Dubbo发布代码中,自带了一个简易的监控中心实现。对于一般的小业务这个监控中心应该能够满足需求,对于那些大业务量的大公司一般都会有自己的监控中心,更加丰富的功能如常用的报警短信通知等等。这章讲解分析使得读者能够了解一般的监控中心实现,也使得有自己接入监控中心需求的大概知道如何集成自己的监控中心实现。下面我们就以dubbo自带的监控中心开始讲解。

监控中心

1.  监控中心启动,我们先看下dubbo的属性文件

dubbo.container=log4j,spring,registry,jetty

dubbo.application.name=simple-monitor

dubbo.application.owner=

dubbo.registry.address=zookeeper://127.0.0.1:2181

dubbo.protocol.port=7070

dubbo.jetty.port=8080

dubbo.jetty.directory=${user.home}/monitor

dubbo.charts.directory=${dubbo.jetty.directory}/charts

dubbo.statistics.directory=${user.home}/monitor/statistics

相比于provider, consumer的启动注册中心多了registry, jetty容器启动

它们都是基于dubbo的spi扩展机制的。

SpringContainer容器启动就是加载classpath*:META-INF/spring/ *.xml spring的配置文件

<beanid="monitorService"class="com.alibaba.dubbo.monitor.simple.SimpleMonitorService">

<propertyname="statisticsDirectory"value="${dubbo.statistics.directory}"/>

<propertyname="chartsDirectory"value="${dubbo.charts.directory}"/>

</bean>

<dubbo:applicationname="${dubbo.application.name}"owner="${dubbo.application.owner}"/>

<dubbo:registryaddress="${dubbo.registry.address}"/>

<dubbo:protocolname="dubbo"port="${dubbo.protocol.port}"/>

<dubbo:serviceinterface="com.alibaba.dubbo.monitor.MonitorService"ref="monitorService"delay="-1"/>

<dubbo:referenceid="registryService"interface="com.alibaba.dubbo.registry.RegistryService"/>

2. SimpleMonitorService

监控中心配置了监控服务的实现SimpleMonitorService, 并且作为一个普通的dubbo服务暴露到注册中心,供服务的提供者和服务的消费方调用,将服务提供者和服务的消费方的调用数据保存到监控中心。

监控服务的接口定义

public
interface
MonitorService {

/**

* 监控数据采集.

* 1. 支持调用次数统计:count://host/interface?application=foo&method=foo&provider=10.20.153.11:20880&success=12&failure=2&elapsed=135423423

* 1.1host,application,interface,group,version,method记录监控来源主机,应用,接口,方法信息。

* 1.2 如果是消费者发送的数据,加上provider地址参数,反之,加上来源consumer地址参数。

* 1.3 success,faulure,elapsed
记录距上次采集,调用的成功次数,失败次数,成功调用总耗时,平均时间将用总耗时除以成功次数。

*

* @paramstatistics

*/

void collect(URLstatistics);

/**

* 监控数据查询.

* 1. 支持按天查询:count://host/interface?application=foo&method=foo&side=provider&view=chart&date=2012-07-03

* 1.1host,application,interface,group,version,method查询主机,应用,接口,方法的匹配条件,缺失的条件的表示全部,host用0.0.0.0表示全部。

* 1.2 side=consumer,provider
查询由调用的哪一端采集的数据,缺省为都查询。

* 1.3 缺省为view=summary,返回全天汇总信息,支持view=chart表示返回全天趋势图表图片的URL地址,可以进接嵌入其它系统的页面上展示。

* 1.4 date=2012-07-03指定查询数据的日期,缺省为当天。

*

* @param query

* @returnstatistics

*/

List<URL> lookup(URL query);

}

注: lookup方面可能在开源过程中依赖了阿里的什么系统,并没有具体的实现,如果使用着需要此功能则需要根据接口定义自己实现

MonitorService的dubbo默认实现SimpleMonitorService

Collect方法被远程调用后将数据url(传过来的url包含监控需要的数据)保存到一个阻塞队列中BlockingQueue<URL>

启动定时任务将统计日志记录到本地,

String filename =${user.home}/monitor/statistics

+ "/" + day

+ "/" +statistics.getServiceInterface()

+ "/" +statistics.getParameter(METHOD)

+ "/" + consumer

+ "/" + provider

+ "/" + type +
"." + key

这是文件在本地存储的格式

文件内容如图保存时间方法消费耗时

3. 起定时任务利用JFreeeChart绘制图表,保存路径

${user.home}\monitor\charts\date\interfaceName\methodName

产生监控数据

注册中心暴露了MonitorService服务,它是被谁调用的呢,监控中心的数据是从哪里来呢,下面我们看下服务提供方与服务的消费方式如何介入监控中心的。

在服务的提供方跟消费方的dubbo配置加入如下配置

通过注册中心<dubbo:monitor protocol="registry" />

或者直连  <dubbo:monitor address="127.0.0.1:7070" />

在构建服务的调用链的时候有如上基于监控的扩展,下面我们就来看下这个类

@Activate(group = {Constants.PROVIDER, Constants.CONSUMER})

//此过滤器在服务的提供方,服务的消费方应用中被激活,也就是起作用

public class MonitorFilter implements Filter {

private MonitorFactory monitorFactory;

    public Result invoke(Invoker<?>invoker, Invocation invocation) throws RpcException {

    if(invoker.getUrl().hasParameter(Constants.MONITOR_KEY)) {

         //有注监控中心处理

1.  获取invoker的调用上下文

2.  记录起始时间戳

3.  并发计数加一

try {

4.  调用调用链的下一步

5.  采集调用信息

} finally {

6.  并发计数减一

}

    } else {

         //没有配置监控中心,直接往下调用

         return invoker.inovke(invocation);

   }

}

上面第5点信息采集

1. 计算调用耗时

2. 获取并发数

3. 获取服务名称

4. 获取方法名

5. 判断是服务消费方监控还是服务提供方监控

6. 由工厂类monitorFactory.getMonitor(监控url),获取DubboMonitor对象,

构建调用监控中心服务的的Url, url中包括了监控中心所需的监控信息

monitor.collect(newURL(Constants.COUNT_PROTOCOL,

NetUtils.getLocalHost(),localPort,

service + "/" +method,

MonitorService.APPLICATION, application,

MonitorService.INTERFACE,service,

MonitorService.METHOD,method,

remoteKey, remoteValue,

error ?MonitorService.FAILURE : MonitorService.SUCCESS, "1",

MonitorService.ELAPSED,String.valueOf(elapsed),

MonitorService.CONCURRENT,String.valueOf(concurrent),

Constants.INPUT_KEY, input,

Constants.OUTPUT_KEY, output));

DubboMonitor是调用监控中心的服务的封装,之所以没有直接调监控中心而是通过DubboMonitor调用,是因为监控是附加功能,不应该影响主链路更不应该损害主链路的新能,DubboMonitor采集到数据后通过任务定时调用监控中心服务将数据提交到监控中心。

RegistryContainer

监控中心refer引用了注册中心暴露的RegistryService服务,主要是被下面的RegistryContainer使用的。

RegistryContainer主要是到注册中心收集服务,分组,版本信息,并注册回调当注册中心数据发生变化的时候更新到监控中心

下面看下RegistryContainer的start方法流程:

1. 通过SpringContainer获取前面初始化的RegistryService, 得到其实是对注册中心的一个远程代理服务

2. 构建订阅注册中心数据的URL,看可以看出下面的url是订阅服务提供者和服务消费者的所有服务

subscribeUrl = newURL(Constants.ADMIN_PROTOCOL, NetUtils.getLocalHost(), 0,"",

Constants.INTERFACE_KEY,Constants.ANY_VALUE,//所有服务

Constants.GROUP_KEY,Constants.ANY_VALUE,//所有分组

Constants.VERSION_KEY, Constants.ANY_VALUE,//所有版本

Constants.CLASSIFIER_KEY,Constants.ANY_VALUE,//所有分类

Constants.CATEGORY_KEY,Constants.PROVIDERS_CATEGORY +
","  + Constants.CONSUMERS_CATEGORY,//服务的提供者和服务的消费者

Constants.CHECK_KEY,String.valueOf(false));//不检查

3.  调注册中心服务registry.subscirbe(subscribeUrl,listener)订阅所有数据, NotifyListener在监控中心暴露为回调服务,由注册中心回调

回调接口NotifyListener实现的功能主要是按服务提供者和服务的消费者分类,收集服务名称,服务的url,服务提供方或者消费方的系统相关信息。 同时提供了一系列方法供注册中心调用查询。

JettyContainer

监控中心将采集到的信息通过内置jetty来展现给用户,这里为了不依赖与jsp, velocity,freemarker等一些编写web应用的技术,采用在servlet中将html,css,js打印出来

JettyContainer的start方法启动了内置的jettyweb容器

将监控中心访问的本地文件目录设置到ResourceFilter中,并设置这个filter的访问映射到jetty中   , ResourceFilter主要是读取本地保存的JFreeChart绘制的图片到浏览器中去。

将监控中心的前置控制器PageServlet, 以及这个servlet的访问映射配置到jetty中。之所以叫PageServet为前置控制器,就像其他的mvc框架一样用来分发具体的业务类

PageServet的init初始化方法在web容器启动的时候加载所有的页面处理器PageHandler, 用来根据不同的请求生成不同的页面,前面说过这里页面html都是通过java代码打印出来的。

PageServet的init方法加载所有PageHandler时会判断PageHandler上是否有@Menu注解,将有注解的PageHandler加入集合,以被HomePageHandl er用来生成主页以及各个页面的uri

PageServet的doGet, doPost接收浏览器请求,请求以xx.hml形式,xx就是PageHandler扩展的key,找到对应的PageHandler绘制对应的页面返回给浏览器。

@Menu(name = "Home",desc = "Home page.", order = Integer.MIN_VALUE)

//有注解 name跟desc属性都是在页面中展示给用户看的

public class HomePageHandlerimplements PageHandler {

public Page handle(URL url) {

List<List<String>> rows =new ArrayList<List<String>>();

for (PageHandler handler :PageServlet.getInstance().getMenus()) {

String uri =ExtensionLoader.getExtensionLoader(PageHandler.class).getExtensionName(handler); //这个uri其实就是PageHandler扩展配置的key,页面中用它来请求选择具体的handler绘制  
  //出具体的page

Menu menu =handler.getClass().getAnnotation(Menu.class);

List<String> row = newArrayList<String>();

row.add("<ahref=\"" + uri + ".html\">" + menu.name() +"</a>");

row.add(menu.desc());

rows.add(row);

}

return new Page("Home","Menus",  new String[]{"Menu Name", "Menu Desc"}, rows);  //一个Page实体就是一个页面,这里包含所有主要HomePage的页面内容

}

}

PageHandler的在com.alibaba.dubbo.container.page.PageHandler文件中的扩展配置

index=com.alibaba.dubbo.container.page.pages.HomePageHandler

providers=com.alibaba.dubbo.monitor.simple.pages.ProvidersPageHandler

consumers=com.alibaba.dubbo.monitor.simple.pages.ConsumersPageHandler

。。。。

下面截图看下dubbo大概提供了哪些扩展

下面截几张图看看监控中心的页面。

时间: 2024-10-19 12:15:35

26. Dubbo原理解析-监控的相关文章

13. Dubbo原理解析-注册中心之Zookeeper协议注册中心

下面我们来看下开源dubbo推荐的业界成熟的zookeeper做为注册中心, zookeeper是hadoop的一个子项目是分布式系统的可靠协调者,他提供了配置维护,名字服务,分布式同步等服务.对于zookeeper的原理本文档不分析,后面有时间在做专题. zookeeper注册中心 Zookeeper对数据存储类似linux的目录结构,下面给出官方文档对dubbo注册数据的存储示例 假设读者对zookeeper有所了解,能够搭建zookeeper服务,其实不了解也没关系,谷歌百度下分分钟搞起.

8. Dubbo原理解析-代理之服务发布

服务发布是服务提供方向注册中注册服务过程,以便服务消费者从注册中心查阅并调用服务. 服务发布方在spring的配置文件中配置如下: <bean id="demoService"class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" /> 上面是在spring中配置的服务的具体实现,是spring中的一个普通的bean <dubbo:serviceinterface="com.alib

9. Dubbo原理解析-代理之服务引用

服务引用是服务的消费方向注册中心订阅服务提供方提供的服务地址后向服务提供方引用服务的过程. 服务的应用方在spring的配置实例如下: <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo. DemoService"/> 如上配置spring在容器启动的时候会解析自定义的schema元素<dubbo: reference/>转换成dubbo内部数据结构Refer

分布式服务框架dubbo原理解析

alibaba有好几个分布式框架,主要有:进行远程调用(类似于RMI的这种远程调用)的(dubbo.hsf),jms消息服务(napoli.notify),KV数据库(tair)等.这个框架/工具/产品在实现的时候,都考虑到了容灾,扩展,负载均衡,于是出现一个配置中心(ConfigServer)的东西来解决这些问题. 基本原理如图: 在我们的系统中,经常会有一些跨系统的调用,如在A系统中要调用B系统的一个服务,我们可能会使用RMI直接来进行,B系统发布一个RMI接口服务,然后A系统就来通过RMI

16. Dubbo原理解析-集群&amp;容错之router路由服务

Router服务路由, 根据路由规则从多个Invoker中选出一个子集AbstractDirectory是所有目录服务实现的上层抽象, 它在list列举出所有invokers后,会在通过Router服务进行路由过滤. Router接口定义 public interface Router extendsComparable<Router> { URL getUrl(); <T> List<Invoker<T>> route(List<Invoker<

11. Dubbo原理解析-注册中心之基于dubbo协议的接口介绍

服务注册与发现的中心,服务的提供者将服务发布到注册中心,服务的使用着到注册中引用服务. Dubbo的注册中心提供了多种实现,其实现是基于dubbo的spi的扩展机制的,使用着可以直接实现自己的注册中心. @SPI("dubbo") public interface RegistryFactory { /** * 连接注册中心. * 连接注册中心需处理契约 * 1. 当设置check=false时表示不检查连接,否则在连接不上时抛出异常. * 2. 支持URL上的username:pas

12. Dubbo原理解析-注册中心之基于dubbo协议的简单注册中心实现

基于dubbo协议开源只是给出了默认一个注册中心实现SimpleRegistryService, 它只是一个简单实现,不支持集群,就是利用Map<String/*ip:port*/, Map<String/*service*/, URL>来存储服务地址, 具体不在啰嗦了,请读者翻看源代码,可作为自定义注册中的参考. 注册中心启动 SimpleRegistryService本身也是作为一个dubbo服务暴露. <dubbo:protocolport="9090"

10. Dubbo原理解析-代理之Listener &amp; filter

Listener ExporterListener: dubbo在服务暴露(exporter)以及销毁暴露(unexporter)服务的过程中提供了回调窗口,供用户做业务处理.ProtocolListenerWrapper在暴露过程中构建了监听器链 public class ProtocolListenerWrapper implements Protocol { public <T> Exporter<T> export(Invoker<T>invoker) thro

14. Dubbo原理解析-集群&amp;容错之Cluster

Dubbo作为一个分布式的服务治理框架,提供了集群部署,路由,软负载均衡及容错机制 下图描述了dubbo调用过程中的对于集群,负载等的调用关系. Cluster 将Directory中的多个Invoker伪装成一个Invoker, 对上层透明,包含集群的容错机制 Cluster接口定义 @SPI(FailoverCluster.NAME) public interface Cluster { @Adaptive <T> Invoker<T>join(Directory<T&g