@@ -19,6 +19,7 @@ import {
1919 QueryResultData ,
2020} from '../infrastructure/prometheus_scraper' ;
2121import { DataUsageByUser , DataUsageTimeframe } from '../model/metrics' ;
22+ import * as logging from '../infrastructure/logging' ;
2223
2324const PROMETHEUS_RANGE_QUERY_STEP_SECONDS = 5 * 60 ;
2425
@@ -99,61 +100,6 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
99100 return { bytesTransferredByUserId : usage } ;
100101 }
101102
102- private queryCache = new Map < string , { timestamp : number ; result : QueryResultData } > ( ) ;
103-
104- private async promethusClientTimedQuery ( query : string ) {
105- const cacheId = query ;
106-
107- if ( this . queryCache . has ( cacheId ) ) {
108- const cached = this . queryCache . get ( cacheId ) ;
109-
110- if ( cached && cached . timestamp + PROMETHEUS_RANGE_QUERY_STEP_SECONDS * 1000 > Date . now ( ) ) {
111- console . log ( cacheId , 'cache hit' ) ;
112-
113- return cached . result ;
114- }
115- }
116-
117- console . time ( query ) ;
118-
119- const result = await this . prometheusClient . query ( query ) ;
120-
121- this . queryCache . set ( cacheId , { timestamp : Date . now ( ) , result} ) ;
122-
123- console . timeEnd ( query ) ;
124-
125- return result ;
126- }
127-
128- private async promethusClientTimedRangeQuery (
129- query : string ,
130- start : number ,
131- end : number ,
132- step : string
133- ) {
134- const cacheId = `${ query } -${ start } -${ end } -${ step } ` ;
135-
136- if ( this . queryCache . has ( cacheId ) ) {
137- const cached = this . queryCache . get ( cacheId ) ;
138-
139- if ( cached && cached . timestamp + PROMETHEUS_RANGE_QUERY_STEP_SECONDS * 1000 > Date . now ( ) ) {
140- console . log ( cacheId , 'cache hit' ) ;
141-
142- return cached . result ;
143- }
144- }
145-
146- console . time ( cacheId ) ;
147-
148- const result = await this . prometheusClient . queryRange ( query , start , end , step ) ;
149-
150- this . queryCache . set ( cacheId , { timestamp : Date . now ( ) , result} ) ;
151-
152- console . timeEnd ( cacheId ) ;
153-
154- return result ;
155- }
156-
157103 async getServerMetrics ( timeframe : Duration ) : Promise < ServerMetrics > {
158104 const now = new Date ( ) . getTime ( ) / 1000 ;
159105 // We need to calculate consistent start and end times for Prometheus range
@@ -167,6 +113,8 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
167113 Math . ceil ( now / PROMETHEUS_RANGE_QUERY_STEP_SECONDS ) * PROMETHEUS_RANGE_QUERY_STEP_SECONDS ;
168114 const start = end - timeframe . seconds ;
169115
116+ this . prunePrometheusCache ( ) ;
117+
170118 const [
171119 bandwidth ,
172120 bandwidthRange ,
@@ -177,34 +125,34 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
177125 dataTransferredByAccessKeyRange ,
178126 tunnelTimeByAccessKeyRange ,
179127 ] = await Promise . all ( [
180- this . promethusClientTimedQuery (
128+ this . cachedPrometheusClient . query (
181129 `sum(rate(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${ PROMETHEUS_RANGE_QUERY_STEP_SECONDS } s]))`
182130 ) ,
183- this . promethusClientTimedRangeQuery (
131+ this . cachedPrometheusClient . queryRange (
184132 `sum(rate(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${ PROMETHEUS_RANGE_QUERY_STEP_SECONDS } s]))` ,
185133 start ,
186134 end ,
187135 `${ PROMETHEUS_RANGE_QUERY_STEP_SECONDS } s`
188136 ) ,
189- this . promethusClientTimedQuery (
137+ this . cachedPrometheusClient . query (
190138 `sum(increase(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${ timeframe . seconds } s])) by (location, asn, asorg)`
191139 ) ,
192- this . promethusClientTimedQuery (
140+ this . cachedPrometheusClient . query (
193141 `sum(increase(shadowsocks_tunnel_time_seconds_per_location[${ timeframe . seconds } s])) by (location, asn, asorg)`
194142 ) ,
195- this . promethusClientTimedQuery (
143+ this . cachedPrometheusClient . query (
196144 `sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${ timeframe . seconds } s])) by (access_key)`
197145 ) ,
198- this . promethusClientTimedQuery (
146+ this . cachedPrometheusClient . query (
199147 `sum(increase(shadowsocks_tunnel_time_seconds[${ timeframe . seconds } s])) by (access_key)`
200148 ) ,
201- this . promethusClientTimedRangeQuery (
149+ this . cachedPrometheusClient . queryRange (
202150 `sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${ PROMETHEUS_RANGE_QUERY_STEP_SECONDS } s])) by (access_key)` ,
203151 start ,
204152 end ,
205153 `${ PROMETHEUS_RANGE_QUERY_STEP_SECONDS } s`
206154 ) ,
207- this . promethusClientTimedRangeQuery (
155+ this . cachedPrometheusClient . queryRange (
208156 `sum(increase(shadowsocks_tunnel_time_seconds[${ PROMETHEUS_RANGE_QUERY_STEP_SECONDS } s])) by (access_key)` ,
209157 start ,
210158 end ,
@@ -287,6 +235,41 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
287235 accessKeys : Array . from ( accessKeyMap . values ( ) ) ,
288236 } ;
289237 }
238+
239+ private prometheusCache = new Map < string , { timestamp : number ; result : QueryResultData } > ( ) ;
240+
241+ private get cachedPrometheusClient ( ) {
242+ return new Proxy ( this . prometheusClient , {
243+ get : ( target , prop ) => {
244+ if ( typeof target [ prop ] !== 'function' ) {
245+ return target [ prop ] ;
246+ }
247+
248+ return async ( query , ...args ) => {
249+ const cacheId = `${ String ( prop ) } : ${ query } (args: ${ args . join ( ', ' ) } ))` ;
250+
251+ if ( this . prometheusCache . has ( cacheId ) ) {
252+ return this . prometheusCache . get ( cacheId ) . result ;
253+ }
254+
255+ const result = await ( target [ prop ] as Function ) ( query , ...args ) ;
256+
257+ this . prometheusCache . set ( cacheId , { timestamp : Date . now ( ) , result} ) ;
258+
259+ return result ;
260+ } ;
261+ } ,
262+ } ) ;
263+ }
264+
265+ private prunePrometheusCache ( ) {
266+ const now = Date . now ( ) ;
267+ for ( const [ key , value ] of this . prometheusCache ) {
268+ if ( now - value . timestamp > PROMETHEUS_RANGE_QUERY_STEP_SECONDS * 1000 ) {
269+ this . prometheusCache . delete ( key ) ;
270+ }
271+ }
272+ }
290273}
291274
292275function getServerMetricsLocationEntry (
0 commit comments