Dubbo原理解析-监控
Dubbo發(fā)布代碼中,自帶了一個(gè)簡(jiǎn)易的監(jiān)控中心實(shí)現(xiàn)。對(duì)于一般的小業(yè)務(wù)這個(gè)監(jiān)控中心應(yīng)該能夠滿(mǎn)足需求,對(duì)于那些大業(yè)務(wù)量的大公司一般都會(huì)有自己的監(jiān)控中心,更加豐富的功能如常用的報(bào)警短信通知等等。這章講解分析使得讀者能夠了解一般的監(jiān)控中心實(shí)現(xiàn),也使得有自己接入監(jiān)控中心需求的大概知道如何集成自己的監(jiān)控中心實(shí)現(xiàn)。下面我們就以dubbo自帶的監(jiān)控中心開(kāi)始講解。
?
監(jiān)控中心
1.? 監(jiān)控中心啟動(dòng),我們先看下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的啟動(dòng)注冊(cè)中心多了registry, jetty容器啟動(dòng)
它們都是基于dubbo的spi擴(kuò)展機(jī)制的。
SpringContainer容器啟動(dòng)就是加載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
監(jiān)控中心配置了監(jiān)控服務(wù)的實(shí)現(xiàn)SimpleMonitorService, 并且作為一個(gè)普通的dubbo服務(wù)暴露到注冊(cè)中心,供服務(wù)的提供者和服務(wù)的消費(fèi)方調(diào)用,將服務(wù)提供者和服務(wù)的消費(fèi)方的調(diào)用數(shù)據(jù)保存到監(jiān)控中心。
監(jiān)控服務(wù)的接口定義
public?interface?MonitorService {
????/**
???? *?監(jiān)控?cái)?shù)據(jù)采集.
???? * 1.?支持調(diào)用次數(shù)統(tǒng)計(jì):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記錄監(jiān)控來(lái)源主機(jī),應(yīng)用,接口,方法信息。
???? * 1.2?如果是消費(fèi)者發(fā)送的數(shù)據(jù),加上provider地址參數(shù),反之,加上來(lái)源consumer地址參數(shù)。
???? * 1.3 success,faulure,elapsed?記錄距上次采集,調(diào)用的成功次數(shù),失敗次數(shù),成功調(diào)用總耗時(shí),平均時(shí)間將用總耗時(shí)除以成功次數(shù)。
???? *
???? *?@paramstatistics
???? */
????void?collect(URLstatistics);
?
????/**
???? *?監(jiān)控?cái)?shù)據(jù)查詢(xún).?
???? * 1.?支持按天查詢(xún):count://host/interface?application=foo&method=foo&side=provider&view=chart&date=2012-07-03
???? * 1.1host,application,interface,group,version,method查詢(xún)主機(jī),應(yīng)用,接口,方法的匹配條件,缺失的條件的表示全部,host用0.0.0.0表示全部。
???? * 1.2 side=consumer,provider?查詢(xún)由調(diào)用的哪一端采集的數(shù)據(jù),缺省為都查詢(xún)。
???? * 1.3?缺省為view=summary,返回全天匯總信息,支持view=chart表示返回全天趨勢(shì)圖表圖片的URL地址,可以進(jìn)接嵌入其它系統(tǒng)的頁(yè)面上展示。
???? * 1.4 date=2012-07-03指定查詢(xún)數(shù)據(jù)的日期,缺省為當(dāng)天。
???? *
???? *?@param?query
???? *?@returnstatistics
???? */
??? List<URL> lookup(URL query);
}
?
注: lookup方面可能在開(kāi)源過(guò)程中依賴(lài)了阿里的什么系統(tǒng),并沒(méi)有具體的實(shí)現(xiàn),如果使用著需要此功能則需要根據(jù)接口定義自己實(shí)現(xiàn)
?
MonitorService的dubbo默認(rèn)實(shí)現(xiàn)SimpleMonitorService
Collect方法被遠(yuǎn)程調(diào)用后將數(shù)據(jù)url(傳過(guò)來(lái)的url包含監(jiān)控需要的數(shù)據(jù))保存到一個(gè)阻塞隊(duì)列中BlockingQueue<URL>
啟動(dòng)定時(shí)任務(wù)將統(tǒng)計(jì)日志記錄到本地,
String filename =${user.home}/monitor/statistics
??????????????????????? +?"/"?+ day
??????????????????????? +?"/"?+statistics.getServiceInterface()
??????????????????????? +?"/"?+statistics.getParameter(METHOD)
??????????????????????? +?"/"?+ consumer
??????????????????????? +?"/"?+ provider
??????????????????????? +?"/"?+ type +?"."?+ key
這是文件在本地存儲(chǔ)的格式
文件內(nèi)容如圖保存時(shí)間方法消費(fèi)耗時(shí)
?
3.?起定時(shí)任務(wù)利用JFreeeChart繪制圖表,保存路徑
${user.home}\monitor\charts\date\interfaceName\methodName
?
?
?
產(chǎn)生監(jiān)控?cái)?shù)據(jù)
注冊(cè)中心暴露了MonitorService服務(wù),它是被誰(shuí)調(diào)用的呢,監(jiān)控中心的數(shù)據(jù)是從哪里來(lái)呢,下面我們看下服務(wù)提供方與服務(wù)的消費(fèi)方式如何介入監(jiān)控中心的。
在服務(wù)的提供方跟消費(fèi)方的dubbo配置加入如下配置
通過(guò)注冊(cè)中心<dubbo:monitor protocol="registry" />
或者直連??<dubbo:monitor address="127.0.0.1:7070" />
在構(gòu)建服務(wù)的調(diào)用鏈的時(shí)候有如上基于監(jiān)控的擴(kuò)展,下面我們就來(lái)看下這個(gè)類(lèi)
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
//此過(guò)濾器在服務(wù)的提供方,服務(wù)的消費(fèi)方應(yīng)用中被激活,也就是起作用
public class MonitorFilter implements Filter {
private MonitorFactory monitorFactory;
??? public Result invoke(Invoker<?>invoker, Invocation invocation) throws RpcException {
??? if(invoker.getUrl().hasParameter(Constants.MONITOR_KEY)) {
???????? //有注監(jiān)控中心處理
1.??獲取invoker的調(diào)用上下文
2.??記錄起始時(shí)間戳
3.??并發(fā)計(jì)數(shù)加一
try {
4.??調(diào)用調(diào)用鏈的下一步
5.??采集調(diào)用信息
} finally {
6.??并發(fā)計(jì)數(shù)減一
}
??? } else {
???????? //沒(méi)有配置監(jiān)控中心,直接往下調(diào)用
???? ??? return invoker.inovke(invocation);
?? }
}
?
上面第5點(diǎn)信息采集
1.?計(jì)算調(diào)用耗時(shí)
2.?獲取并發(fā)數(shù)
3.?獲取服務(wù)名稱(chēng)
4.?獲取方法名
5.?判斷是服務(wù)消費(fèi)方監(jiān)控還是服務(wù)提供方監(jiān)控
6.?由工廠類(lèi)monitorFactory.getMonitor(監(jiān)控url),獲取DubboMonitor對(duì)象,
構(gòu)建調(diào)用監(jiān)控中心服務(wù)的的Url, url中包括了監(jiān)控中心所需的監(jiān)控信息
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是調(diào)用監(jiān)控中心的服務(wù)的封裝,之所以沒(méi)有直接調(diào)監(jiān)控中心而是通過(guò)DubboMonitor調(diào)用,是因?yàn)楸O(jiān)控是附加功能,不應(yīng)該影響主鏈路更不應(yīng)該損害主鏈路的新能,DubboMonitor采集到數(shù)據(jù)后通過(guò)任務(wù)定時(shí)調(diào)用監(jiān)控中心服務(wù)將數(shù)據(jù)提交到監(jiān)控中心。
?
RegistryContainer
監(jiān)控中心refer引用了注冊(cè)中心暴露的RegistryService服務(wù),主要是被下面的RegistryContainer使用的。
?
RegistryContainer主要是到注冊(cè)中心收集服務(wù),分組,版本信息,并注冊(cè)回調(diào)當(dāng)注冊(cè)中心數(shù)據(jù)發(fā)生變化的時(shí)候更新到監(jiān)控中心
下面看下RegistryContainer的start方法流程:
1. 通過(guò)SpringContainer獲取前面初始化的RegistryService, 得到其實(shí)是對(duì)注冊(cè)中心的一個(gè)遠(yuǎn)程代理服務(wù)
2. 構(gòu)建訂閱注冊(cè)中心數(shù)據(jù)的URL,看可以看出下面的url是訂閱服務(wù)提供者和服務(wù)消費(fèi)者的所有服務(wù)
subscribeUrl =?newURL(Constants.ADMIN_PROTOCOL, NetUtils.getLocalHost(), 0,"",
??? ????????????Constants.INTERFACE_KEY,Constants.ANY_VALUE,//所有服務(wù)
??????????????? Constants.GROUP_KEY,Constants.ANY_VALUE,//所有分組
??????????????? Constants.VERSION_KEY, Constants.ANY_VALUE,//所有版本
??????????????? Constants.CLASSIFIER_KEY,Constants.ANY_VALUE,//所有分類(lèi)
Constants.CATEGORY_KEY,Constants.PROVIDERS_CATEGORY +?","? + Constants.CONSUMERS_CATEGORY,//服務(wù)的提供者和服務(wù)的消費(fèi)者
??? ?????????????Constants.CHECK_KEY,String.valueOf(false));//不檢查
3.? 調(diào)注冊(cè)中心服務(wù)registry.subscirbe(subscribeUrl,listener)訂閱所有數(shù)據(jù), NotifyListener在監(jiān)控中心暴露為回調(diào)服務(wù),由注冊(cè)中心回調(diào)
回調(diào)接口NotifyListener實(shí)現(xiàn)的功能主要是按服務(wù)提供者和服務(wù)的消費(fèi)者分類(lèi),收集服務(wù)名稱(chēng),服務(wù)的url,服務(wù)提供方或者消費(fèi)方的系統(tǒng)相關(guān)信息。 同時(shí)提供了一系列方法供注冊(cè)中心調(diào)用查詢(xún)。
?
JettyContainer
監(jiān)控中心將采集到的信息通過(guò)內(nèi)置jetty來(lái)展現(xiàn)給用戶(hù),這里為了不依賴(lài)與jsp, velocity,freemarker等一些編寫(xiě)web應(yīng)用的技術(shù),采用在servlet中將html,css,js打印出來(lái)
JettyContainer的start方法啟動(dòng)了內(nèi)置的jettyweb容器
將監(jiān)控中心訪問(wèn)的本地文件目錄設(shè)置到ResourceFilter中,并設(shè)置這個(gè)filter的訪問(wèn)映射到j(luò)etty中?? , ResourceFilter主要是讀取本地保存的JFreeChart繪制的圖片到瀏覽器中去。
將監(jiān)控中心的前置控制器PageServlet, 以及這個(gè)servlet的訪問(wèn)映射配置到j(luò)etty中。之所以叫PageServet為前置控制器,就像其他的mvc框架一樣用來(lái)分發(fā)具體的業(yè)務(wù)類(lèi)
?
PageServet的init初始化方法在web容器啟動(dòng)的時(shí)候加載所有的頁(yè)面處理器PageHandler, 用來(lái)根據(jù)不同的請(qǐng)求生成不同的頁(yè)面,前面說(shuō)過(guò)這里頁(yè)面html都是通過(guò)java代碼打印出來(lái)的。
PageServet的init方法加載所有PageHandler時(shí)會(huì)判斷PageHandler上是否有@Menu注解,將有注解的PageHandler加入集合,以被HomePageHandl er用來(lái)生成主頁(yè)以及各個(gè)頁(yè)面的uri
PageServet的doGet, doPost接收瀏覽器請(qǐng)求,請(qǐng)求以xx.hml形式,xx就是PageHandler擴(kuò)展的key,找到對(duì)應(yīng)的PageHandler繪制對(duì)應(yīng)的頁(yè)面返回給瀏覽器。
?
?
@Menu(name = "Home",desc = "Home page.", order = Integer.MIN_VALUE)
//有注解?name跟desc屬性都是在頁(yè)面中展示給用戶(hù)看的
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);?//這個(gè)uri其實(shí)就是PageHandler擴(kuò)展配置的key,頁(yè)面中用它來(lái)請(qǐng)求選擇具體的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);??//一個(gè)Page實(shí)體就是一個(gè)頁(yè)面,這里包含所有主要HomePage的頁(yè)面內(nèi)容
??? }
}
?
PageHandler的在com.alibaba.dubbo.container.page.PageHandler文件中的擴(kuò)展配置
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大概提供了哪些擴(kuò)展
?下面截幾張圖看看監(jiān)控中心的頁(yè)面。
轉(zhuǎn)載于:https://www.cnblogs.com/duyinqiang/p/5696319.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Dubbo原理解析-监控的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 华为技术加持!阿维塔11智能驾驶实拍:大
- 下一篇: 遍历枚举