Skip to content

SSLStream should not use the ArrayPool for it's internal buffers #49001

@davidfowl

Description

@davidfowl

Description

Today SSLStream uses a 4K buffer for the TLS handshake and a 16K buffer for the reading TLS frames. These buffers come from the array pool today which makes it really easy to exhaust the buckets in the shared array pool for those commonly used sizes. This affects websocket and any other scenario that results in a large number of long lived concurrent connections.

Regression?

No.

Data

A demo of 5000 websocket connections connected to an ASP.NET Core server using Kestrel:

Here's a heap dump sorted by inclusive size. Most of what is being held onto is array pool buffers.
image

On top of that, I took a trace of the same set of connections and you can see the ArrayPool event source says the number of buffers allocated is 5000. The buffers are all 32K in size (because of how the SslSteam adds the FrameOverhead).

image

Allocation profile of 5000 websocket connections. You can see the array pool has the most byte[] allocations.

image

They're mostly in the handshake and reading (I'm not writing in this app), just sitting mostly idle with ping pongs:

image

Analysis

We shouldn't use the array pool buffers for reads that may take a long time. That means both for the handshake and the encryption/decryption:

_internalBuffer = ArrayPool<byte>.Shared.Rent(ReadBufferSize);

The handshake will end up doing the same for 8K buffers in the pool but potentially for a much shorter duration as clients negotiate quickly and there's a timeout to complete the handshake (in kestrel).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions