mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-11 14:53:49 +00:00
505d359b39
* app/vminsert: allows parsing tenant id from labels it should help mitigate issues with vmagent's multiTenant mode, which works incorrectly at heavy load and it cannot handle more then 100 different tenants. This functional hidden with flag and do not change vminsert default behaviour https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2970 * Update docs/Cluster-VictoriaMetrics.md Co-authored-by: Roman Khavronenko <roman@victoriametrics.com> * wip * app/vminsert/netstorage: clean remaining labels in order to free up GC * docs/Cluster-VictoriaMetrics.md: typo fix * wip * wip Co-authored-by: Roman Khavronenko <roman@victoriametrics.com> Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
79 lines
2 KiB
Go
79 lines
2 KiB
Go
package tenantmetrics
|
|
|
|
import (
|
|
"fmt"
|
|
"sync/atomic"
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/auth"
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
|
"github.com/VictoriaMetrics/metrics"
|
|
)
|
|
|
|
// TenantID defines metric tenant.
|
|
type TenantID struct {
|
|
AccountID uint32
|
|
ProjectID uint32
|
|
}
|
|
|
|
// CounterMap is a map of counters keyed by tenant.
|
|
type CounterMap struct {
|
|
metric string
|
|
m atomic.Value
|
|
}
|
|
|
|
// NewCounterMap creates new CounterMap for the given metric.
|
|
func NewCounterMap(metric string) *CounterMap {
|
|
cm := &CounterMap{
|
|
metric: metric,
|
|
}
|
|
cm.m.Store(make(map[TenantID]*metrics.Counter))
|
|
return cm
|
|
}
|
|
|
|
// Get returns counter for the given at
|
|
func (cm *CounterMap) Get(at *auth.Token) *metrics.Counter {
|
|
key := TenantID{
|
|
AccountID: at.AccountID,
|
|
ProjectID: at.ProjectID,
|
|
}
|
|
return cm.GetByTenant(key)
|
|
}
|
|
|
|
// MultiAdd adds multiple values grouped by auth.Token
|
|
func (cm *CounterMap) MultiAdd(perTenantValues map[auth.Token]int) {
|
|
for token, value := range perTenantValues {
|
|
cm.Get(&token).Add(value)
|
|
}
|
|
}
|
|
|
|
// GetByTenant returns counter for the given key.
|
|
func (cm *CounterMap) GetByTenant(key TenantID) *metrics.Counter {
|
|
m := cm.m.Load().(map[TenantID]*metrics.Counter)
|
|
if c := m[key]; c != nil {
|
|
// Fast path - the counter for k already exists.
|
|
return c
|
|
}
|
|
|
|
// Slow path - create missing counter for k and re-create m.
|
|
newM := make(map[TenantID]*metrics.Counter, len(m)+1)
|
|
for k, c := range m {
|
|
newM[k] = c
|
|
}
|
|
metricName := createMetricName(cm.metric, key)
|
|
c := metrics.GetOrCreateCounter(metricName)
|
|
newM[key] = c
|
|
cm.m.Store(newM)
|
|
return c
|
|
}
|
|
|
|
func createMetricName(metric string, key TenantID) string {
|
|
if len(metric) == 0 {
|
|
logger.Panicf("BUG: metric cannot be empty")
|
|
}
|
|
if metric[len(metric)-1] != '}' {
|
|
// Metric without labels.
|
|
return fmt.Sprintf(`%s{accountID="%d",projectID="%d"}`, metric, key.AccountID, key.ProjectID)
|
|
}
|
|
// Metric with labels.
|
|
return fmt.Sprintf(`%s,accountID="%d",projectID="%d"}`, metric[:len(metric)-1], key.AccountID, key.ProjectID)
|
|
}
|