Skip to content
This repository was archived by the owner on Jul 22, 2026. It is now read-only.

Fix dark cluster URI rewrite deopt storm consuming 80% CPU - #1160

Closed
jcleezer wants to merge 6 commits into
masterfrom
jleezer/dc-deop-storm
Closed

Fix dark cluster URI rewrite deopt storm consuming 80% CPU #1160
jcleezer wants to merge 6 commits into
masterfrom
jleezer/dc-deop-storm

Conversation

@jcleezer

@jcleezer jcleezer commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds UriBuilder.replaceQueryFrom(URI) that copies the raw (already percent-encoded) query string directly from a source URI, bypassing the expensive character-by-character UriComponent._encode loop.
  • Simplifies D2URIRewriter to use the new method — removes the skipReEncoding flag, 2-arg constructor, and rewriteURIFromRaw workaround.
  • Updates DarkClusterManagerImpl to use the simplified single-arg D2URIRewriter constructor.

Problem

Production profiling shows DarkClusterFilter.onRestRequestDarkClusterManagerImpl.rewriteRequestD2URIRewriter.rewriteURIUriBuilder.replaceQueryUriComponent._encode consuming ~82% of total CPU.

The root cause: replaceQuery(d2Uri.getRawQuery()) passes an already percent-encoded query string into _encode, which iterates every character via codePointAt only to leave them unchanged. For large query strings this is devastating,
especially under JIT deoptimization.

Fix

Rather than bypassing UriBuilder entirely (the previous skipReEncoding approach), this puts the fix in the right layer: UriBuilder.replaceQueryFrom(URI) copies uri.getRawQuery() directly into the builder's internal query field —
which already expects percent-encoded values (see UriBuilder.uri() lines 202-206 which do the same thing).

This means:

  • Any caller doing URI-to-URI rewriting benefits, not just D2URIRewriter
  • No duplicated URI assembly logic outside UriBuilder
  • D2URIRewriter goes back to being a simple, single-path class

Test plan

  • UriBuilder.replaceQueryFrom(URI) tested via existing UriComponentTest suite
  • TestD2URIRewriter — simple rewrite, encoded queries, no query, fragment, exhaustive ASCII character preservation
  • TestDarkClusterUrlRewrite — basic rewrite, query params, encoded query params
  • ./gradlew :li-jersey-uri:test :d2:test --tests TestD2URIRewriter :darkcluster:test --tests TestDarkClusterUrlRewrite passes

Jason Leezer added 4 commits April 7, 2026 17:44
…append(String) is an intrinsic, a single System.arraycopy

  - No bimodal branching — no speculative optimization to get wrong
  - Monomorphic call sites — StringBuilder.append and URI.create are stable JIT targets with no polymorphic dispatch
Comment thread d2/src/main/java/com/linkedin/d2/balancer/util/D2URIRewriter.java Outdated
Jason Leezer and others added 2 commits April 8, 2026 17:41
Instead of bypassing UriBuilder entirely with a skipReEncoding flag and
raw StringBuilder assembly in D2URIRewriter, add a replaceQueryFrom(URI)
method to UriBuilder that copies the raw query directly. This puts the
fix in the right layer so any caller doing URI rewriting benefits.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@sashagavrilov sashagavrilov left a comment

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.

LGTM

@ChrisCarini

Copy link
Copy Markdown
Member

The linkedin/rest.li repository is being archived - see #1178 for details.

Ahead of it's archiving, we are closing all issues and PRs.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants