Skip to content

feat(collector): use FlowSummary to reduce conntrack peak memory#30

Open
sichenzhao wants to merge 2 commits intomainfrom
feat/flow-summary-memory-optimization
Open

feat(collector): use FlowSummary to reduce conntrack peak memory#30
sichenzhao wants to merge 2 commits intomainfrom
feat/flow-summary-memory-optimization

Conversation

@sichenzhao
Copy link

Summary

  • Introduces a lightweight FlowSummary struct containing only the fields kubenetmon uses from conntrack.Flow (tuples and counters), dropping unused fields like Status, Timeout, ProtoInfo, Labels, SeqAdj, SynProxy, etc.
  • Converts []conntrack.Flow to []FlowSummary immediately after each conntrack dump and nils the original slice, allowing the GC to reclaim the heavier objects before the gRPC send loop begins.
  • Updates shouldIgnoreFlow to operate on *FlowSummary instead of *conntrack.Flow.
  • No dependency changes — the ConntrackInterface and its mock remain unchanged; the conversion is internal to the collector.

Inspired by ClickHouse/data-plane-application#31052, adapted for the OSS codebase which uses github.com/ti-mo/conntrack instead of the internal fork.

Test plan

  • Added TestToFlowSummaries with sub-tests for empty input, field extraction (verifying dropped fields), and multi-flow conversion
  • Updated all TestShouldIgnoreFlow sub-tests to use FlowSummary
  • Existing TestCollect integration test passes (exercises the full dump → convert → send path)
  • toFlowSummaries and shouldIgnoreFlow both at 100% coverage
  • Full test suite passes (go test ./...)

🤖 Generated with Claude Code

sichenzhao and others added 2 commits March 20, 2026 04:23
Introduce a lightweight FlowSummary struct that holds only the fields
kubenetmon actually uses (tuples and counters) from conntrack.Flow.
After each conntrack dump the full []conntrack.Flow is immediately
converted to []FlowSummary and released, allowing the GC to reclaim
the heavier Flow objects (which carry unused fields like Status,
Timeout, ProtoInfo, Labels, SeqAdj, SynProxy, etc.) before the
send loop begins.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The `rawFlows = nil` assignment was flagged by golangci-lint (ineffassign)
since the variable is not read after that point. The local variable
becomes unreachable after toFlowSummaries returns, allowing the GC to
collect it without the explicit nil assignment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sichenzhao sichenzhao requested a review from andreev-io March 20, 2026 04:39

now := collector.clock.Now()
flows, err := collector.conntrack.Dump(&conntrack.DumpOptions{ZeroCounters: true})
rawFlows, err := collector.conntrack.Dump(&conntrack.DumpOptions{ZeroCounters: true})
Copy link
Member

@andreev-io andreev-io Mar 20, 2026

Choose a reason for hiding this comment

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

Thank you for putting this up. I think we should swap in conntrack for a fork like we do internally and replace the Flow struct at that level during conversion from netlink messages. Otherwise this change may do more harm than good, since it will be allocating 3 times for each flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants