Skip to content

Commit d262f52

Browse files
feat: cache recent prometheus queries in memory (#1643)
* [DO NOT MERGE] prometheus query timer * add cache layer * add query result data * ready for a look * remove logger
1 parent 15a9e54 commit d262f52

File tree

1 file changed

+46
-8
lines changed

1 file changed

+46
-8
lines changed

src/shadowbox/server/manager_metrics.ts

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
PrometheusClient,
1717
PrometheusMetric,
1818
PrometheusValue,
19+
QueryResultData,
1920
} from '../infrastructure/prometheus_scraper';
2021
import {DataUsageByUser, DataUsageTimeframe} from '../model/metrics';
2122

@@ -111,6 +112,8 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
111112
Math.ceil(now / PROMETHEUS_RANGE_QUERY_STEP_SECONDS) * PROMETHEUS_RANGE_QUERY_STEP_SECONDS;
112113
const start = end - timeframe.seconds;
113114

115+
this.prunePrometheusCache();
116+
114117
const [
115118
bandwidth,
116119
bandwidthRange,
@@ -121,34 +124,34 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
121124
dataTransferredByAccessKeyRange,
122125
tunnelTimeByAccessKeyRange,
123126
] = await Promise.all([
124-
this.prometheusClient.query(
127+
this.cachedPrometheusClient.query(
125128
`sum(rate(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))`
126129
),
127-
this.prometheusClient.queryRange(
130+
this.cachedPrometheusClient.queryRange(
128131
`sum(rate(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))`,
129132
start,
130133
end,
131134
`${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s`
132135
),
133-
this.prometheusClient.query(
136+
this.cachedPrometheusClient.query(
134137
`sum(increase(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${timeframe.seconds}s])) by (location, asn, asorg)`
135138
),
136-
this.prometheusClient.query(
139+
this.cachedPrometheusClient.query(
137140
`sum(increase(shadowsocks_tunnel_time_seconds_per_location[${timeframe.seconds}s])) by (location, asn, asorg)`
138141
),
139-
this.prometheusClient.query(
142+
this.cachedPrometheusClient.query(
140143
`sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${timeframe.seconds}s])) by (access_key)`
141144
),
142-
this.prometheusClient.query(
145+
this.cachedPrometheusClient.query(
143146
`sum(increase(shadowsocks_tunnel_time_seconds[${timeframe.seconds}s])) by (access_key)`
144147
),
145-
this.prometheusClient.queryRange(
148+
this.cachedPrometheusClient.queryRange(
146149
`sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s])) by (access_key)`,
147150
start,
148151
end,
149152
`${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s`
150153
),
151-
this.prometheusClient.queryRange(
154+
this.cachedPrometheusClient.queryRange(
152155
`sum(increase(shadowsocks_tunnel_time_seconds[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s])) by (access_key)`,
153156
start,
154157
end,
@@ -231,6 +234,41 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
231234
accessKeys: Array.from(accessKeyMap.values()),
232235
};
233236
}
237+
238+
private prometheusCache = new Map<string, {timestamp: number; result: QueryResultData}>();
239+
240+
private get cachedPrometheusClient() {
241+
return new Proxy(this.prometheusClient, {
242+
get: (target, prop) => {
243+
if (typeof target[prop] !== 'function') {
244+
return target[prop];
245+
}
246+
247+
return async (query, ...args) => {
248+
const cacheId = `${String(prop)}: ${query} (args: ${args.join(', ')}))`;
249+
250+
if (this.prometheusCache.has(cacheId)) {
251+
return this.prometheusCache.get(cacheId).result;
252+
}
253+
254+
const result = await (target[prop] as Function)(query, ...args);
255+
256+
this.prometheusCache.set(cacheId, {timestamp: Date.now(), result});
257+
258+
return result;
259+
};
260+
},
261+
});
262+
}
263+
264+
private prunePrometheusCache() {
265+
const now = Date.now();
266+
for (const [key, value] of this.prometheusCache) {
267+
if (now - value.timestamp > PROMETHEUS_RANGE_QUERY_STEP_SECONDS * 1000) {
268+
this.prometheusCache.delete(key);
269+
}
270+
}
271+
}
234272
}
235273

236274
function getServerMetricsLocationEntry(

0 commit comments

Comments
 (0)