From 33bba9509939dae568c6b6e49b9871974cdcf98d Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Wed, 26 Oct 2022 10:49:20 +0200 Subject: [PATCH] Reduce memory utilization in downstream projects creating multiple Alertmanager instances (#3114) * Reduce memory utilization in downstream projects creating multiple Alertmanager instances Signed-off-by: Marco Pracucci --- api/v2/api.go | 21 +++++++++++++-------- go.mod | 4 ++-- go.sum | 4 ++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/api/v2/api.go b/api/v2/api.go index ba1f57ba..b272322c 100644 --- a/api/v2/api.go +++ b/api/v2/api.go @@ -23,6 +23,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" + "github.com/go-openapi/analysis" "github.com/go-openapi/loads" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" @@ -101,7 +102,7 @@ func NewAPI( } // Load embedded swagger file. - swaggerSpec, err := getSwaggerSpec() + swaggerSpec, swaggerSpecAnalysis, err := getSwaggerSpec() if err != nil { return nil, err } @@ -113,7 +114,9 @@ func NewAPI( // the API itself via RoutesHandler. See: // https://github.com/go-swagger/go-swagger/issues/1779 openAPI.Middleware = func(b middleware.Builder) http.Handler { - return middleware.Spec("", swaggerSpec.Raw(), openAPI.Context().RoutesHandler(b)) + // Manually create the context so that we can use the singleton swaggerSpecAnalysis. + swaggerContext := middleware.NewRoutableContextWithAnalyzedSpec(swaggerSpec, swaggerSpecAnalysis, openAPI, nil) + return middleware.Spec("", swaggerSpec.Raw(), swaggerContext.RoutesHandler(b)) } openAPI.AlertGetAlertsHandler = alert_ops.GetAlertsHandlerFunc(api.getAlertsHandler) @@ -674,29 +677,31 @@ func parseFilter(filter []string) ([]*labels.Matcher, error) { } var ( - swaggerSpecCacheMx sync.Mutex - swaggerSpecCache *loads.Document + swaggerSpecCacheMx sync.Mutex + swaggerSpecCache *loads.Document + swaggerSpecAnalysisCache *analysis.Spec ) // getSwaggerSpec loads and caches the swagger spec. If a cached version already exists, // it returns the cached one. The reason why we cache it is because some downstream projects // (e.g. Grafana Mimir) creates many Alertmanager instances in the same process, so they would // incur in a significant memory penalty if we would reload the swagger spec each time. -func getSwaggerSpec() (*loads.Document, error) { +func getSwaggerSpec() (*loads.Document, *analysis.Spec, error) { swaggerSpecCacheMx.Lock() defer swaggerSpecCacheMx.Unlock() // Check if a cached version exists. if swaggerSpecCache != nil { - return swaggerSpecCache, nil + return swaggerSpecCache, swaggerSpecAnalysisCache, nil } // Load embedded swagger file. swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "") if err != nil { - return nil, fmt.Errorf("failed to load embedded swagger file: %w", err) + return nil, nil, fmt.Errorf("failed to load embedded swagger file: %w", err) } swaggerSpecCache = swaggerSpec - return swaggerSpec, nil + swaggerSpecAnalysisCache = analysis.New(swaggerSpec.Spec()) + return swaggerSpec, swaggerSpecAnalysisCache, nil } diff --git a/go.mod b/go.mod index f61ebc14..59f71775 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,10 @@ require ( github.com/cenkalti/backoff/v4 v4.1.3 github.com/cespare/xxhash/v2 v2.1.2 github.com/go-kit/log v0.2.1 + github.com/go-openapi/analysis v0.21.4 github.com/go-openapi/errors v0.20.3 github.com/go-openapi/loads v0.21.2 - github.com/go-openapi/runtime v0.24.1 + github.com/go-openapi/runtime v0.24.3-0.20221021160911-4425b20330b2 github.com/go-openapi/spec v0.20.7 github.com/go-openapi/strfmt v0.21.3 github.com/go-openapi/swag v0.22.3 @@ -54,7 +55,6 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/golang/protobuf v1.5.2 // indirect diff --git a/go.sum b/go.sum index d69fb971..49160e59 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXym github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.24.1 h1:Sml5cgQKGYQHF+M7yYSHaH1eOjvTykrddTE/KtQVjqo= -github.com/go-openapi/runtime v0.24.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= +github.com/go-openapi/runtime v0.24.3-0.20221021160911-4425b20330b2 h1:Vr08+BrsrnvcgikSlS273dkijppZ/M+fL/TMfc/LEJM= +github.com/go-openapi/runtime v0.24.3-0.20221021160911-4425b20330b2/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI=