pjfanning opened a new pull request, #3510:
URL: https://github.com/apache/pekko/pull/3510

   ### Motivation
   `deserializeCompressionAdvertisement` (`ArteryMessageSerializer:179-192`) 
resolves every key in
   the advertised table — for actor refs that means `resolveActorRef`, which 
parses a path and
   populates the per-thread resolve cache. The key list was unbounded, so the 
only limit was the
   transport frame size.
   
   Measured on this branch:
   
   ```
      256 entries ->     9009 wire bytes,  32 ms
     1000 entries ->    35793 wire bytes,  37 ms
    10000 entries ->   368793 wire bytes, 150 ms
    50000 entries ->  1922409 wire bytes, 622 ms
   ```
   
   256 is what a peer legitimately advertises (`compression.actor-refs.max` 
defaults to 256), and
   9 KB. The default `maximum-frame-size` of 256 KiB allows roughly 7000 
entries, so the reachable
   worst case is around 100 ms of CPU on the inbound control stream per 
message, repeatable.
   
   ### Modification
   Reject an advertisement carrying more entries than
   `pekko.remote.artery.advanced.compression.<table>.max` — the setting that 
bounds the table on
   the sending side, parsed here the same way `ArterySettings` parses it. When 
it is `"off"`
   locally the setting is 0, there is no configured number to check against, 
and no bound is
   applied.
   
   **The tradeoff worth a reviewer's attention:** this bounds by the 
*receiver's* setting, but the
   table is sized by the *sender's*. Configurations are normally uniform across 
a cluster, but
   during a rolling change of `actor-refs.max` a node still on the smaller 
value would reject a
   larger advertisement. I checked what that costs before choosing it: a 
`fromBinary` failure on
   the inbound stream is caught at `Codecs.scala:692-704`, which logs an error 
and drops the
   message — no quarantine — and `InboundCompressions` resends advertisements 
periodically
   (`InboundCompressions.scala:553`, "The ActorRefCompressionAdvertisement 
message is resent
   because it can be lost"). So the worst case for a skewed config is that 
compression is not
   established for that association until both sides are updated; messages 
still flow uncompressed.
   If reviewers would rather have headroom than exactness, the alternative is a 
separate setting
   with a default well above the table maxes.
   
   ### What I did not change
   The review this came from also flagged `ActorRefResolveCache` as 
hash-floodable:
   `LruBoundedCache` never grows and `Unsafe.fastHash` is seeded with two fixed 
public constants,
   so colliding actor paths can be precomputed offline. I measured it rather 
than assume:
   generating 4096 keys that all land in one slot took 558 ms, and cache 
operations then went from
   2347 ns to 13631 ns, about 5.8x.
   
   That is a real effect but far short of the degradation I expected, the cache 
is bounded at 1024
   entries so nothing grows without limit, and closing it means changing the 
seed of a public
   `Unsafe.fastHash`. 5.8x on one cache lookup does not seem to justify that, 
so I left it alone
   and am recording the numbers here instead.
   
   ### Result
   An oversized advertisement is reported as a serialization failure. A 
legitimately sized one is
   unaffected.
   
   ### Tests
   - `sbt "remote/testOnly org.apache.pekko.remote.serialization.*"` — 195 
passed, 1 pending
   
   One new test in `ArteryMessageSerializerSpec`, checked to discriminate by 
reverting the
   production file and re-running, where it fails with `no exception was 
thrown`:
   
   - `reject a compression table advertisement with more entries than the 
configured maximum` —
     asserts a table of exactly `max` entries still deserializes, and that `max 
+ 1` is rejected
   
   - `sbt "remote/mimaReportBinaryIssues"` — no issues
   - `sbt "remote/scalafmtCheckAll" headerCreateAll` — clean
   
   ### References
   Touches the same method as #3507, so whichever merges second needs a trivial 
rebase; the two
   guards are independent.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to