lib/promscrape: avoid copying response body when scraping targets.

This should reduce memory usage when scraping targets with millions of metrics.
This commit is contained in:
Aliaksandr Valialkin 2020-09-18 12:31:16 +03:00
parent 70c721c01b
commit 1a9ee39b0e

View file

@ -97,7 +97,16 @@ func (c *client) ReadData(dst []byte) ([]byte, error) {
req.Header.Set("Authorization", c.authHeader) req.Header.Set("Authorization", c.authHeader)
} }
resp := fasthttp.AcquireResponse() resp := fasthttp.AcquireResponse()
swapResponseBodies := len(dst) == 0
if swapResponseBodies {
// An optimization: write response directly to dst.
// This should reduce memory uage when scraping big targets.
dst = resp.SwapBody(dst)
}
err := doRequestWithPossibleRetry(c.hc, req, resp, deadline) err := doRequestWithPossibleRetry(c.hc, req, resp, deadline)
if swapResponseBodies {
dst = resp.SwapBody(dst)
}
statusCode := resp.StatusCode() statusCode := resp.StatusCode()
if err == nil && (statusCode == fasthttp.StatusMovedPermanently || statusCode == fasthttp.StatusFound) { if err == nil && (statusCode == fasthttp.StatusMovedPermanently || statusCode == fasthttp.StatusFound) {
// Allow a single redirect. // Allow a single redirect.
@ -125,14 +134,21 @@ func (c *client) ReadData(dst []byte) ([]byte, error) {
dstLen := len(dst) dstLen := len(dst)
if ce := resp.Header.Peek("Content-Encoding"); string(ce) == "gzip" { if ce := resp.Header.Peek("Content-Encoding"); string(ce) == "gzip" {
var err error var err error
dst, err = fasthttp.AppendGunzipBytes(dst, resp.Body()) var src []byte
if swapResponseBodies {
src = append(src, dst...)
dst = dst[:0]
} else {
src = resp.Body()
}
dst, err = fasthttp.AppendGunzipBytes(dst, src)
if err != nil { if err != nil {
fasthttp.ReleaseResponse(resp) fasthttp.ReleaseResponse(resp)
scrapesGunzipFailed.Inc() scrapesGunzipFailed.Inc()
return dst, fmt.Errorf("cannot ungzip response from %q: %w", c.scrapeURL, err) return dst, fmt.Errorf("cannot ungzip response from %q: %w", c.scrapeURL, err)
} }
scrapesGunzipped.Inc() scrapesGunzipped.Inc()
} else { } else if !swapResponseBodies {
dst = append(dst, resp.Body()...) dst = append(dst, resp.Body()...)
} }
if statusCode != fasthttp.StatusOK { if statusCode != fasthttp.StatusOK {