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 <marco@pracucci.com>
This commit is contained in:
Marco Pracucci 2022-10-26 10:49:20 +02:00 committed by GitHub
parent 28c3df0173
commit 33bba95099
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 17 additions and 12 deletions

View File

@ -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
}

4
go.mod
View File

@ -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

4
go.sum
View File

@ -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=