/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.synapse.transport.passthru.jmx; import org.apache.synapse.commons.jmx.MBeanRegistrar; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; /** * <p>LatencyView provides statistical information related to the latency (overhead) incurred by * the Synapse NHTTP transport, when mediating messages back and forth. Statistics are available * under two main categories, namely short term data and long term data. Short term data is * statistical information related to the last 15 minutes of execution and these metrics are * updated every 5 seconds. Long term data is related to the last 24 hours of execution and * they are updated every 5 minutes. Two timer tasks and a single threaded scheduled executor * is used to perform these periodic calculations.</p> * * <p>Latency calculation for a single invocation is carried out by taking timestamps on * following events:</p> * * <ul> * <li>t1 - Receiving a new request (ServerHandler#requestReceived)</li> * <li>t2 - Obtaining a connection to forward the request (ClientHandler#processConnection)</li> * <li>t3 - Reading the complete response from the backend server (ClientHandler#inputReady)</li> * <li>t4 - Writing the complete response to the client (ServerHandler#outputReady)</li> * <ul> * * <p>Having taken these timestamps, the latency for the invocation is calculated as follows:<br/> * Latency = (t4 - t1) - (t3 - t2) * </p> * */ public class LatencyView implements LatencyViewMBean { private static final int SMALL_DATA_COLLECTION_PERIOD = 5; private static final int LARGE_DATA_COLLECTION_PERIOD = 5 * 60; /** Keeps track of th last reported latency value */ private LatencyParameter lastLatency = new LatencyParameter(true); /** -Following are used to calculate BackEnd(Be) latency - */ /** Keeps track of th last reported BE latency value */ private LatencyParameter lastLatencyBe = new LatencyParameter(true); private LatencyParameter serverDecodeLatency; private LatencyParameter serverEncodeLatency; private LatencyParameter clientEncodeLatency; private LatencyParameter clientDecodeLatency; private LatencyParameter serverWorkerWaitTime; private LatencyParameter clientWorkerWaitTime; private LatencyParameter requestMediationLatency; private LatencyParameter responseMediationLatency; private List<LatencyParameter> latencies = new ArrayList<LatencyParameter>(10); /** Scheduled executor on which data collectors are executed */ private ScheduledExecutorService scheduler; private Date resetTime = Calendar.getInstance().getTime(); private String latencyMode; private String name; /** * Implementation of LatencyMbean * @param latencyMode S2S enabled or not * @param isHttps Is Secured */ public LatencyView(final String latencyMode, boolean isHttps) { this(latencyMode, isHttps, "", false); } /** * Implementation of LatencyMbean * @param latencyMode S2S enabled or not * @param isHttps Is Secured * @param namePostfix NamePostfix * @param showAdvancedParameters Enabling advanced latency capturing */ public LatencyView(final String latencyMode, boolean isHttps, final String namePostfix, final boolean showAdvancedParameters) { this.latencyMode = latencyMode; name = "nio-http" + (isHttps ? "s" : "") + namePostfix; scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { public Thread newThread(Runnable r) { return new Thread(r, latencyMode + "-" + name + "-latency-view"); } }); scheduler.scheduleAtFixedRate(new ShortTermDataCollector(), SMALL_DATA_COLLECTION_PERIOD, SMALL_DATA_COLLECTION_PERIOD, TimeUnit.SECONDS); scheduler.scheduleAtFixedRate(new LongTermDataCollector(), LARGE_DATA_COLLECTION_PERIOD, LARGE_DATA_COLLECTION_PERIOD, TimeUnit.SECONDS); boolean registered = false; try { registered = MBeanRegistrar.getInstance().registerMBean(this, this.latencyMode, name); } finally { if (!registered) { scheduler.shutdownNow(); } } registerAllLatencies(showAdvancedParameters); } public void destroy() { MBeanRegistrar.getInstance().unRegisterMBean(latencyMode, name); if (!scheduler.isShutdown()) { scheduler.shutdownNow(); } } /** * Report the timestamp values captured during mediating messages back and forth * * @param reqArrival The request arrival time * @param reqDeparture The request departure time (backend connection establishment) * @param resArrival The resoponse arrival time * @param resDeparture The response departure time */ private void notifyTimes(long reqArrival, long reqDeparture, long resArrival, long resDeparture) { long latencyBe = (resArrival - reqDeparture); long latency = (resDeparture - reqArrival) - latencyBe; lastLatency.update(latency); lastLatencyBe.update(latencyBe); } public void notifyTimes(LatencyCollector collector) { lastLatency.update(collector.getLatency()); lastLatencyBe.update(collector.getBackendLatency()); serverDecodeLatency.update(collector.getServerDecodeLatency()); clientEncodeLatency.update(collector.getClientEncodeLatency()); clientDecodeLatency.update(collector.getClientDecodeLatency()); serverEncodeLatency.update(collector.getServerEncodeLatency()); serverWorkerWaitTime.update(collector.getServerWorkerQueuedTime()); clientWorkerWaitTime.update(collector.getClientWorkerQueuedTime()); requestMediationLatency.update(collector.getServerWorkerLatency()); responseMediationLatency.update(collector.getClientWorkerLatency()); } private void registerAllLatencies(boolean recordAdditionalLatencies) { latencies.add(lastLatency); latencies.add(lastLatencyBe); serverDecodeLatency = new LatencyParameter(recordAdditionalLatencies); serverEncodeLatency = new LatencyParameter(recordAdditionalLatencies); clientEncodeLatency = new LatencyParameter(recordAdditionalLatencies); clientDecodeLatency = new LatencyParameter(recordAdditionalLatencies); serverWorkerWaitTime = new LatencyParameter(recordAdditionalLatencies); clientWorkerWaitTime = new LatencyParameter(recordAdditionalLatencies); requestMediationLatency = new LatencyParameter(recordAdditionalLatencies); responseMediationLatency = new LatencyParameter(recordAdditionalLatencies); latencies.add(serverDecodeLatency); latencies.add(clientEncodeLatency); latencies.add(clientDecodeLatency); latencies.add(serverEncodeLatency); latencies.add(serverWorkerWaitTime); latencies.add(clientWorkerWaitTime); latencies.add(requestMediationLatency); latencies.add(responseMediationLatency); } public double getAvg_Latency() { return lastLatency.getAllTimeAverage(); } public double getAvg_Client_To_Esb_RequestReadTime() { return serverDecodeLatency.getAllTimeAverage(); } public double getAvg_Esb_To_BackEnd_RequestWriteTime() { return clientEncodeLatency.getAllTimeAverage(); } public double getAvg_BackEnd_To_Esb_ResponseReadTime() { return clientDecodeLatency.getAllTimeAverage(); } public double getAvg_Esb_To_Client_ResponseWriteTime() { return serverEncodeLatency.getAllTimeAverage(); } public double get1m_Avg_Client_To_Esb_RequestReadTime() { return serverDecodeLatency.getAverageLatency1m(); } public double get1m_Avg_Esb_To_BackEnd_RequestWriteTime() { return clientEncodeLatency.getAverageLatency1m(); } public double get1m_Avg_BackEnd_To_Esb_ResponseReadTime() { return clientDecodeLatency.getAverageLatency1m(); } public double get1m_Avg_Esb_To_Client_ResponseWriteTime() { return serverEncodeLatency.getAverageLatency1m(); } public double get5m_Avg_Client_To_Esb_RequestReadTime() { return serverDecodeLatency.getAverageLatency5m(); } public double get5m_Avg_Esb_To_BackEnd_RequestWriteTime() { return clientEncodeLatency.getAverageLatency5m(); } public double get5m_Avg_BackEnd_To_Esb_ResponseReadTime() { return clientDecodeLatency.getAverageLatency5m(); } public double get5m_Avg_Esb_To_Client_ResponseWriteTime() { return serverEncodeLatency.getAverageLatency5m(); } public double get15m_Avg_Client_To_Esb_RequestReadTime() { return serverDecodeLatency.getAverageLatency15m(); } public double get15m_Avg_Esb_To_BackEnd_RequestWriteTime() { return clientEncodeLatency.getAverageLatency15m(); } public double get15m_Avg_BackEnd_To_Esb_ResponseReadTime() { return clientDecodeLatency.getAverageLatency15m(); } public double get15m_Avg_Esb_To_Client_ResponseWriteTime() { return serverEncodeLatency.getAverageLatency15m(); } public double getAvg_ClientWorker_QueuedTime() { return clientWorkerWaitTime.getAllTimeAverage(); } public double get1m_Avg_ClientWorker_QueuedTime() { return clientWorkerWaitTime.getAverageLatency1m(); } public double get5m_Avg_ClientWorker_QueuedTime() { return clientWorkerWaitTime.getAverageLatency5m(); } public double get15m_Avg_ClientWorker_QueuedTime() { return clientWorkerWaitTime.getAverageLatency15m(); } public double getAvg_ServerWorker_QueuedTime() { return serverWorkerWaitTime.getAllTimeAverage(); } public double get1m_Avg_ServerWorker_QueuedTime() { return serverWorkerWaitTime.getAverageLatency1m(); } public double get5m_Avg_ServerWorker_QueuedTime() { return serverWorkerWaitTime.getAverageLatency5m(); } public double get15m_Avg_ServerWorker_QueuedTime() { return serverWorkerWaitTime.getAverageLatency15m(); } public double get1m_Avg_Latency() { return lastLatency.getAverageLatency1m(); } public double get5m_Avg_Latency() { return lastLatency.getAverageLatency5m(); } public double get15m_Avg_Latency() { return lastLatency.getAverageLatency15m(); } public double get1h_Avg_Latency() { return lastLatency.getAverageLatency1h(); } public double get8h_Avg_Latency() { return lastLatency.getAverageLatency8h(); } public double get24h_Avg_Latency() { return lastLatency.getAverageLatency24h(); } public double getAvg_Latency_BackEnd() { return lastLatencyBe.getAllTimeAverage(); } public double get1m_Avg_Latency_BackEnd() { return lastLatencyBe.getAverageLatency1m(); } public double get5m_Avg_Latency_BackEnd() { return lastLatencyBe.getAverageLatency5m(); } public double get15m_Avg_Latency_BackEnd() { return lastLatencyBe.getAverageLatency15m(); } public double get1h_Avg_Latency_BackEnd() { return lastLatencyBe.getAverageLatency1h(); } public double get8h_Avg_Latency_BackEnd() { return lastLatencyBe.getAverageLatency8h(); } public double get24h_Avg_Latency_BackEnd() { return lastLatencyBe.getAverageLatency24h(); } public double get1h_Avg_Client_To_Esb_RequestReadTime() { return serverDecodeLatency.getAverageLatency1h(); } public double get1h_Avg_Esb_To_BackEnd_RequestWriteTime() { return clientEncodeLatency.getAverageLatency1h(); } public double get1h_Avg_BackEnd_To_Esb_ResponseReadTime() { return clientDecodeLatency.getAverageLatency1h(); } public double get1h_Avg_Esb_To_Client_ResponseWriteTime() { return serverEncodeLatency.getAverageLatency1h(); } public double get1h_Avg_ServerWorker_QueuedTime() { return serverWorkerWaitTime.getAverageLatency1h(); } public double get1h_Avg_ClientWorker_QueuedTime() { return clientWorkerWaitTime.getAverageLatency1h(); } public double get8h_Avg_Client_To_Esb_RequestReadTime() { return serverDecodeLatency.getAverageLatency8h(); } public double get8h_Avg_Esb_To_BackEnd_RequestWriteTime() { return clientEncodeLatency.getAverageLatency8h(); } public double get8h_Avg_BackEnd_To_Esb_ResponseReadTime() { return clientDecodeLatency.getAverageLatency8h(); } public double get8h_Avg_Esb_To_Client_ResponseWriteTime() { return serverEncodeLatency.getAverageLatency8h(); } public double get8h_Avg_ServerWorker_QueuedTime() { return serverWorkerWaitTime.getAverageLatency8h(); } public double get8h_Avg_ClientWorker_QueuedTime() { return clientWorkerWaitTime.getAverageLatency8h(); } public double get24h_Avg_Client_To_Esb_RequestReadTime() { return serverDecodeLatency.getAverageLatency24h(); } public double get24h_Avg_Esb_To_BackEnd_RequestWriteTime() { return clientEncodeLatency.getAverageLatency24h(); } public double get24h_Avg_BackEnd_To_Esb_ResponseReadTime() { return clientDecodeLatency.getAverageLatency24h(); } public double get24h_Avg_Esb_To_Client_ResponseWriteTime() { return serverEncodeLatency.getAverageLatency24h(); } public double get24h_Avg_ServerWorker_QueuedTime() { return serverWorkerWaitTime.getAverageLatency24h(); } public double get24h_Avg_ClientWorker_QueuedTime() { return clientWorkerWaitTime.getAverageLatency24h(); } public double getAvg_request_Mediation_Latency() { return requestMediationLatency.getAllTimeAverage(); } public double getAvg_response_Mediation_Latency() { return responseMediationLatency.getAllTimeAverage(); } public double get1m_Avg_request_Mediation_Latency() { return requestMediationLatency.getAverageLatency1m(); } public double get1m_Avg_response_Mediation_Latency() { return responseMediationLatency.getAverageLatency1m(); } public double get5m_Avg_request_Mediation_Latency() { return requestMediationLatency.getAverageLatency5m(); } public double get5m_Avg_response_Mediation_Latency() { return responseMediationLatency.getAverageLatency5m(); } public double get15m_Avg_request_Mediation_Latency() { return requestMediationLatency.getAverageLatency15m(); } public double get15m_Avg_response_Mediation_Latency() { return responseMediationLatency.getAverageLatency15m(); } public double get1h_Avg_request_Mediation_Latency() { return requestMediationLatency.getAverageLatency1h(); } public double get1h_Avg_response_Mediation_Latency() { return responseMediationLatency.getAverageLatency1h(); } public double get8h_Avg_request_Mediation_Latency() { return requestMediationLatency.getAverageLatency8h(); } public double get8h_Avg_response_Mediation_Latency() { return responseMediationLatency.getAverageLatency8h(); } public double get24h_Avg_request_Mediation_Latency() { return requestMediationLatency.getAverageLatency24h(); } public double get24h_Avg_response_Mediation_Latency() { return responseMediationLatency.getAverageLatency24h(); } public void reset() { for (LatencyParameter latency : latencies) { latency.reset(); } resetTime = Calendar.getInstance().getTime(); } public Date getLastResetTime() { return resetTime; } private class ShortTermDataCollector implements Runnable { public void run() { for (LatencyParameter latency : latencies) { latency.updateCache(); } } } private class LongTermDataCollector implements Runnable { public void run() { for (LatencyParameter latency : latencies) { latency.updateLongTermCache(); } } } }