From 11c9289efd462bd99bd7bee05274002b127108ac Mon Sep 17 00:00:00 2001 From: Andrey Butusov Date: Thu, 21 Nov 2024 18:15:33 +0300 Subject: [PATCH] node: add `neofs_node_engine_capacity` metric Expose metric for shard's capacity. Closes #1794. Signed-off-by: Andrey Butusov --- CHANGELOG.md | 1 + cmd/neofs-node/config.go | 29 ++++++++++++++++++----------- cmd/neofs-node/main.go | 3 +++ cmd/neofs-node/metrics.go | 25 +++++++++++++++++++++++++ pkg/metrics/engine.go | 14 ++++++++++++++ 5 files changed, 61 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 858b6c242f..e704343d5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ attribute, which is used for container domain name in NNS contracts (#2954) - New `peapod-to-fstree` tool providing peapod-to-fstree data migration (#3013) - Reloading node attributes with SIGHUP (#3005) - Reloading pool sizes (#3018) +- Add metrics for shard's capacity (#3021) ### Fixed - Do not search for tombstones when handling their expiration, use local indexes instead (#2929) diff --git a/cmd/neofs-node/config.go b/cmd/neofs-node/config.go index da6a705154..493c5d607b 100644 --- a/cmd/neofs-node/config.go +++ b/cmd/neofs-node/config.go @@ -935,17 +935,9 @@ func writeSystemAttributes(c *cfg) error { var paths []string for _, sh := range c.applicationConfiguration.engine.shards { for _, subStorage := range sh.SubStorages { - path := subStorage.Path - - for len(path) > 1 { // Dir returns / or . if nothing else left. - fi, err := os.Stat(path) - if err == nil && fi.IsDir() { - break - } - if err != nil && !errors.Is(err, fs.ErrNotExist) { - return fmt.Errorf("accessing %q: %w", path, err) - } - path = filepath.Dir(path) + path, err := getInitPath(subStorage.Path) + if err != nil { + return err } paths = append(paths, path) @@ -961,3 +953,18 @@ func writeSystemAttributes(c *cfg) error { return nil } + +func getInitPath(path string) (string, error) { + for len(path) > 1 { // Dir returns / or . if nothing else left. + fi, err := os.Stat(path) + if err == nil && fi.IsDir() { + break + } + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return "", fmt.Errorf("accessing %q: %w", path, err) + } + path = filepath.Dir(path) + } + + return path, nil +} diff --git a/cmd/neofs-node/main.go b/cmd/neofs-node/main.go index 86e362e516..428ae172bf 100644 --- a/cmd/neofs-node/main.go +++ b/cmd/neofs-node/main.go @@ -61,6 +61,9 @@ func main() { initApp(c) + err = c.setShardsCapacity() + fatalOnErr(err) + c.setHealthStatus(control.HealthStatus_STARTING) bootUp(c) diff --git a/cmd/neofs-node/metrics.go b/cmd/neofs-node/metrics.go index a3899a92e5..9040f4bbf6 100644 --- a/cmd/neofs-node/metrics.go +++ b/cmd/neofs-node/metrics.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + metricsconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/metrics" httputil "github.com/nspcc-dev/neofs-node/pkg/util/http" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -25,3 +27,26 @@ func initMetrics(c *cfg) *httputil.Server { return srv } + +func (c *cfg) setShardsCapacity() error { + for _, sh := range c.cfgObject.cfgLocalStorage.localStorage.DumpInfo().Shards { + paths := make([]string, 0, len(sh.BlobStorInfo.SubStorages)) + for _, subStorage := range sh.BlobStorInfo.SubStorages { + path, err := getInitPath(subStorage.Path) + if err != nil { + return err + } + + paths = append(paths, path) + } + + capacity, err := totalBytes(paths) + if err != nil { + return fmt.Errorf("calculating capacity on shard %s: %w", sh.ID.String(), err) + } + + c.metricsCollector.SetCapacitySize(sh.ID.String(), capacity) + } + + return nil +} diff --git a/pkg/metrics/engine.go b/pkg/metrics/engine.go index 71a4d3cf2e..8952fda476 100644 --- a/pkg/metrics/engine.go +++ b/pkg/metrics/engine.go @@ -22,6 +22,7 @@ type ( containerSize prometheus.GaugeVec payloadSize prometheus.GaugeVec + capacitySize prometheus.GaugeVec } ) @@ -121,6 +122,13 @@ func newEngineMetrics() engineMetrics { Name: "payload_size", Help: "Accumulated size of all objects in a shard", }, []string{shardIDLabelKey}) + + capacitySize = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: storageNodeNameSpace, + Subsystem: engineSubsystem, + Name: "capacity", + Help: "Contains the shard's capacity", + }, []string{shardIDLabelKey}) ) return engineMetrics{ @@ -137,6 +145,7 @@ func newEngineMetrics() engineMetrics { listObjectsDuration: listObjectsDuration, containerSize: *containerSize, payloadSize: *payloadSize, + capacitySize: *capacitySize, } } @@ -154,6 +163,7 @@ func (m engineMetrics) register() { prometheus.MustRegister(m.listObjectsDuration) prometheus.MustRegister(m.containerSize) prometheus.MustRegister(m.payloadSize) + prometheus.MustRegister(m.capacitySize) } func (m engineMetrics) AddListContainersDuration(d time.Duration) { @@ -211,3 +221,7 @@ func (m engineMetrics) AddToContainerSize(cnrID string, size int64) { func (m engineMetrics) AddToPayloadCounter(shardID string, size int64) { m.payloadSize.With(prometheus.Labels{shardIDLabelKey: shardID}).Add(float64(size)) } + +func (m engineMetrics) SetCapacitySize(shardID string, capacity uint64) { + m.capacitySize.With(prometheus.Labels{shardIDLabelKey: shardID}).Set(float64(capacity)) +}