Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added streaming remote read client side functionality (fork) #8351

Closed
wants to merge 1 commit into from

Conversation

wycbox
Copy link

@wycbox wycbox commented Jan 8, 2021

The origin pull request(#7354) is already stale, so I fork it and try to finish it.

Fixes #5926

@wycbox
Copy link
Author

wycbox commented Jan 8, 2021

@bwplotka please review it.

Base automatically changed from master to main February 23, 2021 19:36
Copy link
Member

@tomwilkie tomwilkie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for resurrecting this @wwformat! Bunch of minor nits, nothing major.

I moved the remote read server code into the remote package in #8536, so I think this might need rebasing against that. It might also make writing an e2e test easier?

@@ -99,7 +100,7 @@ type ClientConfig struct {
// ReadClient uses the SAMPLES method of remote read to read series samples from remote server.
// TODO(bwplotka): Add streamed chunked remote read method as well (https://github.com/prometheus/prometheus/issues/5926).
type ReadClient interface {
Read(ctx context.Context, query *prompb.Query) (*prompb.QueryResult, error)
StartRead(ctx context.Context, query *prompb.Query, sortSeries bool) (storage.SeriesSet, error)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to rename the method?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think StartRead is asynchronous method name, it imply that the result storage.SeriesSet must be handled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do this all the time, we have method Query and Select that gives SeriesSet so it might be ok to have just Read for simplicity and consistency (:

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@@ -99,7 +100,7 @@ type ClientConfig struct {
// ReadClient uses the SAMPLES method of remote read to read series samples from remote server.
// TODO(bwplotka): Add streamed chunked remote read method as well (https://github.com/prometheus/prometheus/issues/5926).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment can be removed now.

if httpResp.StatusCode/100 != 2 {
return nil, errors.Errorf("remote server %s returned HTTP status %s: %s", c.url.String(), httpResp.Status, strings.TrimSpace(string(compressed)))
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure removing this is correct - for the sample response path, we never seen to check the status code?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How? We still have it removed (:

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this code to Client.Read to handle sample/stream response path, like:

	start := time.Now()
	httpResp, err := c.Client.Do(httpReq)
	if err != nil {
		return nil, errors.Wrap(err, "error sending request")
	}

	if httpResp.StatusCode/100 != 2 {
		httpResp.Body.Close()
		return nil, errors.Errorf("remote server %s returned HTTP status %s: %s", c.url.String(), httpResp.Status, strings.TrimSpace(string(compressed)))
	}

"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/pkg/textparse"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/tsdb/tsdbutil"
"github.com/stretchr/testify/require"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try and keep non-prometheus/prometheus imports in a separate block.

Copy link
Member

@bwplotka bwplotka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! LGTM overall, just minor suggestions.

Sorry for the massive lag on review. Would you like to fix the last nits?

@@ -99,7 +100,7 @@ type ClientConfig struct {
// ReadClient uses the SAMPLES method of remote read to read series samples from remote server.
// TODO(bwplotka): Add streamed chunked remote read method as well (https://github.com/prometheus/prometheus/issues/5926).
type ReadClient interface {
Read(ctx context.Context, query *prompb.Query) (*prompb.QueryResult, error)
StartRead(ctx context.Context, query *prompb.Query, sortSeries bool) (storage.SeriesSet, error)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do this all the time, we have method Query and Select that gives SeriesSet so it might be ok to have just Read for simplicity and consistency (:

return nil, errors.Errorf("not supported remote read content type: %s", contentType)
}

// Handling streamed response
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have comments a full sentence 🤗

Suggested change
// Handling streamed response
// Handling streamed response.

if httpResp.StatusCode/100 != 2 {
return nil, errors.Errorf("remote server %s returned HTTP status %s: %s", c.url.String(), httpResp.Status, strings.TrimSpace(string(compressed)))
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How? We still have it removed (:

@Tanemahuta
Copy link

Hi there. I have a suggestion for refactoring the complete ReadClient.
My suggestions breaks the interface though, but unifies the way to read the time series either streamed or unstreamed.
It will also solve the problem of executing multiple queries at once (as mentioned the TODO in the client).

The API looks as follows:

type ReadClient interface {
	Read(ctx context.Context, stream bool, queries ...*prompb.Query) (ReadResponse, error)
}

// ReadResponse is the interface for an iterable response
type ReadResponse interface {
	// Next returns true in case there is another time series
	Next() bool
	// At returns a partial or full TimeSeries or nil
	At() *TimeSeries
	// Err denotes the error that iteration as failed with. When an error occurs, set cannot continue to iterate.
	Err() error
	// IsPartial returns true if the TimeSeries in this response are chunked
	IsPartial() bool
}

// TimeSeries represents a partial or complete time series from a query
type TimeSeries struct {
	// Labels denote the identifier of the TimeSeries
	Labels []prompb.Label
	// Samples denote the time stamps and values
	Samples []prompb.Sample
	// QueryIdx denotes the index of the original query
	QueryIdx int64
}

The implementation is done, but I have to create tests for it.

Since this would most probably replace 100% of the code of this PR, I would like all of the participants to decide if this approach or the one of PR is preferred.

Best regards, Christian

Signed-off-by: Yunchuan Wen <yunchuanwen@gmail.com>
@pstibrany
Copy link
Contributor

What is the status of this PR? It seems like in the current state it was good-enough to be merged. Is there anything we can do to help?

@juansc
Copy link

juansc commented Jul 19, 2022

We're also looking forward to this feature. Any updates?

@Sniper91
Copy link
Contributor

I think both #8351 and #11379 are not good enough.
The read client interface below isn't properly designed.

StartRead(ctx context.Context, query *prompb.Query, sortSeries bool) (storage.SeriesSet, error)

if response type is sampled, it's ok to return storage.SeriesSet.
But if response type is chunked, the chunked data must be decompressed to return storage.SeriesSet.
In ChunkQuerier method

func (q *chunkQuerier) Select(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.ChunkSeriesSet {

the storage.SeriesSet is compressed to return storage.ChunkSeriesSet.
So the chunked data firstly are decompressed and then compressed if storage.ChunkQuerier.Select is invoked.
I think it depends on the response type to return storage.SeriesSet or storage.ChunkedSeriesSet.

@wycbox wycbox closed this Mar 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow Prometheus to use ReadRequest_STREAMED_XOR_CHUNKS when calling remote read API.
7 participants