perf(loki.process): Reduce goroutines and channels in the stage pipeline - #6873
Draft
csmarchbanks wants to merge 1 commit into
Draft
perf(loki.process): Reduce goroutines and channels in the stage pipeline#6873csmarchbanks wants to merge 1 commit into
csmarchbanks wants to merge 1 commit into
Conversation
csmarchbanks
force-pushed
the
loki-process-many-rules-bench
branch
3 times, most recently
from
August 12, 2026 17:18
1620914 to
09fd2e0
Compare
4 tasks
…hannel per stage Pipeline.Run gave every stage its own goroutine and unbuffered channel, even though almost all stages are pure synchronous single-entry transforms with no need for one. For a pipeline with many stages (e.g. one built from many stage.match rules), that overhead scales linearly with stage count, and under concurrent load it scales with stream count too, since every stream pays it independently. Stage now splits into SyncStage (Process(Entry) (Entry, bool), the common case) and ChannelStage (Run(chan Entry) chan Entry, only for multiline's wall-clock flush and cri/split_json's fan-out). Pipeline precomputes a fused function once when every stage is a SyncStage, and only falls back to channels around the few ChannelStages that need one. stage.match is now one of two concrete types decided at construction (syncMatchStage / asyncMatchStage) depending on whether its nested pipeline is itself fully synchronous. Assisted-by: Claude Sonnet 5
4 tasks
csmarchbanks
force-pushed
the
loki-process-many-rules-bench
branch
from
August 13, 2026 14:58
09fd2e0 to
b18c674
Compare
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brief description of Pull Request
loki.processgave every pipeline stage its own goroutine and unbuffered channel, even though almost all stages are pure synchronous single-entry transforms. For a pipeline built from manystage.matchrules, that overhead scales linearly with stage count, and under concurrent load it scales with stream count too.Stagenow splits intoSyncStage(Process(Entry) (Entry, bool), the common case — composed as plain function calls) andChannelStage(Run(chan Entry) chan Entry, only formultiline's wall-clock flush andcri/split_json's fan-out).Pipelineprecomputes a single fused function when every stage is aSyncStage;stage.matchis one of two concrete types decided at construction depending on whether its nested pipeline is itself fully synchronous.This PR is now chained on top of #6879, which holds the shared benchmark commit as a common base (that commit also picked up a benchmark-harness fix: the drain goroutine wasn't awaited, so a sub-benchmark's leftover work could bleed CPU into the next one's timing). This branch itself contains only the redesign commit (
b18c6744d).git checkout loki-process-benchmarksvsgit checkout loki-process-many-rules-benchreproduces the numbers below directly.benchstat,GOMAXPROCS=2(representative of a CPU-limited container),-count=10, re-run against the fixed benchmark harness (this supersedes the numbers previously posted here, which predated that fix):PipelineManyRulesis one stream, mostly idle.PipelineOneMultilineAmongManyRuleschecks that a single stage needing its own channel (nestingstage.multiline) doesn't drag the rest of a 1000-rule pipeline back to the old per-stage-channel cost — it doesn't;one_multiline_in_middlemeasuring faster thanall_syncis a GOMAXPROCS-dependent artifact of an even split enabling incidental cross-core pipelining, not something this design relies on (it disappears atGOMAXPROCS=1).PipelineManyStreamsSaturatedmodels many concurrent streams actually competing for the CPU rather than one idle stream, which is the throughput number that matters for a loaded instance: +577% entries/sec, alongside an 84% cut in memory and 91% fewer allocations per op (fewer goroutines/channels in flight).Verified with
go test -raceacrossinternal/component/loki/...and the promtail converter, andgolangci-lint(no new findings).Pull Request Details
Issue(s) fixed by this Pull Request
Notes to the Reviewer
PR Checklist