app/vmselect/querystats: show the number of matching queries in the top by average duration and in the top by summary duration

This should help debugging slow queries.
This commit is contained in:
Aliaksandr Valialkin 2021-02-28 19:40:16 +02:00
parent 1da1d502a8
commit 2b53add6b2

View file

@ -89,7 +89,7 @@ func (qst *queryStatsTracker) writeJSONQueryStats(w io.Writer, topN int, maxLife
fmt.Fprintf(w, `],"topByAvgDuration":[`) fmt.Fprintf(w, `],"topByAvgDuration":[`)
topByAvgDuration := qst.getTopByAvgDuration(topN, maxLifetime) topByAvgDuration := qst.getTopByAvgDuration(topN, maxLifetime)
for i, r := range topByAvgDuration { for i, r := range topByAvgDuration {
fmt.Fprintf(w, `{"query":%q,"timeRangeSeconds":%d,"avgDurationSeconds":%.3f}`, r.query, r.timeRangeSecs, r.duration.Seconds()) fmt.Fprintf(w, `{"query":%q,"timeRangeSeconds":%d,"avgDurationSeconds":%.3f,"count":%d}`, r.query, r.timeRangeSecs, r.duration.Seconds(), r.count)
if i+1 < len(topByAvgDuration) { if i+1 < len(topByAvgDuration) {
fmt.Fprintf(w, `,`) fmt.Fprintf(w, `,`)
} }
@ -97,7 +97,7 @@ func (qst *queryStatsTracker) writeJSONQueryStats(w io.Writer, topN int, maxLife
fmt.Fprintf(w, `],"topBySumDuration":[`) fmt.Fprintf(w, `],"topBySumDuration":[`)
topBySumDuration := qst.getTopBySumDuration(topN, maxLifetime) topBySumDuration := qst.getTopBySumDuration(topN, maxLifetime)
for i, r := range topBySumDuration { for i, r := range topBySumDuration {
fmt.Fprintf(w, `{"query":%q,"timeRangeSeconds":%d,"sumDurationSeconds":%.3f}`, r.query, r.timeRangeSecs, r.duration.Seconds()) fmt.Fprintf(w, `{"query":%q,"timeRangeSeconds":%d,"sumDurationSeconds":%.3f,"count":%d}`, r.query, r.timeRangeSecs, r.duration.Seconds(), r.count)
if i+1 < len(topBySumDuration) { if i+1 < len(topBySumDuration) {
fmt.Fprintf(w, `,`) fmt.Fprintf(w, `,`)
} }
@ -202,6 +202,7 @@ func (qst *queryStatsTracker) getTopByAvgDuration(topN int, maxLifetime time.Dur
query: k.query, query: k.query,
timeRangeSecs: k.timeRangeSecs, timeRangeSecs: k.timeRangeSecs,
duration: ks.sum / time.Duration(ks.count), duration: ks.sum / time.Duration(ks.count),
count: ks.count,
}) })
} }
sort.Slice(a, func(i, j int) bool { sort.Slice(a, func(i, j int) bool {
@ -217,26 +218,35 @@ type queryStatByDuration struct {
query string query string
timeRangeSecs int64 timeRangeSecs int64
duration time.Duration duration time.Duration
count int
} }
func (qst *queryStatsTracker) getTopBySumDuration(topN int, maxLifetime time.Duration) []queryStatByDuration { func (qst *queryStatsTracker) getTopBySumDuration(topN int, maxLifetime time.Duration) []queryStatByDuration {
currentTime := time.Now() currentTime := time.Now()
qst.mu.Lock() qst.mu.Lock()
m := make(map[queryStatKey]time.Duration) type countDuration struct {
count int
sum time.Duration
}
m := make(map[queryStatKey]countDuration)
for _, r := range qst.a { for _, r := range qst.a {
if r.matches(currentTime, maxLifetime) { if r.matches(currentTime, maxLifetime) {
k := r.key() k := r.key()
m[k] = m[k] + r.duration kd := m[k]
kd.count++
kd.sum += r.duration
m[k] = kd
} }
} }
qst.mu.Unlock() qst.mu.Unlock()
var a []queryStatByDuration var a []queryStatByDuration
for k, d := range m { for k, kd := range m {
a = append(a, queryStatByDuration{ a = append(a, queryStatByDuration{
query: k.query, query: k.query,
timeRangeSecs: k.timeRangeSecs, timeRangeSecs: k.timeRangeSecs,
duration: d, duration: kd.sum,
count: kd.count,
}) })
} }
sort.Slice(a, func(i, j int) bool { sort.Slice(a, func(i, j int) bool {