mirror of https://github.com/prometheus/prometheus
web: deduplicate series in federation
parent
f56644e3ae
commit
bbcf20ba01
|
@ -104,6 +104,13 @@ type dedupedSeriesSet struct {
|
||||||
// DeduplicateSeriesSet merges two SeriesSet and removes duplicates.
|
// DeduplicateSeriesSet merges two SeriesSet and removes duplicates.
|
||||||
// If two series exist in both sets, their datapoints must be equal.
|
// If two series exist in both sets, their datapoints must be equal.
|
||||||
func DeduplicateSeriesSet(a, b SeriesSet) SeriesSet {
|
func DeduplicateSeriesSet(a, b SeriesSet) SeriesSet {
|
||||||
|
if a == nil {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
if b == nil {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
s := &dedupedSeriesSet{a: a, b: b}
|
s := &dedupedSeriesSet{a: a, b: b}
|
||||||
s.adone = !s.a.Next()
|
s.adone = !s.a.Next()
|
||||||
s.bdone = !s.b.Next()
|
s.bdone = !s.b.Next()
|
||||||
|
|
|
@ -340,11 +340,7 @@ func (api *API) series(r *http.Request) (interface{}, *apiError) {
|
||||||
var set storage.SeriesSet
|
var set storage.SeriesSet
|
||||||
|
|
||||||
for _, mset := range matcherSets {
|
for _, mset := range matcherSets {
|
||||||
if set == nil {
|
set = storage.DeduplicateSeriesSet(set, q.Select(mset...))
|
||||||
set = q.Select(mset...)
|
|
||||||
} else {
|
|
||||||
set = storage.DeduplicateSeriesSet(set, q.Select(mset...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics := []labels.Labels{}
|
metrics := []labels.Labels{}
|
||||||
|
|
|
@ -69,42 +69,46 @@ func (h *Handler) federation(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
defer q.Close()
|
defer q.Close()
|
||||||
|
|
||||||
// TODO(fabxc): expose merge functionality in storage interface.
|
|
||||||
// We just concatenate results for all sets of matchers, which may produce
|
|
||||||
// duplicated results.
|
|
||||||
vec := make(promql.Vector, 0, 8000)
|
vec := make(promql.Vector, 0, 8000)
|
||||||
|
|
||||||
|
var set storage.SeriesSet
|
||||||
|
|
||||||
for _, mset := range matcherSets {
|
for _, mset := range matcherSets {
|
||||||
series := q.Select(mset...)
|
set = storage.DeduplicateSeriesSet(set, q.Select(mset...))
|
||||||
for series.Next() {
|
}
|
||||||
s := series.At()
|
if set == nil {
|
||||||
// TODO(fabxc): allow fast path for most recent sample either
|
return
|
||||||
// in the storage itself or caching layer in Prometheus.
|
}
|
||||||
it := storage.NewBuffer(s.Iterator(), int64(promql.StalenessDelta/1e6))
|
|
||||||
|
|
||||||
var t int64
|
for set.Next() {
|
||||||
var v float64
|
s := set.At()
|
||||||
|
|
||||||
ok := it.Seek(maxt)
|
// TODO(fabxc): allow fast path for most recent sample either
|
||||||
if ok {
|
// in the storage itself or caching layer in Prometheus.
|
||||||
t, v = it.Values()
|
it := storage.NewBuffer(s.Iterator(), int64(promql.StalenessDelta/1e6))
|
||||||
} else {
|
|
||||||
t, v, ok = it.PeekBack()
|
var t int64
|
||||||
if !ok {
|
var v float64
|
||||||
continue
|
|
||||||
}
|
ok := it.Seek(maxt)
|
||||||
|
if ok {
|
||||||
|
t, v = it.Values()
|
||||||
|
} else {
|
||||||
|
t, v, ok = it.PeekBack()
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vec = append(vec, promql.Sample{
|
vec = append(vec, promql.Sample{
|
||||||
Metric: s.Labels(),
|
Metric: s.Labels(),
|
||||||
Point: promql.Point{T: t, V: v},
|
Point: promql.Point{T: t, V: v},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if series.Err() != nil {
|
if set.Err() != nil {
|
||||||
federationErrors.Inc()
|
federationErrors.Inc()
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(byName(vec))
|
sort.Sort(byName(vec))
|
||||||
|
|
Loading…
Reference in New Issue