Dubbo監視センタ

6820 ワード

Dubbo監視センタ
Dubboは1つの粗末な監視センターを提供して関連するサービスの情況を開発して観察することができて、普通の小さい会社の使う異化はすでに満足することができて、しかし大きい会社の中で業務は比較的に複雑で、往々にして需要を満たすことができなくて、そのため自分でカスタマイズして開発する必要があります(我が社は自分でカスタマイズしたセットです).実はDubboのモニタリングはDubboの核心業務ではなく、説明した理由も自分の学習の私心を満たすためで、自分もモニタリングセンターが一般的にどのように構築されるか分からないので、この機会に勉強しながら共有しましょう.
ビジネスモニタリングとして、一般的にモニタリングするデータはconsumer側の呼び出し時間、provider側の対応する時間、同時量、rtなどである.これらのデータの収集は,インタフェース呼び出しの後に収集するだけでなく,インタフェース呼び出しの前に収集する必要がある.モニタリングはすべてのアプリケーションが必要ではないので、Dubboのモニタリングセンターはオプションで、Dubboの既存のアーキテクチャに基づいてFilterがこのような仕事に最適であり、Dubboもそうしています.Filterの具体的な実装を簡単に見てみましょう.
    //       ,            ,        
    public Result invoke(Invoker> invoker, Invocation invocation) throws RpcException {
        //   monitor             
        if (invoker.getUrl().hasParameter(Constants.MONITOR_KEY)) {
            //       invoke()    context  
            RpcContext context = RpcContext.getContext();  
            //        
            long start = System.currentTimeMillis(); 
            //      (     )
            getConcurrent(invoker, invocation).incrementAndGet();           
            try {
                //        
                Result result = invoker.invoke(invocation);            
                collect(invoker, invocation, result, context, start, false);
                return result;
            } catch (RpcException e) {
                collect(invoker, invocation, null, context, start, true);
                throw e;
            } finally {
                getConcurrent(invoker, invocation).decrementAndGet(); //    
            }
        } else {
            return invoker.invoke(invocation);
        }
    }
    
    
    //              ,             monitor
    private void collect(Invoker> invoker, Invocation invocation, Result result, RpcContext context, long start, boolean error) {
        try {
            // ----        ----
            long elapsed = System.currentTimeMillis() - start; //       
            int concurrent = getConcurrent(invoker, invocation).get(); //        
            String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
            String service = invoker.getInterface().getName(); //       
            String method = RpcUtils.getMethodName(invocation); //      
            URL url = invoker.getUrl().getUrlParameter(Constants.MONITOR_KEY);
            Monitor monitor = monitorFactory.getMonitor(url);//   DubboMonitor
            int localPort;
            String remoteKey;
            String remoteValue;
            if (Constants.CONSUMER_SIDE.equals(invoker.getUrl().getParameter(Constants.SIDE_KEY))) {
                // ----         ----
                context = RpcContext.getContext(); //       invoke()    context  
                localPort = 0;
                remoteKey = MonitorService.PROVIDER;
                remoteValue = invoker.getUrl().getAddress();
            } else {
                // ----         ----
                localPort = invoker.getUrl().getPort();
                remoteKey = MonitorService.CONSUMER;
                remoteValue = context.getRemoteHost();
            }
            //input     request    ,output             
            String input = "", output = "";
            if (invocation.getAttachment(Constants.INPUT_KEY) != null) {
                input = invocation.getAttachment(Constants.INPUT_KEY);
            }
            if (result != null && result.getAttachment(Constants.OUTPUT_KEY) != null) {
                output = result.getAttachment(Constants.OUTPUT_KEY);
            }
            monitor.collect(new URL(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));
        } catch (Throwable t) {
            logger.error("Failed to monitor count service " + invoker.getUrl() + ", cause: " + t.getMessage(), t);
        }
    }

Dubboが収集したデータは主に以下の項目がある.
  • 総成功回数
  • 総失敗回数
  • 合計requestデータサイズ
  • 合計responseデータサイズ
  • 呼び出し総消費時間
  • 同時量
  • 最大requestデータサイズ
  • 最大responseデータサイズ
  • 最大消費時間
  • 最大同時量
  • DubboMonitorは、Filterで収集したデータを格納し、monitorServicesにデータを送信し、最終的にmonitorServicesが受信したデータを整理して表示します.
        public SimpleMonitorService() {
            //       
            queue = new LinkedBlockingQueue(Integer.parseInt(ConfigUtils.getProperty("dubbo.monitor.queue", "100000")));
            writeThread = new Thread(new Runnable() {
                public void run() {
                    while (running) {
                        try {
                            write(); //       
                        } catch (Throwable t) { //      
                            logger.error("Unexpected error occur at write stat log, cause: " + t.getMessage(), t);
                            try {
                                Thread.sleep(5000); //     
                            } catch (Throwable t2) {
                            }
                        }
                    }
                }
            });
            writeThread.setDaemon(true);
            writeThread.setName("DubboMonitorAsyncWriteLogThread");
            writeThread.start();
            chartFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
                public void run() {
                    try {
                        draw(); //     
                    } catch (Throwable t) { //      
                        logger.error("Unexpected error occur at draw stat chart, cause: " + t.getMessage(), t);
                    }
                }
            }, 1, 300, TimeUnit.SECONDS);
            INSTANCE = this;
        }
    

    write()メソッドはLinkedBlockingQueue独自のロックメカニズムを利用してデータを分類して指定したファイルにリフレッシュし、収集したデータがない場合write()はデータが来るまでブロックします.drawメソッドはwirte()メソッドに基づいて生成されたデータファイルを定期的にスキャンしてグラフを生成する.個人的にはwriteもdrawも比較的はっきりした方法だと思いますが、中には重要な内容は含まれていないので、具体的なコードは展示されません.
    以上の紹介から分かるように、Dubboは収集したデータ情報を1つのキューで格納している.単機の問題で、本質的には一定の容量制限がある.Dubboが現在設定しているキューの最大長は100000(10 W)であるが、データを生成するデータがDubboがファイルを書く速度を超えるとデータの蓄積が発生し、蓄積は時間とともに深刻になり、最終的には一部の収集データが漏れ、収集プロセス全体が正確でない可能性がある.したがって、アプリケーションへのアクセスが大きい場合は、Dubboのモニタリングセンターをカスタマイズしてください.