mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
app/vmselect/netstorage: reduce the contention at fs.ReaderAt stats collection on systems with big number of CPU cores
This optimization is based on the profile provided at https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3966#issuecomment-1483208419
This commit is contained in:
parent
a2ecf4fa4a
commit
db3bcbe56a
2 changed files with 35 additions and 2 deletions
|
@ -144,6 +144,9 @@ func (tbf *tmpBlocksFile) Finalize() error {
|
||||||
// This should reduce the number of disk seeks, which is important
|
// This should reduce the number of disk seeks, which is important
|
||||||
// for HDDs.
|
// for HDDs.
|
||||||
r.MustFadviseSequentialRead(true)
|
r.MustFadviseSequentialRead(true)
|
||||||
|
// Collect local stats in order to improve performance on systems with big number of CPU cores.
|
||||||
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3966
|
||||||
|
r.SetUseLocalStats()
|
||||||
tbf.r = r
|
tbf.r = r
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||||
"github.com/VictoriaMetrics/metrics"
|
"github.com/VictoriaMetrics/metrics"
|
||||||
|
@ -27,8 +28,13 @@ type MustReadAtCloser interface {
|
||||||
|
|
||||||
// ReaderAt implements rand-access reader.
|
// ReaderAt implements rand-access reader.
|
||||||
type ReaderAt struct {
|
type ReaderAt struct {
|
||||||
|
readCalls uint64
|
||||||
|
readBytes uint64
|
||||||
|
|
||||||
f *os.File
|
f *os.File
|
||||||
mmapData []byte
|
mmapData []byte
|
||||||
|
|
||||||
|
useLocalStats bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustReadAt reads len(p) bytes at off from r.
|
// MustReadAt reads len(p) bytes at off from r.
|
||||||
|
@ -56,8 +62,13 @@ func (r *ReaderAt) MustReadAt(p []byte, off int64) {
|
||||||
// But production workload proved this is OK in most cases, so use it without fear :)
|
// But production workload proved this is OK in most cases, so use it without fear :)
|
||||||
copy(p, src)
|
copy(p, src)
|
||||||
}
|
}
|
||||||
readCalls.Inc()
|
if r.useLocalStats {
|
||||||
readBytes.Add(len(p))
|
atomic.AddUint64(&r.readCalls, 1)
|
||||||
|
atomic.AddUint64(&r.readBytes, uint64(len(p)))
|
||||||
|
} else {
|
||||||
|
readCalls.Inc()
|
||||||
|
readBytes.Add(len(p))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustClose closes r.
|
// MustClose closes r.
|
||||||
|
@ -71,9 +82,28 @@ func (r *ReaderAt) MustClose() {
|
||||||
}
|
}
|
||||||
MustClose(r.f)
|
MustClose(r.f)
|
||||||
r.f = nil
|
r.f = nil
|
||||||
|
|
||||||
|
if r.useLocalStats {
|
||||||
|
readCalls.Add(int(r.readCalls))
|
||||||
|
readBytes.Add(int(r.readBytes))
|
||||||
|
r.readCalls = 0
|
||||||
|
r.readBytes = 0
|
||||||
|
r.useLocalStats = false
|
||||||
|
}
|
||||||
readersCount.Dec()
|
readersCount.Dec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetUseLocalStats switches to local stats collection instead of global stats collection.
|
||||||
|
//
|
||||||
|
// This function must be called before the first call to MustReadAt().
|
||||||
|
//
|
||||||
|
// Collecting local stats may improve performance on systems with big number of CPU cores,
|
||||||
|
// since the locally collected stats is pushed to global stats only at MustClose() call
|
||||||
|
// instead of pushing it at every MustReadAt call.
|
||||||
|
func (r *ReaderAt) SetUseLocalStats() {
|
||||||
|
r.useLocalStats = true
|
||||||
|
}
|
||||||
|
|
||||||
// MustFadviseSequentialRead hints the OS that f is read mostly sequentially.
|
// MustFadviseSequentialRead hints the OS that f is read mostly sequentially.
|
||||||
//
|
//
|
||||||
// if prefetch is set, then the OS is hinted to prefetch f data.
|
// if prefetch is set, then the OS is hinted to prefetch f data.
|
||||||
|
|
Loading…
Reference in a new issue