mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-09-27 14:02:38 +02:00
Reduced the performance graph size
Reduced resolution of data: - Last 30 days: Full resolution (1 per minute) - Last 60 - 30 days: 1 per 5 minutes - 60+ days old: 1 per 20 minutes Effect: - Reduced /v1/graphs?type=performance size from 21 MB to 9.15 MB (126k rows in database) Added new endpoint /v1/graphs?type=optimizedPerformance that doesn't parse series separately - Sends a single array of arrays instead of one array for each series - Added a parseDataSeries to graphs.js that translates the data Effect: - Reduced from 9.15 MB to 3.35 MB - Moved some workload to the browser Affects issues: - Fixed #1622
This commit is contained in:
parent
f14dfe7a7c
commit
ccd492c052
@ -249,4 +249,29 @@ public class TPSMutator {
|
||||
tpsData.sort(new TPSComparator());
|
||||
return Optional.of(tpsData.get(tpsData.size() - 1));
|
||||
}
|
||||
|
||||
public Number[][] toArrays(boolean displayGaps) {
|
||||
List<Number[]> arrays = new ArrayList<>();
|
||||
Long lastX = null;
|
||||
for (TPS tps : tpsData) {
|
||||
long date = tps.getDate();
|
||||
if (displayGaps && lastX != null && date - lastX > TimeUnit.MINUTES.toMillis(3L)) {
|
||||
addMissingPoints(arrays, lastX, date);
|
||||
}
|
||||
lastX = date;
|
||||
|
||||
arrays.add(tps.toArray());
|
||||
}
|
||||
return arrays.toArray(new Number[0][]);
|
||||
}
|
||||
|
||||
private void addMissingPoints(List<Number[]> arrays, Long lastX, long date) {
|
||||
long iterate = lastX + TimeUnit.MINUTES.toMillis(1L);
|
||||
while (iterate < date) {
|
||||
Number[] entry = new Number[7];
|
||||
entry[0] = iterate;
|
||||
arrays.add(entry);
|
||||
iterate += TimeUnit.MINUTES.toMillis(30L);
|
||||
}
|
||||
}
|
||||
}
|
@ -80,10 +80,7 @@ public class GraphJSONCreator {
|
||||
public String performanceGraphJSON(UUID serverUUID) {
|
||||
Database db = dbSystem.getDatabase();
|
||||
LineGraphFactory lineGraphs = graphs.line();
|
||||
long now = System.currentTimeMillis();
|
||||
long halfYearAgo = now - TimeUnit.DAYS.toMillis(180L);
|
||||
TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(serverUUID)))
|
||||
.filterDataBetween(halfYearAgo, now);
|
||||
TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(serverUUID)));
|
||||
return '{' +
|
||||
"\"playersOnline\":" + lineGraphs.playersOnlineGraph(tpsMutator).toHighChartsSeries() +
|
||||
",\"tps\":" + lineGraphs.tpsGraph(tpsMutator).toHighChartsSeries() +
|
||||
@ -109,6 +106,33 @@ public class GraphJSONCreator {
|
||||
"}}";
|
||||
}
|
||||
|
||||
public Map<String, Object> optimizedPerformanceGraphJSON(UUID serverUUID) {
|
||||
Database db = dbSystem.getDatabase();
|
||||
TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(serverUUID)));
|
||||
Number[][] values = tpsMutator.toArrays(config.isTrue(DisplaySettings.GAPS_IN_GRAPH_DATA));
|
||||
|
||||
return Maps.builder(String.class, Object.class)
|
||||
.put("keys", new String[]{"date", "playersOnline", "tps", "cpu", "ram", "entities", "chunks", "disk"})
|
||||
.put("values", values)
|
||||
.put("colors", Maps.builder(String.class, Object.class)
|
||||
.put("playersOnline", theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE))
|
||||
.put("cpu", theme.getValue(ThemeVal.GRAPH_CPU))
|
||||
.put("ram", theme.getValue(ThemeVal.GRAPH_RAM))
|
||||
.put("entities", theme.getValue(ThemeVal.GRAPH_ENTITIES))
|
||||
.put("chunks", theme.getValue(ThemeVal.GRAPH_CHUNKS))
|
||||
.put("low", theme.getValue(ThemeVal.GRAPH_TPS_LOW))
|
||||
.put("med", theme.getValue(ThemeVal.GRAPH_TPS_MED))
|
||||
.put("high", theme.getValue(ThemeVal.GRAPH_TPS_HIGH))
|
||||
.build())
|
||||
.put("zones", Maps.builder(String.class, Object.class)
|
||||
.put("tpsThresholdMed", config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_MED))
|
||||
.put("tpsThresholdHigh", config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_HIGH))
|
||||
.put("diskThresholdMed", config.get(DisplaySettings.GRAPH_DISK_THRESHOLD_MED))
|
||||
.put("diskThresholdHigh", config.get(DisplaySettings.GRAPH_DISK_THRESHOLD_HIGH))
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
public String playersOnlineGraph(UUID serverUUID) {
|
||||
Database db = dbSystem.getDatabase();
|
||||
long now = System.currentTimeMillis();
|
||||
|
@ -30,6 +30,7 @@ public enum DataID {
|
||||
KILLS,
|
||||
PING_TABLE,
|
||||
GRAPH_PERFORMANCE,
|
||||
GRAPH_OPTIMIZED_PERFORMANCE,
|
||||
GRAPH_ONLINE,
|
||||
GRAPH_UNIQUE_NEW,
|
||||
GRAPH_HOURLY_UNIQUE_NEW,
|
||||
|
@ -88,6 +88,8 @@ public class GraphsJSONResolver implements Resolver {
|
||||
switch (type) {
|
||||
case "performance":
|
||||
return DataID.GRAPH_PERFORMANCE;
|
||||
case "optimizedPerformance":
|
||||
return DataID.GRAPH_OPTIMIZED_PERFORMANCE;
|
||||
case "playersOnline":
|
||||
return DataID.GRAPH_ONLINE;
|
||||
case "uniqueAndNew":
|
||||
@ -117,6 +119,8 @@ public class GraphsJSONResolver implements Resolver {
|
||||
switch (id) {
|
||||
case GRAPH_PERFORMANCE:
|
||||
return graphJSON.performanceGraphJSON(serverUUID);
|
||||
case GRAPH_OPTIMIZED_PERFORMANCE:
|
||||
return graphJSON.optimizedPerformanceGraphJSON(serverUUID);
|
||||
case GRAPH_ONLINE:
|
||||
return graphJSON.playersOnlineGraph(serverUUID);
|
||||
case GRAPH_UNIQUE_NEW:
|
||||
|
@ -168,4 +168,17 @@ public class TPS implements DateHolder {
|
||||
"chunksLoaded=" + chunksLoaded + ", " +
|
||||
"freeDiskSpace=" + freeDiskSpace + '}';
|
||||
}
|
||||
|
||||
public Number[] toArray() {
|
||||
return new Number[]{
|
||||
getDate(),
|
||||
getPlayers(),
|
||||
getTicksPerSecond(),
|
||||
getCPUUsage(),
|
||||
getUsedMemory(),
|
||||
getEntityCount(),
|
||||
getChunksLoaded(),
|
||||
getFreeDiskSpace()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
import static com.djrapitops.plan.storage.database.sql.tables.TPSTable.*;
|
||||
@ -45,27 +46,72 @@ public class TPSQueries {
|
||||
}
|
||||
|
||||
public static Query<List<TPS>> fetchTPSDataOfServer(UUID serverUUID) {
|
||||
String sql = Select.all(TABLE_NAME)
|
||||
.where(SERVER_ID + "=" + ServerTable.STATEMENT_SELECT_SERVER_ID)
|
||||
.toString();
|
||||
return db -> {
|
||||
String selectLowestResolution = SELECT +
|
||||
"MIN(t." + DATE + ") as " + DATE + ',' +
|
||||
"MIN(t." + TPS + ") as " + TPS + ',' +
|
||||
"MAX(t." + PLAYERS_ONLINE + ") as " + PLAYERS_ONLINE + ',' +
|
||||
"MAX(t." + RAM_USAGE + ") as " + RAM_USAGE + ',' +
|
||||
"MAX(t." + CPU_USAGE + ") as " + CPU_USAGE + ',' +
|
||||
"MAX(t." + ENTITIES + ") as " + ENTITIES + ',' +
|
||||
"MAX(t." + CHUNKS + ") as " + CHUNKS + ',' +
|
||||
"MAX(t." + FREE_DISK + ") as " + FREE_DISK +
|
||||
FROM + TABLE_NAME + " t" +
|
||||
WHERE + SERVER_ID + "=" + ServerTable.STATEMENT_SELECT_SERVER_ID +
|
||||
AND + DATE + "<?" +
|
||||
GROUP_BY + "FLOOR(" + DATE + "/?)";
|
||||
String selectLowerResolution = SELECT +
|
||||
"MIN(t." + DATE + ") as " + DATE + ',' +
|
||||
"MIN(t." + TPS + ") as " + TPS + ',' +
|
||||
"MAX(t." + PLAYERS_ONLINE + ") as " + PLAYERS_ONLINE + ',' +
|
||||
"MAX(t." + RAM_USAGE + ") as " + RAM_USAGE + ',' +
|
||||
"MAX(t." + CPU_USAGE + ") as " + CPU_USAGE + ',' +
|
||||
"MAX(t." + ENTITIES + ") as " + ENTITIES + ',' +
|
||||
"MAX(t." + CHUNKS + ") as " + CHUNKS + ',' +
|
||||
"MAX(t." + FREE_DISK + ") as " + FREE_DISK +
|
||||
FROM + TABLE_NAME + " t" +
|
||||
WHERE + SERVER_ID + "=" + ServerTable.STATEMENT_SELECT_SERVER_ID +
|
||||
AND + DATE + ">=?" +
|
||||
AND + DATE + "<?" +
|
||||
GROUP_BY + "FLOOR(" + DATE + "/?)";
|
||||
String selectNormalResolution = SELECT +
|
||||
DATE + ',' + TPS + ',' + PLAYERS_ONLINE + ',' +
|
||||
RAM_USAGE + ',' + CPU_USAGE + ',' + ENTITIES + ',' + CHUNKS + ',' + FREE_DISK +
|
||||
FROM + TABLE_NAME +
|
||||
WHERE + SERVER_ID + "=" + ServerTable.STATEMENT_SELECT_SERVER_ID +
|
||||
AND + DATE + ">=?";
|
||||
|
||||
return new QueryStatement<List<TPS>>(sql, 50000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
}
|
||||
String sql = selectLowestResolution +
|
||||
UNION + selectLowerResolution +
|
||||
UNION + selectNormalResolution +
|
||||
ORDER_BY + DATE;
|
||||
|
||||
@Override
|
||||
public List<TPS> processResults(ResultSet set) throws SQLException {
|
||||
List<TPS> data = new ArrayList<>();
|
||||
while (set.next()) {
|
||||
|
||||
com.djrapitops.plan.gathering.domain.TPS tps = extractTPS(set);
|
||||
|
||||
data.add(tps);
|
||||
return db.query(new QueryStatement<List<TPS>>(sql, 50000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
long now = System.currentTimeMillis();
|
||||
long lowestResolution = TimeUnit.MINUTES.toMillis(20);
|
||||
long lowResolution = TimeUnit.MINUTES.toMillis(5);
|
||||
statement.setString(1, serverUUID.toString());
|
||||
statement.setLong(2, now - TimeUnit.DAYS.toMillis(60));
|
||||
statement.setLong(3, lowestResolution);
|
||||
statement.setString(4, serverUUID.toString());
|
||||
statement.setLong(5, now - TimeUnit.DAYS.toMillis(60));
|
||||
statement.setLong(6, now - TimeUnit.DAYS.toMillis(30));
|
||||
statement.setLong(7, lowResolution);
|
||||
statement.setString(8, serverUUID.toString());
|
||||
statement.setLong(9, now - TimeUnit.DAYS.toMillis(30));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TPS> processResults(ResultSet set) throws SQLException {
|
||||
List<TPS> data = new ArrayList<>();
|
||||
while (set.next()) {
|
||||
data.add(extractTPS(set));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -182,6 +182,29 @@ function onlineActivityCalendar(id, event_data, firstDay) {
|
||||
window.calendars.online_activity.render();
|
||||
}
|
||||
|
||||
function mapToDataSeries(performanceData) {
|
||||
const dataSeries = {
|
||||
playersOnline: [],
|
||||
tps: [],
|
||||
cpu: [],
|
||||
ram: [],
|
||||
entities: [],
|
||||
chunks: [],
|
||||
disk: []
|
||||
};
|
||||
for (const entry of performanceData) {
|
||||
const date = entry[0];
|
||||
dataSeries.playersOnline.push([date, entry[1]]);
|
||||
dataSeries.tps.push([date, entry[2]]);
|
||||
dataSeries.cpu.push([date, entry[3]]);
|
||||
dataSeries.ram.push([date, entry[4]]);
|
||||
dataSeries.entities.push([date, entry[5]]);
|
||||
dataSeries.chunks.push([date, entry[6]]);
|
||||
dataSeries.disk.push([date, entry[7]]);
|
||||
}
|
||||
return dataSeries;
|
||||
}
|
||||
|
||||
function performanceChart(id, playersOnlineSeries, tpsSeries, cpuSeries, ramSeries, entitySeries, chunkSeries) {
|
||||
graphs.push(Highcharts.stockChart(id, {
|
||||
rangeSelector: {
|
||||
|
@ -1330,9 +1330,9 @@
|
||||
}
|
||||
};
|
||||
|
||||
jsonRequest("../v1/graph?type=performance&server=${serverUUID}", function (json, error) {
|
||||
jsonRequest("../v1/graph?type=optimizedPerformance&server=${serverUUID}", function (json, error) {
|
||||
if (json) {
|
||||
var zones = {
|
||||
const zones = {
|
||||
tps: [{
|
||||
value: json.zones.tpsThresholdMed,
|
||||
color: json.colors.low
|
||||
@ -1354,51 +1354,52 @@
|
||||
color: json.colors.high
|
||||
}]
|
||||
};
|
||||
var series = {
|
||||
const dataSeries = mapToDataSeries(json.values);
|
||||
const series = {
|
||||
playersOnline: {
|
||||
name: s.name.playersOnline, type: s.type.areaSpline, tooltip: s.tooltip.zeroDecimals,
|
||||
data: json.playersOnline, color: json.colors.playersOnline, yAxis: 0
|
||||
data: dataSeries.playersOnline, color: json.colors.playersOnline, yAxis: 0
|
||||
},
|
||||
tps: {
|
||||
name: s.name.tps, type: s.type.spline, color: json.colors.high,
|
||||
zones: zones.tps, tooltip: s.tooltip.twoDecimals, data: json.tps,
|
||||
zones: zones.tps, tooltip: s.tooltip.twoDecimals, data: dataSeries.tps,
|
||||
yAxis: 1
|
||||
},
|
||||
cpu: {
|
||||
name: s.name.cpu, type: s.type.spline, tooltip: s.tooltip.twoDecimals,
|
||||
data: json.cpu, color: json.colors.cpu, yAxis: 2
|
||||
data: dataSeries.cpu, color: json.colors.cpu, yAxis: 2
|
||||
},
|
||||
cpu_alt: {
|
||||
name: s.name.cpu, type: s.type.spline, tooltip: s.tooltip.twoDecimals,
|
||||
data: json.cpu, color: json.colors.cpu, yAxis: 1
|
||||
data: dataSeries.cpu, color: json.colors.cpu, yAxis: 1
|
||||
},
|
||||
ram: {
|
||||
name: s.name.ram, type: s.type.spline, tooltip: s.tooltip.zeroDecimals,
|
||||
data: json.ram, color: json.colors.ram, yAxis: 3
|
||||
data: dataSeries.ram, color: json.colors.ram, yAxis: 3
|
||||
},
|
||||
ram_alt: {
|
||||
name: s.name.ram, type: s.type.spline, tooltip: s.tooltip.zeroDecimals,
|
||||
data: json.ram, color: json.colors.ram, yAxis: 2
|
||||
data: dataSeries.ram, color: json.colors.ram, yAxis: 2
|
||||
},
|
||||
entities: {
|
||||
name: s.name.entities, type: s.type.spline, tooltip: s.tooltip.zeroDecimals,
|
||||
data: json.entities, color: json.colors.entities, yAxis: 4
|
||||
data: dataSeries.entities, color: json.colors.entities, yAxis: 4
|
||||
},
|
||||
entities_alt: {
|
||||
name: s.name.entities, type: s.type.spline, tooltip: s.tooltip.zeroDecimals,
|
||||
data: json.entities, color: json.colors.entities, yAxis: 1
|
||||
data: dataSeries.entities, color: json.colors.entities, yAxis: 1
|
||||
},
|
||||
chunks: {
|
||||
name: s.name.chunks, type: s.type.spline, tooltip: s.tooltip.zeroDecimals,
|
||||
data: json.chunks, color: json.colors.chunks, yAxis: 5
|
||||
data: dataSeries.chunks, color: json.colors.chunks, yAxis: 5
|
||||
},
|
||||
chunks_alt: {
|
||||
name: s.name.chunks, type: s.type.spline, tooltip: s.tooltip.zeroDecimals,
|
||||
data: json.chunks, color: json.colors.chunks, yAxis: 2
|
||||
data: dataSeries.chunks, color: json.colors.chunks, yAxis: 2
|
||||
},
|
||||
disk: {
|
||||
name: s.name.disk, type: s.type.spline, color: json.colors.high,
|
||||
zones: zones.disk, tooltip: s.tooltip.zeroDecimals, data: json.disk
|
||||
zones: zones.disk, tooltip: s.tooltip.zeroDecimals, data: dataSeries.disk
|
||||
}
|
||||
};
|
||||
playersChart('playersOnlineChart', series.playersOnline, 2);
|
||||
|
Loading…
Reference in New Issue
Block a user