Skip to content

[fix][ml] OOM caused by orphan items in ActiveManagedCursorContainerImpl.pendingPositionUpdates - #26506

Closed
poorbarcode wants to merge 1 commit into
apache:masterfrom
poorbarcode:fix_cache_oom
Closed

poorbarcode wants to merge 1 commit into
apache:masterfrom
poorbarcode:fix_cache_oom

Conversation

@poorbarcode

@poorbarcode poorbarcode commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

The issue was introduced by #24623, only affects the version newer than 4.1.0

Background

  • ActiveManagedCursorContainerImpl traces the slowest position of cursors.
  • To delay the calculation of the slowest position, ActiveManagedCursorContainerImpl maintains two collections: pendingRemovedCursors and pendingPositionUpdates.
  • pendingRemovedCursors caches the events that cursors are inactive, and pendingPositionUpdates caches the events that cursors are active.
  • When getting the slowest position, it flushes pendingRemovedCursors and pendingPositionUpdates.
    • (Highlight) If no such call was made, it never flushes

Issue

With cacheEvictionByExpectedReadCount enabled, a cursor can be removed before its read any messages. The removed cursor is no longer tracked in the Managed ledger, but its node remains in ActiveManagedCursorContainerImpl.pendingPositionUpdates until a future pending-position flush. If no such flush is triggered, repeated cursor creation and removal can accumulate stale nodes and retain their associated cursor objects, increasing memory usage and potentially causing OOM.

It can be reproduced with the following steps. See also the new test.

  • create a topic
  • create subscription 1
  • delete the subscription
    • an orphan item is left in ActiveManagedCursorContainerImpl.pendingPositionUpdates.
  • create subscription 2
  • delete the subscription
    • the second orphan item is left in ActiveManagedCursorContainerImpl.pendingPositionUpdates.
  • ...

Modifications

Count orphan items in ActiveManagedCursorContainerImpl.pendingPositionUpdates, flush pending cursor updates, and reset the counter when the count of orphan items is 10.

Does this pull request potentially affect one of the following parts:

If the box was checked, please highlight the changes

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

@poorbarcode poorbarcode added this to the 5.0.0-M2 milestone Sep 8, 2026
@poorbarcode poorbarcode self-assigned this Sep 8, 2026
@merlimat
merlimat requested a review from lhotari September 8, 2026 22:28
@Technoboy- Technoboy- changed the title [fix][managed-ledger] OOM caused by orphan items in ActiveManagedCursorContainerImpl.pendingPositionUpdates [fix][ml] OOM caused by orphan items in ActiveManagedCursorContainerImpl.pendingPositionUpdates Sep 9, 2026
cursorRemovedTimestampMillis = System.currentTimeMillis();
cursorCount--;
// Clear meaningless pending update, which avoids OOM.
if (meaninglessPendingUpdateCount >= 10) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

10 times, how to balance this value?

@lhotari

lhotari commented Sep 9, 2026

Copy link
Copy Markdown
Member

@poorbarcode Thanks for pinpointing the issue! However, the approach taken in this PR introduces additional position flushes in ActiveManagedCursorContainerImpl, which uses lazy updates to
efficiently track the slowest cursor and the number of cursors at or before a given cursor’s position. While reviewing your PR, I also spotted an existing bug: getSlowestCursorPosition()
could mutate internal state while holding only a read lock. Therefore, I’ve proposed a replacement in #26511 that fixes both issues while preserving lazy updates. Local benchmarks show
improved cursor-churn performance compared with this PR. An additional benefit is that ManagedCursor references are dropped immediately when a cursor is removed. Please review #26511. I'll close this PR since there's a replacement, I hope that's fine.

@lhotari lhotari closed this Sep 9, 2026
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.

3 participants