blob: 40eced0897e2dc7071e40b357b7edc99537070ea [file] [log] [blame]
<!--
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.
-->
{{> www/common-header.tmpl }}
<h2>RPC durations</h2>
<p class="lead">This page shows the durations of all RPCs served by this
<samp>{{__common__.process-name}}</samp> process.
</p>
<label>
<input type="checkbox" checked="true" id="toggle" onClick="toggleRefresh()"/>
<span id="refresh_on">Auto-refresh on</span>
</label> Last updated: <span id="last-updated"></span>
{{?services}}
<h2>KRPC Services</h2>
{{/services}}
{{#services}}
<h3><samp>{{service_name}}</samp></h3>
<table class="table table-hover table-bordered" id="{{service_name}}_metrics">
<tbody>
<tr>
<td>
<table class="table table-hover">
<tr>
<th>Queue Size</th>
<th>Idle Threads</th>
<th>Current Memory Usage</th>
<th>Peak Memory Usage</th>
<th>RPCs Rejected due to Queue Overflow</th>
</tr>
<tr>
<td id="{{service_name}}_queue_size">{{queue_size}}</td>
<td id="{{service_name}}_idle_threads">{{idle_threads}}</td>
<td id="{{service_name}}_mem_usage">{{mem_usage}}</td>
<td id="{{service_name}}_mem_peak">{{mem_peak}}</td>
<td id="{{service_name}}_rpcs_queue_overflow">{{rpcs_queue_overflow}}</td>
</tr>
</table>
<table class="table table-hover">
<tr>
<th>Incoming Queueing Time</th>
<td id="{{service_name}}_incoming_queue_time" colspan=2>{{incoming_queue_time}}
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
{{#rpc_method_metrics}}
<table class="table table-bordered table-hover">
<tr><td colspan=2>
<strong>Method: <i>{{method_name}}</i></strong>
</td></tr>
<tr>
<td>Handler Latency</td>
<td class="{{method_name}}_handler_latency">{{handler_latency}}</td>
</tr>
<tr>
<td>Payload Size</td>
<td class="{{method_name}}_payload_size">{{payload_size}}</td>
</tr>
</table>
{{/rpc_method_metrics}}
</td>
</tr>
</tbody>
</table>
{{/services}}
<h3>Per connection metrics for KRPC outbound connections</h3>
<table class="table table-bordered table-hover" id="per_conn_metrics">
<thead>
<tr>
<th>Remote Address</th>
<th># Calls in Flight</th>
<th>Outbound Queue Size (count)</th>
<th>Socket RTT (us)</th>
<th>Socket RTT Variance (us)</th>
<th>Sender Congestion Window</th>
<th># Retransmitted Packets</th>
<th>Pacing Rate</th>
<th>Max Pacing Rate</th>
<th>Bytes Acked</th>
<th>Bytes Received</th>
<th>Segments Sent</th>
<th>Segments Received</th>
<th>Send Queue Size (bytes)</th>
<th>Receive Queue Size (bytes)</th>
</tr>
</thead>
<tbody>
{{#per_conn_metrics}}
<tr>
<td>{{remote_addr}}</td>
<td>{{num_calls_in_flight}}</td>
<td>{{outbound_queue_size}}</td>
<td>{{socket_stats.rtt}}</td>
<td>{{socket_stats.rttvar}}</td>
<td>{{socket_stats.snd_cwnd}}</td>
<td>{{socket_stats.total_retrans}}</td>
<td>{{socket_stats.pacing_rate}}</td>
<td>{{socket_stats.max_pacing_rate}}</td>
<td>{{socket_stats.bytes_acked}}</td>
<td>{{socket_stats.bytes_received}}</td>
<td>{{socket_stats.segs_out}}</td>
<td>{{socket_stats.segs_in}}</td>
<td>{{socket_stats.send_queue_bytes}}</td>
<td>{{socket_stats.receive_queue_bytes}}</td>
</tr>
{{/per_conn_metrics}}
</tbody>
</table>
<h3>Per connection metrics for KRPC inbound connections</h3>
<table class="table table-bordered table-hover" id="inbound_per_conn_metrics">
<thead>
<tr>
<th>Remote Address</th>
<th># Calls in Flight</th>
<th>Socket RTT (us)</th>
<th>Socket RTT Variance (us)</th>
<th>Sender Congestion Window</th>
<th># Retransmitted Packets</th>
<th>Pacing Rate</th>
<th>Max Pacing Rate</th>
<th>Bytes Acked</th>
<th>Bytes Received</th>
<th>Segments Sent</th>
<th>Segments Received</th>
<th>Send Queue Size (bytes)</th>
<th>Receive Queue Size (bytes)</th>
</tr>
</thead>
<tbody>
{{#inbound_per_conn_metrics}}
<tr>
<td>{{remote_addr}}</td>
<td>{{num_calls_in_flight}}</td>
<td>{{socket_stats.rtt}}</td>
<td>{{socket_stats.rttvar}}</td>
<td>{{socket_stats.snd_cwnd}}</td>
<td>{{socket_stats.total_retrans}}</td>
<td>{{socket_stats.pacing_rate}}</td>
<td>{{socket_stats.max_pacing_rate}}</td>
<td>{{socket_stats.bytes_acked}}</td>
<td>{{socket_stats.bytes_received}}</td>
<td>{{socket_stats.segs_out}}</td>
<td>{{socket_stats.segs_in}}</td>
<td>{{socket_stats.send_queue_bytes}}</td>
<td>{{socket_stats.receive_queue_bytes}}</td>
</tr>
{{/inbound_per_conn_metrics}}
</tbody>
</table>
{{?servers}}
<h2>Impala Thrift RPC Services
<button class="btn btn-warning btn-xs" onClick="reset_all();">
Reset all
</button>
</h2>
<label>
<input type="checkbox" id="show_rw_stats" onClick="toggleRWStats()"/>
<span id="refresh_on">Show Read/Write stats</span>
</label>
{{/servers}}
{{#servers}}
<table width=100%>
<tr>
<td>
<h3><samp>{{name}} </samp>
<button class="btn btn-warning btn-xs" onClick="reset_server('{{name}}');">
Reset stats
</button>
</h3>
</td>
<td align=right>
</td>
</tr>
</table>
<table class='table table-hover table-bordered' id='{{name}}'>
<tr>
<th>Method</th>
<th>Duration summary</th>
<th class="rwstats" style="display:none">Read</th>
<th class="rwstats" style="display:none">Write</th>
<th>In Flight</th>
<th></th>
</tr>
{{#methods}}
<tr>
<td><samp>{{name}}</samp></td>
<td>{{summary}}</td>
<td class="rwstats">{{read}}</td>
<td class="rwstats">{{write}}</td>
<td>{{in_flight}}</td>
<td align="center">
<button class="btn btn-warning btn-xs"
onClick="reset_method('{{server_name}}', '{{name}}');">
Reset
</button>
</td>
</tr>
{{/methods}}
</table>
{{/servers}}
<style>
.rwstats{
}
</style>
<script>
function reset_all() {
var xhr = new XMLHttpRequest();
xhr.open('GET', make_url("/rpcz_reset"), true);
xhr.send();
}
function reset_method(server, method) {
var xhr = new XMLHttpRequest();
xhr.open('GET', make_url("/rpcz_reset?server=" + server + "&method=" + method), true);
xhr.send();
}
function reset_server(server) {
var xhr = new XMLHttpRequest();
xhr.open('GET', make_url("/rpcz_reset?server=" + server), true);
xhr.send();
}
// Update all metrics for services in "servers", which use Impala's old RPC layer.
function update_impala_services(json) {
for (var i = 0; i < json["servers"].length; ++i) {
var tbl_json = json["servers"][i];
var table = document.getElementById(tbl_json["name"]);
if (!table) continue;
// Delete all existing rows, stopping at 1 to save the header
for (var j = table.rows.length - 1; j >= 1; --j) table.deleteRow(j);
tbl_json["methods"].forEach(function(method) {
var row = table.insertRow();
row.insertCell().innerHTML = "<samp>" + method.name + "</samp>";
row.insertCell().innerHTML = method.summary;
cell = row.insertCell()
cell.className= "rwstats";
cell.style.display= getRWDisplay();
cell.innerHTML = method.read;
cell = row.insertCell()
cell.className= "rwstats";
cell.style.display= getRWDisplay();
cell.innerHTML = method.write;
row.insertCell().innerHTML = method.in_flight;
var reset_cell = row.insertCell();
reset_cell.align = "center";
var button = document.createElement("button");
button.className = "btn btn-warning btn-xs";
button.appendChild(document.createTextNode("Reset"));
button.onclick = function() { reset_method(method.server_name, method.name); }
reset_cell.appendChild(button);
});
}
}
// Update all krpc metrics from the "services" member of "json".
function update_krpc_services(json) {
if (!json["services"]) return;
// Update each service
for (var i = 0; i < json["services"].length; ++i) {
var svc_json = json["services"][i];
var svc_name = svc_json["service_name"];
var table = document.getElementById(svc_name + "_metrics");
// Skip updates for unknown services.
if (!table) continue;
// Update service metrics
var keys = ["queue_size", "idle_threads", "mem_usage", "mem_peak",
"rpcs_queue_overflow", "incoming_queue_time"];
for (var j = 0; j < keys.length; ++j) {
var key = keys[j];
var cell = document.getElementById(svc_name + "_" + key);
// Skip update for unknown values.
if (!cell) continue;
cell.innerHTML = svc_json[key];
}
// Update metrics for individual methods.
var num_methods = svc_json["rpc_method_metrics"].length;
for (var j = 0; j < num_methods; ++j) {
var method_json = svc_json["rpc_method_metrics"][j];
var method_name = method_json["method_name"];
// Update all metrics for this method.
var keys = ["handler_latency", "payload_size"];
for (var l = 0; l < keys.length; ++l) {
var key = keys[l];
var cell = $(table).find("." + method_name + "_" + key)[0];
// Skip update for unknown values.
if (!cell) continue;
cell.innerHTML = method_json[key];
}
}
}
}
function update_krpc_conn_metrics_datatable(json) {
var table = $('#per_conn_metrics').DataTable();
if (!json["rpc_use_unix_domain_socket"]) {
var rows = $.map(json["per_conn_metrics"], function(row) {
return [[row["remote_addr"], row["num_calls_in_flight"], row["outbound_queue_size"],
row["socket_stats"]["rtt"] ?? '',
row["socket_stats"]["rttvar"] ?? '',
row["socket_stats"]["snd_cwnd"] ?? '',
row["socket_stats"]["total_retrans"] ?? '',
row["socket_stats"]["pacing_rate"] ?? '',
row["socket_stats"]["max_pacing_rate"] ?? '',
row["socket_stats"]["bytes_acked"] ?? '',
row["socket_stats"]["bytes_received"] ?? '',
row["socket_stats"]["segs_out"] ?? '',
row["socket_stats"]["segs_in"] ?? '',
row["socket_stats"]["send_queue_bytes"] ?? '',
row["socket_stats"]["receive_queue_bytes"] ?? '']];
});
} else {
var rows = $.map(json["per_conn_metrics"], function(row) {
return [[row["remote_addr"], row["num_calls_in_flight"], row["outbound_queue_size"],
'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A',
'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A']];
});
}
table.clear().rows.add(rows).draw();
}
function update_krpc_inbound_conn_metrics_datatable(json) {
var table = $('#inbound_per_conn_metrics').DataTable();
if (!json["rpc_use_unix_domain_socket"]) {
var rows = $.map(json["inbound_per_conn_metrics"], function(row) {
return [[row["remote_addr"], row["num_calls_in_flight"],
row["socket_stats"]["rtt"] ?? '',
row["socket_stats"]["rttvar"] ?? '',
row["socket_stats"]["snd_cwnd"] ?? '',
row["socket_stats"]["total_retrans"] ?? '',
row["socket_stats"]["pacing_rate"] ?? '',
row["socket_stats"]["max_pacing_rate"] ?? '',
row["socket_stats"]["bytes_acked"] ?? '',
row["socket_stats"]["bytes_received"] ?? '',
row["socket_stats"]["segs_out"] ?? '',
row["socket_stats"]["segs_in"] ?? '',
row["socket_stats"]["send_queue_bytes"] ?? '',
row["socket_stats"]["receive_queue_bytes"] ?? '']];
});
} else {
var rows = $.map(json["inbound_per_conn_metrics"], function(row) {
return [[row["remote_addr"], row["num_calls_in_flight"],
'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A',
'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A']];
});
}
table.clear().rows.add(rows).draw();
}
$(document).ready(function() {
table = $('#per_conn_metrics').DataTable({
"order": [[ 0, "asc" ]],
"pageLength": 50
});
});
function refresh() {
var xhr = new XMLHttpRequest();
xhr.responseType = 'text';
xhr.timeout = 60000;
xhr.onload = function(ignored_arg) {
if (xhr.status != 200) return;
var blob = xhr.response;
json = JSON.parse(blob);
update_impala_services(json);
update_krpc_services(json);
update_krpc_conn_metrics_datatable(json);
update_krpc_inbound_conn_metrics_datatable(json);
document.getElementById("last-updated").textContent = new Date();
}
xhr.ontimeout = function() {}
xhr.open('GET', make_url("/rpcz?json"), true);
xhr.send();
}
document.getElementById("last-updated").textContent = new Date();
var intervalId = setInterval(refresh, 1000);
function toggleRefresh() {
if (document.getElementById("toggle").checked === true) {
intervalId = setInterval(refresh, 1000);
document.getElementById("refresh_on").textContent = "Auto-refresh on";
} else {
clearInterval(intervalId);
document.getElementById("refresh_on").textContent = "Auto-refresh off";
}
}
function getRWDisplay() {
if (document.getElementById('show_rw_stats').checked) {
return "";
}
return "none";
}
function toggleRWStats() {
var rwDisplay = getRWDisplay();
for (item of document.getElementsByClassName('rwstats')) {
item.style.display = rwDisplay;
}
}
</script>
{{> www/common-footer.tmpl }}