Files
seaweedfs/telemetry/server/storage/sizes.go
T
Chris LuandGitHub 88fd2d1be8 telemetry: stack volume servers per cluster, drop the total disk usage chart (#10550)
* telemetry: stack volume servers per cluster over time

The fleet-wide server count says how many volume servers reported, but not
who they belong to. Carry per-cluster counts in /api/cluster-sizes and draw
them the same way as cluster sizes, sharing one cluster ranking so a cluster
keeps its colour across both stacks.

* telemetry: drop the total disk usage chart from the dashboard

The stacked cluster sizes chart right below it has the same fleet total as
its stack height, plus the per-cluster breakdown. /api/metrics still serves
the aggregate for anyone graphing it elsewhere.
2026-08-03 13:13:48 -07:00

91 lines
3.0 KiB
Go

package storage
import (
"sort"
"time"
)
// ClusterSeries is one cluster's daily disk usage and volume server count,
// aligned to the shared date axis of the enclosing ClusterSizeSeries.
type ClusterSeries struct {
ClusterId string `json:"cluster_id"`
Disk []uint64 `json:"disk"`
Servers []uint64 `json:"servers"`
}
// OtherSeries is the clusters beyond the caller's limit, summed per day so a
// stacked chart still adds up to the fleet total.
type OtherSeries struct {
Count int `json:"count"`
Disk []uint64 `json:"disk"`
Servers []uint64 `json:"servers"`
}
// ClusterSizeSeries is per-cluster disk usage and volume server count over
// time: one value per cluster per day, largest cluster first, ranked by disk on
// their most recent day. Both metrics share one ranking so a cluster keeps its
// place, and its colour, across the charts drawn from this.
type ClusterSizeSeries struct {
Dates []string `json:"dates"`
Clusters []ClusterSeries `json:"clusters"`
Other *OtherSeries `json:"other,omitempty"`
ClusterCount int `json:"cluster_count"`
TotalDisk uint64 `json:"total_disk"` // across all clusters on the last day
TotalServers uint64 `json:"total_servers"` // across all clusters on the last day
}
// GetClusterSizeSeries returns the last `days` days of per-cluster disk usage
// and volume server counts across confirmed clusters. Clusters beyond `limit`
// are folded into Other.
func (s *PrometheusStorage) GetClusterSizeSeries(days, limit int) ClusterSizeSeries {
s.mu.RLock()
defer s.mu.RUnlock()
histories := s.seriesHistories()
axis := newDailySeries(days, histories)
activeSince := time.Now().UTC().AddDate(0, 0, -activeDays).Unix()
last := len(axis.dates) - 1
series := ClusterSizeSeries{Dates: axis.dates}
for id, history := range histories {
disk, ok := axis.align(history, activeSince, diskBytes)
if !ok {
continue
}
servers, _ := axis.align(history, activeSince, serverCount)
series.Clusters = append(series.Clusters, ClusterSeries{ClusterId: id, Disk: disk, Servers: servers})
series.TotalDisk += disk[last]
series.TotalServers += servers[last]
}
series.ClusterCount = len(series.Clusters)
// Rank by the latest day so the stack reads largest-first at its right
// edge, tie-breaking on id to keep the order stable across refreshes.
sort.Slice(series.Clusters, func(i, j int) bool {
a, b := series.Clusters[i], series.Clusters[j]
if a.Disk[last] != b.Disk[last] {
return a.Disk[last] > b.Disk[last]
}
return a.ClusterId < b.ClusterId
})
if limit > 0 && len(series.Clusters) > limit {
other := OtherSeries{
Count: len(series.Clusters) - limit,
Disk: make([]uint64, len(axis.dates)),
Servers: make([]uint64, len(axis.dates)),
}
for _, c := range series.Clusters[limit:] {
for i, v := range c.Disk {
other.Disk[i] += v
}
for i, v := range c.Servers {
other.Servers[i] += v
}
}
series.Clusters = series.Clusters[:limit]
series.Other = &other
}
return series
}