From 8f13b902fb657a7971cf8cd43e50e2ae8eeb99fb Mon Sep 17 00:00:00 2001 From: sbruens Date: Wed, 12 Feb 2025 12:11:37 -0500 Subject: [PATCH 1/2] feat(server): use `rate()` instead of `increase()` for bandwidth calculations --- src/shadowbox/server/manager_metrics.spec.ts | 28 +++++++-------- src/shadowbox/server/manager_metrics.ts | 36 +++++++++----------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/shadowbox/server/manager_metrics.spec.ts b/src/shadowbox/server/manager_metrics.spec.ts index 33931e51b..1808d68b3 100644 --- a/src/shadowbox/server/manager_metrics.spec.ts +++ b/src/shadowbox/server/manager_metrics.spec.ts @@ -41,7 +41,7 @@ describe('PrometheusManagerMetrics', () => { const managerMetrics = new PrometheusManagerMetrics( new QueryMapPrometheusClient( { - 'sum(increase(shadowsocks_data_bytes_per_location{dir=~"ct"}[300s]))': { + 'sum(rate(shadowsocks_data_bytes_per_location{dir=~"ct"}[300s]))': { resultType: 'vector', result: [ { @@ -106,7 +106,7 @@ describe('PrometheusManagerMetrics', () => { }, }, { - 'sum(increase(shadowsocks_data_bytes_per_location{dir=~"ct"}[300s]))': { + 'sum(rate(shadowsocks_data_bytes_per_location{dir=~"ct"}[300s]))': { resultType: 'matrix', result: [ { @@ -161,12 +161,12 @@ describe('PrometheusManagerMetrics', () => { "tunnelTime": { "seconds": 1000 }, - "dataTransferred": { - "total": { - "bytes": 1000 - }, + "bandwidth": { "current": { - "bytes": 1234 + "data": { + "bytes": 1234 + }, + "timestamp": 1739284734 }, "peak": { "data": { @@ -216,7 +216,7 @@ describe('PrometheusManagerMetrics', () => { const managerMetrics = new PrometheusManagerMetrics( new QueryMapPrometheusClient( { - 'sum(increase(shadowsocks_data_bytes_per_location{dir=~"ct"}[300s]))': { + 'sum(rate(shadowsocks_data_bytes_per_location{dir=~"ct"}[300s]))': { resultType: 'vector', result: [ { @@ -279,7 +279,7 @@ describe('PrometheusManagerMetrics', () => { }, }, { - 'sum(increase(shadowsocks_data_bytes_per_location{dir=~"ct"}[300s]))': { + 'sum(rate(shadowsocks_data_bytes_per_location{dir=~"ct"}[300s]))': { resultType: 'matrix', result: [ { @@ -334,12 +334,12 @@ describe('PrometheusManagerMetrics', () => { "tunnelTime": { "seconds": 1000 }, - "dataTransferred": { - "total": { - "bytes": 1000 - }, + "bandwidth": { "current": { - "bytes": 1234 + "data": { + "bytes": 1234 + }, + "timestamp": 1739284734 }, "peak": { "data": { diff --git a/src/shadowbox/server/manager_metrics.ts b/src/shadowbox/server/manager_metrics.ts index 1f372fdde..c45e7e192 100644 --- a/src/shadowbox/server/manager_metrics.ts +++ b/src/shadowbox/server/manager_metrics.ts @@ -41,14 +41,13 @@ interface ConnectionStats { } interface BandwidthStats { - total: Data; - current: Data; + current: TimedData; peak: TimedData; } interface ServerMetricsServerEntry { tunnelTime: Duration; - dataTransferred: BandwidthStats; + bandwidth: BandwidthStats; locations: ServerMetricsLocationEntry[]; } @@ -113,8 +112,8 @@ export class PrometheusManagerMetrics implements ManagerMetrics { const start = end - timeframe.seconds; const [ - totalDataTransferred, - totalDataTransferredRange, + bandwidth, + bandwidthRange, dataTransferredByLocation, tunnelTimeByLocation, dataTransferredByAccessKey, @@ -123,10 +122,10 @@ export class PrometheusManagerMetrics implements ManagerMetrics { tunnelTimeByAccessKeyRange, ] = await Promise.all([ this.prometheusClient.query( - `sum(increase(shadowsocks_data_bytes_per_location{dir=~"ct"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))` + `sum(rate(shadowsocks_data_bytes_per_location{dir=~"ct"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))` ), this.prometheusClient.queryRange( - `sum(increase(shadowsocks_data_bytes_per_location{dir=~"ct"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))`, + `sum(rate(shadowsocks_data_bytes_per_location{dir=~"ct"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))`, start, end, `${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s` @@ -159,25 +158,26 @@ export class PrometheusManagerMetrics implements ManagerMetrics { const serverMetrics: ServerMetricsServerEntry = { tunnelTime: {seconds: 0}, - dataTransferred: { - total: {bytes: 0}, - current: {bytes: 0}, + bandwidth: { + current: {data: {bytes: 0}, timestamp: null}, peak: {data: {bytes: 0}, timestamp: null}, }, locations: [], }; - for (const result of totalDataTransferred.result) { - const bytes = result.value ? parseFloat(result.value[1]) : 0; - serverMetrics.dataTransferred.current.bytes = bytes; + for (const result of bandwidth.result) { + if (result.value) { + serverMetrics.bandwidth.current.data.bytes = parseFloat(result.value[1]); + serverMetrics.bandwidth.current.timestamp = result.value[0]; + } break; // There should only be one result. } - for (const result of totalDataTransferredRange.result) { + for (const result of bandwidthRange.result) { const peakDataTransferred = findPeak(result.values ?? []); if (peakDataTransferred !== null) { const peakValue = parseFloat(peakDataTransferred[1]); if (peakValue > 0) { - serverMetrics.dataTransferred.peak.data.bytes = peakValue; - serverMetrics.dataTransferred.peak.timestamp = Math.min(now, peakDataTransferred[0]); + serverMetrics.bandwidth.peak.data.bytes = peakValue; + serverMetrics.bandwidth.peak.timestamp = Math.min(now, peakDataTransferred[0]); } } break; // There should only be one result. @@ -192,9 +192,7 @@ export class PrometheusManagerMetrics implements ManagerMetrics { } for (const result of dataTransferredByLocation.result) { const entry = getServerMetricsLocationEntry(locationMap, result.metric); - const bytes = result.value ? parseFloat(result.value[1]) : 0; - entry.dataTransferred.bytes = bytes; - serverMetrics.dataTransferred.total.bytes += bytes; + entry.dataTransferred.bytes = result.value ? parseFloat(result.value[1]) : 0; } serverMetrics.locations = Array.from(locationMap.values()); From 535d5fad4810fcf01fb80b4106982c8c61ae4939 Mon Sep 17 00:00:00 2001 From: sbruens Date: Wed, 12 Feb 2025 12:16:22 -0500 Subject: [PATCH 2/2] Add total data transferred a separate top-level metric so we don't have to calculate it client-side. --- src/shadowbox/server/manager_metrics.spec.ts | 6 ++++++ src/shadowbox/server/manager_metrics.ts | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/shadowbox/server/manager_metrics.spec.ts b/src/shadowbox/server/manager_metrics.spec.ts index 1808d68b3..4532224f9 100644 --- a/src/shadowbox/server/manager_metrics.spec.ts +++ b/src/shadowbox/server/manager_metrics.spec.ts @@ -161,6 +161,9 @@ describe('PrometheusManagerMetrics', () => { "tunnelTime": { "seconds": 1000 }, + "dataTransferred": { + "bytes": 1000 + }, "bandwidth": { "current": { "data": { @@ -334,6 +337,9 @@ describe('PrometheusManagerMetrics', () => { "tunnelTime": { "seconds": 1000 }, + "dataTransferred": { + "bytes": 1000 + }, "bandwidth": { "current": { "data": { diff --git a/src/shadowbox/server/manager_metrics.ts b/src/shadowbox/server/manager_metrics.ts index c45e7e192..5c07dbe13 100644 --- a/src/shadowbox/server/manager_metrics.ts +++ b/src/shadowbox/server/manager_metrics.ts @@ -47,6 +47,7 @@ interface BandwidthStats { interface ServerMetricsServerEntry { tunnelTime: Duration; + dataTransferred: Data; bandwidth: BandwidthStats; locations: ServerMetricsLocationEntry[]; } @@ -158,6 +159,7 @@ export class PrometheusManagerMetrics implements ManagerMetrics { const serverMetrics: ServerMetricsServerEntry = { tunnelTime: {seconds: 0}, + dataTransferred: {bytes: 0}, bandwidth: { current: {data: {bytes: 0}, timestamp: null}, peak: {data: {bytes: 0}, timestamp: null}, @@ -192,7 +194,9 @@ export class PrometheusManagerMetrics implements ManagerMetrics { } for (const result of dataTransferredByLocation.result) { const entry = getServerMetricsLocationEntry(locationMap, result.metric); - entry.dataTransferred.bytes = result.value ? parseFloat(result.value[1]) : 0; + const bytes = result.value ? parseFloat(result.value[1]) : 0; + entry.dataTransferred.bytes = bytes; + serverMetrics.dataTransferred.bytes += bytes; } serverMetrics.locations = Array.from(locationMap.values());