blob: f4bd6db96dc8d0623b413071a3ed8c7e32905a0e [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.
Example of json received from the impala server
"resource_pools_plain_json": <..the whole json below in text.>
"resource_pools": [
{
"pool_name": "default-pool",
"agg_num_running": 1,
"agg_num_queued": 4,
"agg_mem_reserved": 10382760,
"local_mem_admitted": 10382760,
"local_num_admitted_running": 1,
"local_num_queued": 4,
"local_backend_mem_reserved": 10382760,
"local_backend_mem_usage": 16384,
"pool_max_mem_resources": 10485760,
"pool_max_requests": 10,
"pool_max_queued": 10,
"pool_queue_timeout": 60000,
"max_query_mem_limit": 0,
"min_query_mem_limit": 0,
"clamp_mem_limit_query_option": true,
"max_query_cpu_core_per_node_limit": 8,
"max_query_cpu_core_coordinator_limit": 8,
"wait_time_ms_EMA": 0.0,
"histogram": [
[
0,
0
],
.
.
.
[
127,
0
]
],
"queued_queries": [
{
"query_id": "6f49e509bfa5b347:207d8ef900000000",
"mem_limit": 10382760,
"mem_limit_to_admit": 10382760,
"num_backends": 1
},
{
"query_id": "854f954e79f79d87:18483b9400000000",
"mem_limit": 10382760,
"mem_limit_to_admit": 10382760,
"num_backends": 1
},
{
"query_id": "45421dce8bf5664f:6865a45200000000",
"mem_limit": 10382760,
"mem_limit_to_admit": 10382760,
"num_backends": 1
},
{
"query_id": "e249aecff1bf3372:d5527a2700000000",
"mem_limit": 10382760,
"mem_limit_to_admit": 10382760,
"num_backends": 1
}
],
"head_queued_reason": "Not enough aggregate memory available in pool default-pool with max mem resources 10.00 MB. Needed 9.90 MB but only 100.59 KB was available.",
"running_queries": [
{
"query_id": "b94cf355d6df041c:ba3b91400000000",
"mem_limit": 10382760,
"mem_limit_to_admit": 10382760,
"num_backends": 1
}
]
}
],
"statestore_admission_control_time_since_last_update_ms": 745,
"statestore_update_staleness_detail": "Warning: admission control information from statestore is stale: 745ms since last update was received.",
"get_all_pools": true
-->
{{> www/common-header.tmpl }}
{{?statestore_update_staleness_detail}}
<div class="alert alert-danger" role="alert">
<strong>{{statestore_update_staleness_detail}}</strong>
</div>
{{/statestore_update_staleness_detail}}
<script src='{{ __common__.host-url }}/www/Chart-2.9.4.min.js'></script>
<script type="text/javascript">
window.onload = function() {
renderGraph();
formatMemoryColumns();
};
// Workaround for https://github.com/chartjs/Chart.js/issues/6154, where the last X-axis
// label is always omitted. This function bakes in a lot of assumptions for our chart.
function afterFit(axis) {
const ticks = axis.getTicks();
const widest = axis._labelSizes.widest.width;
const chartWidth = axis.width;
// Apply a rough heuristic for rotation.
const maxFit = Math.trunc(3 * chartWidth / (2 * widest));
// Limit to 20 labels.
const willFit = Math.min(maxFit, 20);
// Ensure first and last are always shown.
const validLabelIndices = new Set();
validLabelIndices.add(0);
validLabelIndices.add(ticks.length - 1);
const numLabels = ticks.length % 2 === 0 ? willFit : willFit - 1;
const interval = ticks.length / (numLabels - 1);
for (let i = 1; i < willFit - 1; i += 1) {
validLabelIndices.add(Math.floor(interval * i));
}
ticks.forEach((tick, index) => {
Object.assign(
tick,
{ label: validLabelIndices.has(index) ? tick.label : null },
);
});
}
// Picks up all the canvas elements associated with each resource pool and renders its
// peak memory usage histogram.
function renderGraph() {
var plainJson = document.getElementById("resource_pools_plain_json");
var json = JSON.parse(plainJson.innerText);
var canvases = document.getElementsByTagName("canvas");
for (var pool_idx = 0; pool_idx < json.length; pool_idx++){
var histogram = json[pool_idx]["peak_mem_usage_histogram"]
var pool_name = json[pool_idx]['pool_name'];
var hist_labels = new Array();
var hist_values = new Array();
for (var i = 0; i < histogram.length; i++) {
var hist_elem = histogram[i];
//hist_labels.push((hist_elem[0]-1) + " - " + hist_elem[0] + " GB");
hist_labels.push((hist_elem[0]+1) + " GB");
hist_values.push(hist_elem[1]);
}
hist_labels[hist_labels.length-1] += " and above"
// Render the bar chart now.
var chart_Data = {
labels: hist_labels,
datasets: [{
label: 'Number of Queries',
backgroundColor: '#2E6595', // Impala logo's color
data: hist_values
}],
};
var ctx = canvases[pool_name].getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: chart_Data,
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Peak Memory per Host'
},
scales: {
xAxes: [{
afterFit: afterFit,
ticks: {
autoSkip: false
}
}]
}
}
});
}
}
// Picks up all the elemets classified as memory and replaces it with pretty printed
// value.
function formatMemoryColumns() {
var cols = document.getElementsByClassName("memory");
for (var idx = 0; idx < cols.length; idx++) {
cols[idx].innerText = formatMemory(cols[idx].innerText);
}
}
var memory_key = [
{'unit': 'B', 'val': 1},
{'unit': 'KB', 'val': 1024},
{'unit': 'MB', 'val': 1048576},
{'unit': 'GB', 'val': 1073741824}
]
// Helper method that takes in a value (in bytes) and outputs its pretty printed value.
function formatMemory(val) {
var mem_bytes = parseInt(val);
for (var idx = memory_key.length - 1; idx >= 0; idx--) {
var result = parseFloat(mem_bytes / memory_key[idx].val);
if (result < 1) continue;
return result.toFixed(2) + " " + memory_key[idx].unit;
}
return "0 B";
}
function reset_all() {
if (!confirm('Are you sure you want to reset stats for all resource pools ?')) return;
var xhr = new XMLHttpRequest();
xhr.onload = function(ignored_arg) {
window.location.reload(true);
}
xhr.open('GET', make_url("/resource_pool_reset"), true);
xhr.send();
}
function reset_method(pool_name) {
if (!confirm('Are you sure you want to reset stats for ' + pool_name +' ?')) return;
var xhr = new XMLHttpRequest();
xhr.onload = function(ignored_arg) {
window.location.reload(true);
}
xhr.open('GET', make_url("/resource_pool_reset?pool_name=" + pool_name), true);
xhr.send();
}
</script>
<h2>Admission Controller
{{?get_all_pools}}
<button class="btn btn-warning btn-xs" onClick="reset_all();">
Reset informational stats for all pools
</button>
{{/get_all_pools}}
</h2>
{{^get_all_pools}}
<p id="show_all_pools" class="lead">
<a href='{{ __common__.host-url }}/admission'> < Show all Resource Pools</a>
</p>
{{/get_all_pools}}
<p class="lead">
This page lists all resource pools to which queries have been submitted
at least once and their corresponding state and statistics.<br>See the
<a href='{{ __common__.host-url }}/backends'>backends</a> debug page for memory admitted and reserved per
backend.
</p>
<p class="lead">
<strong>
Time since last statestore update containing admission control topic state (ms):
</strong>
{{statestore_admission_control_time_since_last_update_ms}}
</p>
{{#resource_pools}}
<div class="container-fluid">
<h3><a href='{{ __common__.host-url }}/admission?pool_name={{pool_name}}'>{{pool_name}}</a></h3>
<h4>Pool Config</h4>
<table class='table table-hover table-border'>
<tr>
<th>Property</th>
<th>Value</th>
</tr>
<tr>
<td>Max memory (cluster wide)</td>
<td class='memory'>{{pool_max_mem_resources}}</td>
</tr>
<tr>
<td>Max concurrent queries</td>
<td>{{pool_max_requests}}</td>
</tr>
<tr>
<td>Max queue size</td>
<td>{{pool_max_queued}}</td>
</tr>
<tr>
<td>Queue Timeout (ms)</td>
<td>{{pool_queue_timeout}}</td>
</tr>
<tr>
<td><b>Min</b> Query MEM_LIMIT range</td>
<td class='memory'>{{min_query_mem_limit}}</td>
</tr>
<tr>
<td><b>Max</b> Query MEM_LIMIT range</td>
<td class='memory'>{{max_query_mem_limit}}</td>
</tr>
<tr>
<td>Clamp MEM_LIMIT query option</td>
<td>{{clamp_mem_limit_query_option}}</td>
</tr>
<tr>
<td>Query CPU core per node</td>
<td>{{max_query_cpu_core_per_node_limit}}</td>
</tr>
<tr>
<td>Query CPU core on coordinator</td>
<td>{{max_query_cpu_core_coordinator_limit}}</td>
</tr>
</table>
<h4>Queued queries in order of being queued (submitted to this coordinator)</h4>
<table class='table table-hover table-border'>
<tr>
<th>Query ID</th>
<th>Memory limit for the executors</th>
<th>Memory admitted on the executors</th>
<th>Memory limit for the coordinator</th>
<th>Memory admitted on the coordinator</th>
<th>Num of backends it will run on</th>
<th>Details</th>
</tr>
{{#queued_queries}}
<tr>
<td>{{query_id}}</td>
<td class='memory'>{{mem_limit}}</td>
<td class='memory'>{{mem_limit_to_admit}}</td>
<td class='memory'>{{coord_mem_limit}}</td>
<td class='memory'>{{coord_mem_to_admit}}</td>
<td>{{num_backends}}</td>
<td><a href='{{ __common__.host-url }}/query_plan?query_id={{query_id}}'>Details</a></td>
</tr>
{{/queued_queries}}
</table>
<h4>Running queries (submitted to this coordinator)</h4>
<table class='table table-hover table-border'>
<tr>
<th>Query ID</th>
<th>Memory limit for the executors</th>
<th>Memory admitted on the executors</th>
<th>Memory limit for the coordinator</th>
<th>Memory admitted on the coordinator</th>
<th>Num of backends it will run on</th>
<th>Details</th>
</tr>
{{#running_queries}}
<tr>
<td>{{query_id}}</td>
<td class='memory'>{{mem_limit}}</td>
<td class='memory'>{{mem_limit_to_admit}}</td>
<td class='memory'>{{coord_mem_limit}}</td>
<td class='memory'>{{coord_mem_to_admit}}</td>
<td>{{num_backends}}</td>
<td><a href='{{ __common__.host-url }}/query_plan?query_id={{query_id}}'>Details</a></td>
</tr>
{{/running_queries}}
</table>
<h4>Pool stats
<button class="btn btn-warning btn-xs" onClick="reset_method('{{pool_name}}');">
Reset informational stats
</button>
</h4>
<table class='table table-hover table-border'>
<tr>
<th>Property</th>
<th>Value</th>
<th>Limit / Max value</th>
</tr>
<tr>
<td>Total queries <b>admitted</b> by this coordinator</td>
<td colspan='2'>{{total_admitted}}</td>
</tr>
<tr>
<td>Total queries <b>rejected</b> by this coordinator</td>
<td colspan='2'>{{total_rejected}}</td>
</tr>
<tr>
<td>Total queries <b>timed out</b> on this coordinator</td>
<td colspan='2'>{{total_timed_out}}</td>
</tr>
<tr>
<td>Queries currently running</td>
<td>{{agg_num_running}}</td>
<td>{{pool_max_requests}}</td>
</tr>
<tr>
<td>Queries currently queued</td>
<td>{{agg_num_queued}}</td>
<td>{{pool_max_queued}}</td>
</tr>
<tr>
<td>Total memory reserved across cluster</td>
<td class='memory'>{{agg_mem_reserved}}</td>
<td class='memory'>{{pool_max_mem_resources}}</td>
</tr>
<tr>
<td>Memory admitted on this coordinator</td>
<td class='memory'>{{local_mem_admitted}}</td>
<td class='memory'>{{pool_max_mem_resources}}</td>
</tr>
<tr>
<td>Queued reason of query at the head of the queue</td>
<td colspan='2'>{{head_queued_reason}}</td>
</tr>
<tr>
<td>Time in queue (exponential moving average)</td>
<td colspan='2'>{{wait_time_ms_ema}} ms</td>
</tr>
<tr>
<td colspan='3'>
<canvas id="{{pool_name}}" style="border:1px solid"></canvas>
</td>
</tr>
</table>
</div>
{{/resource_pools}}
<div id="resource_pools_plain_json" style="display: none;">
{{resource_pools_plain_json}}
</div>
{{> www/common-footer.tmpl }}