Skip to content

Query Frontend For Logical Query Plan Support #6884

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

rubywtl
Copy link

@rubywtl rubywtl commented Jul 16, 2025

What this PR does:
This PR adds logical plan generation support to the query frontend as part of the distributed query execution implementation.

Features

  • Added middleware components for:
    • PromQL query parsing
    • Logical plan creation
    • Local optimization pipeline

    Note: Distributed optimizer will be implemented in a future stage

Configuration Changes

  • Added feature flag to query frontend configs to control distributed execution
  • Maintains backwards compatibility with existing Cortex data path

Testing Coverage

  • Integration Tests

    • Verified empty request body when feature flag is disabled
    • Validated existing data path functionality remains intact
  • Unit Tests

    • Confirmed middleware correctly serializes optimized logical query plans
    • Validated request encoding functionality

Which issue(s) this PR fixes:
Related to #6789

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated

@rubywtl rubywtl force-pushed the frontend/middleware-logicalplan-support branch from 5e6383f to 3631c26 Compare July 16, 2025 22:05
@rubywtl rubywtl force-pushed the frontend/middleware-logicalplan-support branch from 7c03859 to 0d12680 Compare July 16, 2025 23:08
@@ -533,12 +533,16 @@ func (t *Cortex) initQueryFrontendTripperware() (serv services.Service, err erro
prometheusCodec,
shardedPrometheusCodec,
t.Cfg.Querier.LookbackDelta,
t.Cfg.Querier.EnablePerStepStats,
t.Cfg.Frontend.DistributedExecEnabled,
t.Cfg.Frontend.DisableDuplicateLabelChecks,
Copy link
Contributor

Choose a reason for hiding this comment

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

I would not expose this as a config for now. Let's always disable duplicate label check

lookbackDelta: lookbackDelta,
enabledPerStepStats: enablePerStepStats,
next: next,
disableDuplicateLabelChecks: disableDuplicateLabelChecks,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can just remove lookbackDelta, enabledPerStepStats and disableDuplicateLabelChecks. Those options only make sense in execution time but not the logicalplan and optimize phase. So it doesn't matter if they are true or false. We can just hardcode to false


// TODO: Add distributed optimizer for remote node insertion

return byteLP, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we just combine NewInstantLogicalPlan and NewRangeLogicalPlan into one NewLogicalPlan function?

return byteLP, nil
}

func (l logicalPlanGen) NewRangeLogicalPlan(qs string, start, end time.Time, interval time.Duration) ([]byte, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I would recommend separating creating logical plan and marshal the logical plan. NewLogicalPlan function should return the plan itself instead of the serialized version.

@@ -96,6 +96,8 @@ type Request interface {
GetStep() int64
// GetQuery returns the query of the request.
GetQuery() string
// GetLogicalPlan returns the serialized logical plan
GetLogicalPlan() []byte
Copy link
Contributor

Choose a reason for hiding this comment

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

It probably makes more sense if GetLogicalPlan returns the plan type instead of the serialized version. So we need to keep logical plan as a Plan type here.
We can do the serialization in the Codec encode request part

@@ -26,7 +26,7 @@ import (
)

const (
query = "/api/v1/query_range?end=1536716898&query=sum%28container_memory_rss%29+by+%28namespace%29&start=1536673680&stats=all&step=120"
queryAll = "/api/v1/query_range?end=1536716898&query=sum%28container_memory_rss%29+by+%28namespace%29&start=1536673680&stats=all&step=120"
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need to rename this?

@@ -29,6 +31,8 @@ func (cfg *CombinedFrontendConfig) RegisterFlags(f *flag.FlagSet) {
cfg.FrontendV2.RegisterFlags(f)

f.StringVar(&cfg.DownstreamURL, "frontend.downstream-url", "", "URL of downstream Prometheus.")
f.BoolVar(&cfg.DistributedExecEnabled, "frontend.distributed_exec_enabled", false, "Experimental: Enables distributed execution of queries by passing logical query plan fragments to downstream components.")
Copy link
Contributor

Choose a reason for hiding this comment

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

You need to run make doc to generate docs. Otherwise CI will fail

"net/http"
"strconv"
"testing"
"time"
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's try to sort and group the imports. Otherwise lint will fail

"github.com/thanos-io/promql-engine/query"
"github.com/weaveworks/common/httpgrpc"
"net/http"
"time"
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's try to sort and group the imports. Otherwise lint will fail

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.

2 participants