app/vmselect: add -search.maxExportDuration command-line flag for limiting /api/v1/export duration

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/275
This commit is contained in:
Aliaksandr Valialkin 2019-12-20 11:34:52 +02:00
parent 1825893eef
commit bea5a8700a

View file

@ -23,9 +23,10 @@ import (
var ( var (
latencyOffset = flag.Duration("search.latencyOffset", time.Second*30, "The time when data points become visible in query results after the colection. "+ latencyOffset = flag.Duration("search.latencyOffset", time.Second*30, "The time when data points become visible in query results after the colection. "+
"Too small value can result in incomplete last points for query results") "Too small value can result in incomplete last points for query results")
maxQueryDuration = flag.Duration("search.maxQueryDuration", time.Second*30, "The maximum time for search query execution") maxExportDuration = flag.Duration("search.maxExportDuration", 10*time.Minute, "The maximum duration for `/api/v1/export` call")
maxQueryLen = flag.Int("search.maxQueryLen", 16*1024, "The maximum search query length in bytes") maxQueryDuration = flag.Duration("search.maxQueryDuration", time.Second*30, "The maximum duration for search query execution")
maxLookback = flag.Duration("search.maxLookback", 0, "Synonim to `-search.lookback-delta` from Prometheus. "+ maxQueryLen = flag.Int("search.maxQueryLen", 16*1024, "The maximum search query length in bytes")
maxLookback = flag.Duration("search.maxLookback", 0, "Synonim to `-search.lookback-delta` from Prometheus. "+
"The value is dynamically detected from interval between time series datapoints if not set. It can be overridden on per-query basis via `max_lookback` arg") "The value is dynamically detected from interval between time series datapoints if not set. It can be overridden on per-query basis via `max_lookback` arg")
) )
@ -58,7 +59,7 @@ func FederateHandler(w http.ResponseWriter, r *http.Request) error {
if err != nil { if err != nil {
return err return err
} }
deadline := getDeadline(r) deadline := getDeadlineForQuery(r)
if start >= end { if start >= end {
start = end - defaultStep start = end - defaultStep
} }
@ -129,7 +130,7 @@ func ExportHandler(w http.ResponseWriter, r *http.Request) error {
return err return err
} }
format := r.FormValue("format") format := r.FormValue("format")
deadline := getDeadline(r) deadline := getDeadlineForExport(r)
if start >= end { if start >= end {
end = start + defaultStep end = start + defaultStep
} }
@ -235,7 +236,7 @@ var deleteDuration = metrics.NewSummary(`vm_request_duration_seconds{path="/api/
// See https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values // See https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values
func LabelValuesHandler(labelName string, w http.ResponseWriter, r *http.Request) error { func LabelValuesHandler(labelName string, w http.ResponseWriter, r *http.Request) error {
startTime := time.Now() startTime := time.Now()
deadline := getDeadline(r) deadline := getDeadlineForQuery(r)
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
return fmt.Errorf("cannot parse form values: %s", err) return fmt.Errorf("cannot parse form values: %s", err)
@ -333,7 +334,7 @@ var labelValuesDuration = metrics.NewSummary(`vm_request_duration_seconds{path="
// LabelsCountHandler processes /api/v1/labels/count request. // LabelsCountHandler processes /api/v1/labels/count request.
func LabelsCountHandler(w http.ResponseWriter, r *http.Request) error { func LabelsCountHandler(w http.ResponseWriter, r *http.Request) error {
startTime := time.Now() startTime := time.Now()
deadline := getDeadline(r) deadline := getDeadlineForQuery(r)
labelEntries, err := netstorage.GetLabelEntries(deadline) labelEntries, err := netstorage.GetLabelEntries(deadline)
if err != nil { if err != nil {
return fmt.Errorf(`cannot obtain label entries: %s`, err) return fmt.Errorf(`cannot obtain label entries: %s`, err)
@ -352,7 +353,7 @@ var labelsCountDuration = metrics.NewSummary(`vm_request_duration_seconds{path="
// See https://prometheus.io/docs/prometheus/latest/querying/api/#getting-label-names // See https://prometheus.io/docs/prometheus/latest/querying/api/#getting-label-names
func LabelsHandler(w http.ResponseWriter, r *http.Request) error { func LabelsHandler(w http.ResponseWriter, r *http.Request) error {
startTime := time.Now() startTime := time.Now()
deadline := getDeadline(r) deadline := getDeadlineForQuery(r)
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
return fmt.Errorf("cannot parse form values: %s", err) return fmt.Errorf("cannot parse form values: %s", err)
@ -442,7 +443,7 @@ var labelsDuration = metrics.NewSummary(`vm_request_duration_seconds{path="/api/
// SeriesCountHandler processes /api/v1/series/count request. // SeriesCountHandler processes /api/v1/series/count request.
func SeriesCountHandler(w http.ResponseWriter, r *http.Request) error { func SeriesCountHandler(w http.ResponseWriter, r *http.Request) error {
startTime := time.Now() startTime := time.Now()
deadline := getDeadline(r) deadline := getDeadlineForQuery(r)
n, err := netstorage.GetSeriesCount(deadline) n, err := netstorage.GetSeriesCount(deadline)
if err != nil { if err != nil {
return fmt.Errorf("cannot obtain series count: %s", err) return fmt.Errorf("cannot obtain series count: %s", err)
@ -482,7 +483,7 @@ func SeriesHandler(w http.ResponseWriter, r *http.Request) error {
if err != nil { if err != nil {
return err return err
} }
deadline := getDeadline(r) deadline := getDeadlineForQuery(r)
tagFilterss, err := getTagFilterssFromMatches(matches) tagFilterss, err := getTagFilterssFromMatches(matches)
if err != nil { if err != nil {
@ -551,7 +552,7 @@ func QueryHandler(w http.ResponseWriter, r *http.Request) error {
if err != nil { if err != nil {
return err return err
} }
deadline := getDeadline(r) deadline := getDeadlineForQuery(r)
lookbackDelta, err := getMaxLookback(r) lookbackDelta, err := getMaxLookback(r)
if err != nil { if err != nil {
return err return err
@ -674,7 +675,7 @@ func QueryRangeHandler(w http.ResponseWriter, r *http.Request) error {
} }
func queryRangeHandler(w http.ResponseWriter, query string, start, end, step int64, r *http.Request, ct int64) error { func queryRangeHandler(w http.ResponseWriter, query string, start, end, step int64, r *http.Request, ct int64) error {
deadline := getDeadline(r) deadline := getDeadlineForQuery(r)
mayCache := !getBool(r, "nocache") mayCache := !getBool(r, "nocache")
lookbackDelta, err := getMaxLookback(r) lookbackDelta, err := getMaxLookback(r)
if err != nil { if err != nil {
@ -866,12 +867,21 @@ func getMaxLookback(r *http.Request) (int64, error) {
return getDuration(r, "max_lookback", d) return getDuration(r, "max_lookback", d)
} }
func getDeadline(r *http.Request) netstorage.Deadline { func getDeadlineForQuery(r *http.Request) netstorage.Deadline {
dMax := int64(maxQueryDuration.Seconds() * 1e3)
return getDeadlineWithMaxDuration(r, dMax)
}
func getDeadlineForExport(r *http.Request) netstorage.Deadline {
dMax := int64(maxExportDuration.Seconds() * 1e3)
return getDeadlineWithMaxDuration(r, dMax)
}
func getDeadlineWithMaxDuration(r *http.Request, dMax int64) netstorage.Deadline {
d, err := getDuration(r, "timeout", 0) d, err := getDuration(r, "timeout", 0)
if err != nil { if err != nil {
d = 0 d = 0
} }
dMax := int64(maxQueryDuration.Seconds() * 1e3)
if d <= 0 || d > dMax { if d <= 0 || d > dMax {
d = dMax d = dMax
} }