diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go index 88c03fbb..99735c9c 100644 --- a/cmd/s3-gw/app.go +++ b/cmd/s3-gw/app.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "os/signal" + "runtime/debug" "sync" "sync/atomic" "syscall" @@ -119,6 +120,7 @@ func newApp(ctx context.Context, log *Logger, v *viper.Viper) *App { } func (a *App) init(ctx context.Context) { + a.setRuntimeParameters() a.initAPI(ctx) a.initMetrics() a.initServers(ctx) @@ -507,6 +509,8 @@ func (a *App) configReload(ctx context.Context) { a.log.Warn(logs.FailedToReloadServerParameters, zap.Error(err)) } + a.setRuntimeParameters() + a.stopServices() a.startServices() @@ -679,3 +683,19 @@ func (a *App) initHandler() { a.log.Fatal(logs.CouldNotInitializeAPIHandler, zap.Error(err)) } } + +func (a *App) setRuntimeParameters() { + if len(os.Getenv("GOMEMLIMIT")) != 0 { + // default limit < yaml limit < app env limit < GOMEMLIMIT + a.log.Warn(logs.RuntimeSoftMemoryDefinedWithGOMEMLIMIT) + return + } + + softMemoryLimit := fetchSoftMemoryLimit(a.cfg) + previous := debug.SetMemoryLimit(softMemoryLimit) + if softMemoryLimit != previous { + a.log.Info(logs.RuntimeSoftMemoryLimitUpdated, + zap.Int64("new_value", softMemoryLimit), + zap.Int64("old_value", previous)) + } +} diff --git a/cmd/s3-gw/app_settings.go b/cmd/s3-gw/app_settings.go index 3b89d9b0..7d8f2663 100644 --- a/cmd/s3-gw/app_settings.go +++ b/cmd/s3-gw/app_settings.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "fmt" + "math" "os" "path" "runtime" @@ -37,6 +38,8 @@ const ( defaultMaxClientsCount = 100 defaultMaxClientsDeadline = time.Second * 30 + + defaultSoftMemoryLimit = math.MaxInt64 ) var defaultCopiesNumbers = []uint32{0} @@ -154,6 +157,9 @@ const ( // Settings. cfgResolveBucketAllow = "resolve_bucket.allow" cfgResolveBucketDeny = "resolve_bucket.deny" + // Runtime. + cfgSoftMemoryLimit = "runtime.soft_memory_limit" + // envPrefix is an environment variables prefix used for configuration. envPrefix = "S3_GW" ) @@ -230,6 +236,15 @@ func fetchMaxClientsDeadline(cfg *viper.Viper) time.Duration { return maxClientsDeadline } +func fetchSoftMemoryLimit(cfg *viper.Viper) int64 { + softMemoryLimit := cfg.GetSizeInBytes(cfgSoftMemoryLimit) + if softMemoryLimit <= 0 { + softMemoryLimit = defaultSoftMemoryLimit + } + + return int64(softMemoryLimit) +} + func fetchDefaultPolicy(l *zap.Logger, cfg *viper.Viper) netmap.PlacementPolicy { var policy netmap.PlacementPolicy diff --git a/config/config.env b/config/config.env index a1643d13..3609af32 100644 --- a/config/config.env +++ b/config/config.env @@ -146,3 +146,5 @@ S3_GW_BYPASS_CONTENT_ENCODING_CHECK_IN_CHUNKS=false S3_GW_TRACING_ENABLED=false S3_GW_TRACING_ENDPOINT="localhost:4318" S3_GW_TRACING_EXPORTER="otlp_grpc" + +S3_GW_RUNTIME_SOFT_MEMORY_LIMIT=1073741824 \ No newline at end of file diff --git a/config/config.yaml b/config/config.yaml index e226bdc3..05397209 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -171,3 +171,6 @@ kludge: complete_multipart_keepalive: 10s # Use this flag to be able to use chunked upload approach without having `aws-chunked` value in `Content-Encoding` header. bypass_content_encoding_check_in_chunks: false + +runtime: + soft_memory_limit: 1gb \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md index 50eaa482..af0dd296 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -185,6 +185,7 @@ There are some custom types used for brevity: | `frostfs` | [Parameters of requests to FrostFS](#frostfs-section) | | `resolve_bucket` | [Bucket name resolving configuration](#resolve_bucket-section) | | `kludge` | [Different kludge configuration](#kludge-section) | +| `runtime` | [Runtime configuration](#runtime-section) | ### General section @@ -547,3 +548,15 @@ kludge: | `use_default_xmlns_for_complete_multipart` | `bool` | yes | false | Enable using default xml namespace `http://s3.amazonaws.com/doc/2006-03-01/` when parse `CompleteMultipartUpload` xml body. | | `complete_multipart_keepalive` | `duration` | no | 10s | Set timeout between whitespace transmissions during CompleteMultipartUpload processing. | | `bypass_content_encoding_check_in_chunks` | `bool` | yes | false | Use this flag to be able to use [chunked upload approach](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html) without having `aws-chunked` value in `Content-Encoding` header. | + +# `runtime` section +Contains runtime parameters. + +```yaml +runtime: + soft_memory_limit: 1gb +``` + +| Parameter | Type | SIGHUP reload | Default value | Description | +|---------------------|--------|---------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `soft_memory_limit` | `size` | yes | maxint64 | Soft memory limit for the runtime. Zero or no value stands for no limit. If `GOMEMLIMIT` environment variable is set, the value from the configuration file will be ignored. | \ No newline at end of file diff --git a/internal/logs/logs.go b/internal/logs/logs.go index e9cce3c8..432b8530 100644 --- a/internal/logs/logs.go +++ b/internal/logs/logs.go @@ -112,4 +112,6 @@ const ( ListenAndServe = "listen and serve" // Fatal in ../../cmd/s3-gw/app.go NoHealthyServers = "no healthy servers" // Fatal in ../../cmd/s3-gw/app.go CouldNotInitializeAPIHandler = "could not initialize API handler" // Fatal in ../../cmd/s3-gw/app.go + RuntimeSoftMemoryDefinedWithGOMEMLIMIT = "soft runtime memory defined with GOMEMLIMIT environment variable, config value skipped" // Warn in ../../cmd/s3-gw/app.go + RuntimeSoftMemoryLimitUpdated = "soft runtime memory limit value updated" // Info in ../../cmd/s3-gw/app.go )