cmd, ethdb, vendor: integrate leveldb iostats (#16277)
* cmd, dashboard, ethdb, vendor: send iostats to dashboard * ethdb: change names * ethdb: handle parsing errors * ethdb: handle iostats syntax error * ethdb: r -> w
This commit is contained in:
committed by
Péter Szilágyi
parent
4871e25f5f
commit
39c16c8a1e
@ -37,15 +37,11 @@ type LDBDatabase struct {
|
||||
fn string // filename for reporting
|
||||
db *leveldb.DB // LevelDB instance
|
||||
|
||||
getTimer metrics.Timer // Timer for measuring the database get request counts and latencies
|
||||
putTimer metrics.Timer // Timer for measuring the database put request counts and latencies
|
||||
delTimer metrics.Timer // Timer for measuring the database delete request counts and latencies
|
||||
missMeter metrics.Meter // Meter for measuring the missed database get requests
|
||||
readMeter metrics.Meter // Meter for measuring the database get request data usage
|
||||
writeMeter metrics.Meter // Meter for measuring the database put request data usage
|
||||
compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction
|
||||
compReadMeter metrics.Meter // Meter for measuring the data read during compaction
|
||||
compWriteMeter metrics.Meter // Meter for measuring the data written during compaction
|
||||
diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read
|
||||
diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written
|
||||
|
||||
quitLock sync.Mutex // Mutex protecting the quit channel access
|
||||
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
|
||||
@ -94,16 +90,9 @@ func (db *LDBDatabase) Path() string {
|
||||
|
||||
// Put puts the given key / value to the queue
|
||||
func (db *LDBDatabase) Put(key []byte, value []byte) error {
|
||||
// Measure the database put latency, if requested
|
||||
if db.putTimer != nil {
|
||||
defer db.putTimer.UpdateSince(time.Now())
|
||||
}
|
||||
// Generate the data to write to disk, update the meter and write
|
||||
//value = rle.Compress(value)
|
||||
|
||||
if db.writeMeter != nil {
|
||||
db.writeMeter.Mark(int64(len(value)))
|
||||
}
|
||||
return db.db.Put(key, value, nil)
|
||||
}
|
||||
|
||||
@ -113,32 +102,17 @@ func (db *LDBDatabase) Has(key []byte) (bool, error) {
|
||||
|
||||
// Get returns the given key if it's present.
|
||||
func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
|
||||
// Measure the database get latency, if requested
|
||||
if db.getTimer != nil {
|
||||
defer db.getTimer.UpdateSince(time.Now())
|
||||
}
|
||||
// Retrieve the key and increment the miss counter if not found
|
||||
dat, err := db.db.Get(key, nil)
|
||||
if err != nil {
|
||||
if db.missMeter != nil {
|
||||
db.missMeter.Mark(1)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
// Otherwise update the actually retrieved amount of data
|
||||
if db.readMeter != nil {
|
||||
db.readMeter.Mark(int64(len(dat)))
|
||||
}
|
||||
return dat, nil
|
||||
//return rle.Decompress(dat)
|
||||
}
|
||||
|
||||
// Delete deletes the key from the queue and database
|
||||
func (db *LDBDatabase) Delete(key []byte) error {
|
||||
// Measure the database delete latency, if requested
|
||||
if db.delTimer != nil {
|
||||
defer db.delTimer.UpdateSince(time.Now())
|
||||
}
|
||||
// Execute the actual operation
|
||||
return db.db.Delete(key, nil)
|
||||
}
|
||||
@ -178,15 +152,11 @@ func (db *LDBDatabase) Meter(prefix string) {
|
||||
return
|
||||
}
|
||||
// Initialize all the metrics collector at the requested prefix
|
||||
db.getTimer = metrics.NewRegisteredTimer(prefix+"user/gets", nil)
|
||||
db.putTimer = metrics.NewRegisteredTimer(prefix+"user/puts", nil)
|
||||
db.delTimer = metrics.NewRegisteredTimer(prefix+"user/dels", nil)
|
||||
db.missMeter = metrics.NewRegisteredMeter(prefix+"user/misses", nil)
|
||||
db.readMeter = metrics.NewRegisteredMeter(prefix+"user/reads", nil)
|
||||
db.writeMeter = metrics.NewRegisteredMeter(prefix+"user/writes", nil)
|
||||
db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
|
||||
db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
|
||||
db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
|
||||
db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil)
|
||||
db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil)
|
||||
|
||||
// Create a quit channel for the periodic collector and run it
|
||||
db.quitLock.Lock()
|
||||
@ -207,12 +177,17 @@ func (db *LDBDatabase) Meter(prefix string) {
|
||||
// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294
|
||||
// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884
|
||||
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
|
||||
//
|
||||
// This is how the iostats look like (currently):
|
||||
// Read(MB):3895.04860 Write(MB):3654.64712
|
||||
func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||
// Create the counters to store current and previous values
|
||||
counters := make([][]float64, 2)
|
||||
// Create the counters to store current and previous compaction values
|
||||
compactions := make([][]float64, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
counters[i] = make([]float64, 3)
|
||||
compactions[i] = make([]float64, 3)
|
||||
}
|
||||
// Create storage for iostats.
|
||||
var iostats [2]float64
|
||||
// Iterate ad infinitum and collect the stats
|
||||
for i := 1; ; i++ {
|
||||
// Retrieve the database stats
|
||||
@ -233,8 +208,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||
lines = lines[3:]
|
||||
|
||||
// Iterate over all the table rows, and accumulate the entries
|
||||
for j := 0; j < len(counters[i%2]); j++ {
|
||||
counters[i%2][j] = 0
|
||||
for j := 0; j < len(compactions[i%2]); j++ {
|
||||
compactions[i%2][j] = 0
|
||||
}
|
||||
for _, line := range lines {
|
||||
parts := strings.Split(line, "|")
|
||||
@ -247,19 +222,60 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||
db.log.Error("Compaction entry parsing failed", "err", err)
|
||||
return
|
||||
}
|
||||
counters[i%2][idx] += value
|
||||
compactions[i%2][idx] += value
|
||||
}
|
||||
}
|
||||
// Update all the requested meters
|
||||
if db.compTimeMeter != nil {
|
||||
db.compTimeMeter.Mark(int64((counters[i%2][0] - counters[(i-1)%2][0]) * 1000 * 1000 * 1000))
|
||||
db.compTimeMeter.Mark(int64((compactions[i%2][0] - compactions[(i-1)%2][0]) * 1000 * 1000 * 1000))
|
||||
}
|
||||
if db.compReadMeter != nil {
|
||||
db.compReadMeter.Mark(int64((counters[i%2][1] - counters[(i-1)%2][1]) * 1024 * 1024))
|
||||
db.compReadMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1024 * 1024))
|
||||
}
|
||||
if db.compWriteMeter != nil {
|
||||
db.compWriteMeter.Mark(int64((counters[i%2][2] - counters[(i-1)%2][2]) * 1024 * 1024))
|
||||
db.compWriteMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024))
|
||||
}
|
||||
|
||||
// Retrieve the database iostats.
|
||||
ioStats, err := db.db.GetProperty("leveldb.iostats")
|
||||
if err != nil {
|
||||
db.log.Error("Failed to read database iostats", "err", err)
|
||||
return
|
||||
}
|
||||
parts := strings.Split(ioStats, " ")
|
||||
if len(parts) < 2 {
|
||||
db.log.Error("Bad syntax of ioStats", "ioStats", ioStats)
|
||||
return
|
||||
}
|
||||
r := strings.Split(parts[0], ":")
|
||||
if len(r) < 2 {
|
||||
db.log.Error("Bad syntax of read entry", "entry", parts[0])
|
||||
return
|
||||
}
|
||||
read, err := strconv.ParseFloat(r[1], 64)
|
||||
if err != nil {
|
||||
db.log.Error("Read entry parsing failed", "err", err)
|
||||
return
|
||||
}
|
||||
w := strings.Split(parts[1], ":")
|
||||
if len(w) < 2 {
|
||||
db.log.Error("Bad syntax of write entry", "entry", parts[1])
|
||||
return
|
||||
}
|
||||
write, err := strconv.ParseFloat(w[1], 64)
|
||||
if err != nil {
|
||||
db.log.Error("Write entry parsing failed", "err", err)
|
||||
return
|
||||
}
|
||||
if db.diskReadMeter != nil {
|
||||
db.diskReadMeter.Mark(int64((read - iostats[0]) * 1024 * 1024))
|
||||
}
|
||||
if db.diskWriteMeter != nil {
|
||||
db.diskWriteMeter.Mark(int64((write - iostats[1]) * 1024 * 1024))
|
||||
}
|
||||
iostats[0] = read
|
||||
iostats[1] = write
|
||||
|
||||
// Sleep a bit, then repeat the stats collection
|
||||
select {
|
||||
case errc := <-db.quitChan:
|
||||
|
Reference in New Issue
Block a user