mirror of https://github.com/minio/minio.git
Do lockless last minute latency metrics (#17576)
Collect metrics in one second and accumulate lockless before sending upstream.
This commit is contained in:
parent
0bc34952eb
commit
6efcf9c982
|
@ -90,16 +90,6 @@ func (a *AccElem) add(dur time.Duration) {
|
||||||
a.N++
|
a.N++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a duration to a single element.
|
|
||||||
func (a *AccElem) addSize(dur time.Duration, sz int64) {
|
|
||||||
if dur < 0 {
|
|
||||||
dur = 0
|
|
||||||
}
|
|
||||||
a.Total += int64(dur)
|
|
||||||
a.Size += sz
|
|
||||||
a.N++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge b into a.
|
// Merge b into a.
|
||||||
func (a *AccElem) merge(b AccElem) {
|
func (a *AccElem) merge(b AccElem) {
|
||||||
a.N += b.N
|
a.N += b.N
|
||||||
|
@ -156,11 +146,10 @@ func (l *lastMinuteLatency) add(t time.Duration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new duration data
|
// Add a new duration data
|
||||||
func (l *lastMinuteLatency) addSize(t time.Duration, sz int64) {
|
func (l *lastMinuteLatency) addAll(sec int64, a AccElem) {
|
||||||
sec := time.Now().Unix()
|
|
||||||
l.forwardTo(sec)
|
l.forwardTo(sec)
|
||||||
winIdx := sec % 60
|
winIdx := sec % 60
|
||||||
l.Totals[winIdx].addSize(t, sz)
|
l.Totals[winIdx].merge(a)
|
||||||
l.LastSec = sec
|
l.LastSec = sec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -105,28 +106,57 @@ func (p *xlStorageDiskIDCheck) getMetrics() DiskMetrics {
|
||||||
return m.(DiskMetrics)
|
return m.(DiskMetrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lockedLastMinuteLatency accumulates totals lockless for each second.
|
||||||
type lockedLastMinuteLatency struct {
|
type lockedLastMinuteLatency struct {
|
||||||
sync.Mutex
|
cachedSec int64
|
||||||
|
cached atomic.Pointer[AccElem]
|
||||||
|
mu sync.Mutex
|
||||||
|
init sync.Once
|
||||||
lastMinuteLatency
|
lastMinuteLatency
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *lockedLastMinuteLatency) add(value time.Duration) {
|
func (e *lockedLastMinuteLatency) add(value time.Duration) {
|
||||||
e.Lock()
|
e.addSize(value, 0)
|
||||||
defer e.Unlock()
|
|
||||||
e.lastMinuteLatency.add(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// addSize will add a duration and size.
|
// addSize will add a duration and size.
|
||||||
func (e *lockedLastMinuteLatency) addSize(value time.Duration, sz int64) {
|
func (e *lockedLastMinuteLatency) addSize(value time.Duration, sz int64) {
|
||||||
e.Lock()
|
// alloc on every call, so we have a clean entry to swap in.
|
||||||
defer e.Unlock()
|
t := time.Now().Unix()
|
||||||
e.lastMinuteLatency.addSize(value, sz)
|
e.init.Do(func() {
|
||||||
|
e.cached.Store(&AccElem{})
|
||||||
|
atomic.StoreInt64(&e.cachedSec, t)
|
||||||
|
})
|
||||||
|
acc := e.cached.Load()
|
||||||
|
if lastT := atomic.LoadInt64(&e.cachedSec); lastT != t {
|
||||||
|
// Check if lastT was changed by someone else.
|
||||||
|
if atomic.CompareAndSwapInt64(&e.cachedSec, lastT, t) {
|
||||||
|
// Now we swap in a new.
|
||||||
|
newAcc := &AccElem{}
|
||||||
|
old := e.cached.Swap(newAcc)
|
||||||
|
var a AccElem
|
||||||
|
a.Size = atomic.LoadInt64(&old.Size)
|
||||||
|
a.Total = atomic.LoadInt64(&old.Total)
|
||||||
|
a.N = atomic.LoadInt64(&old.N)
|
||||||
|
e.mu.Lock()
|
||||||
|
e.lastMinuteLatency.addAll(t-1, a)
|
||||||
|
e.mu.Unlock()
|
||||||
|
acc = newAcc
|
||||||
|
} else {
|
||||||
|
// We may be able to grab the new accumulator by yielding.
|
||||||
|
runtime.Gosched()
|
||||||
|
acc = e.cached.Load()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
atomic.AddInt64(&acc.N, 1)
|
||||||
|
atomic.AddInt64(&acc.Total, int64(value))
|
||||||
|
atomic.AddInt64(&acc.Size, sz)
|
||||||
}
|
}
|
||||||
|
|
||||||
// total returns the total call count and latency for the last minute.
|
// total returns the total call count and latency for the last minute.
|
||||||
func (e *lockedLastMinuteLatency) total() AccElem {
|
func (e *lockedLastMinuteLatency) total() AccElem {
|
||||||
e.Lock()
|
e.mu.Lock()
|
||||||
defer e.Unlock()
|
defer e.mu.Unlock()
|
||||||
return e.lastMinuteLatency.getTotal()
|
return e.lastMinuteLatency.getTotal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue