Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve temporary buffer usage for WebSocket PerMessageDeflate. #5499

Closed
leonchen83 opened this issue Oct 25, 2020 · 8 comments
Closed

Improve temporary buffer usage for WebSocket PerMessageDeflate. #5499

leonchen83 opened this issue Oct 25, 2020 · 8 comments
Assignees

Comments

@leonchen83
Copy link
Contributor

leonchen83 commented Oct 25, 2020

Jetty version
9.4.x
Java version
java-11
OS type/version
unix
Description

CompressExtension.decompress method

protected void decompress(ByteAccumulator accumulator, ByteBuffer buf) throws DataFormatException
    {
        if ((buf == null) || (!buf.hasRemaining()))
        {
            return;
        }
        byte[] output = new byte[DECOMPRESS_BUF_SIZE];

        ...
    }

we use async-profiler to profile memory allocate and found that
byte[] output = new byte[DECOMPRESS_BUF_SIZE]; cosume too many memory as following
屏幕快照 2020-10-25 下午4 07 20

could we create that byte[] use thread local like

private static ThreadLocal<byte[]> BYTE = ThreadLocal.withInitial(() -> new byte[DECOMPRESS_BUF_SIZE]);
protected void decompress(ByteAccumulator accumulator, ByteBuffer buf) throws DataFormatException
    {
        if ((buf == null) || (!buf.hasRemaining()))
        {
            return;
        }
        byte[] output = BYTE.get();

        ...
    }
@gregw
Copy link
Contributor

gregw commented Oct 26, 2020

@lachlan-roberts can you write a comment saying the status of your work to pool buffers used for gzip - that's mostly jetty-10 right??

What can be done in 9.4 and is this approach compatible... at least for 9?

@lachlan-roberts
Copy link
Contributor

The 9.4 implementation is quite inefficient and I don't think the ThreadLocal would improve it much. We are reading into this temporary byte array, but then copy this into a ByteAccumulator with another byte array allocation, the data in the ByteAccumulator is eventually transfered to a ByteBuffer taken from the ByteBufferPool.

There was a big rework of the CompressExtension / PerMessageDeflateExtension in Jetty 10 and now we use the ByteBufferPool to get buffers for this. We use frame fragmentation, we decompress directly into a ByteBuffer taken from the pool and then forward this on before decompressing any more. So we avoid all this unnecessary copying and byte array allocations.

I don't think it would be very easy to bring back these changes to 9.4.x. It would require lots of changes specific to 9.4 for the CompressExtension and PerMessageDeflateExtension.

@gregw
Copy link
Contributor

gregw commented Oct 27, 2020

Thanks @lachlan-roberts. So it doesn't sound that we can back port the fixes.... but then it also sounds like 9.4 has some low hanging fruit that could offer some improvements.
The byte accumulator class looks like it could be rewritten.... so that either it is a chain of temporary byte arrays that are copied once into a pooled byte buffer... or perhaps it can accumulate directly into a ByteBuffer, only copying (or chaining) if the capacity is exceeded.

So let's keep this open and once 10 is out the door (priority) see if there is something we can do.

leonchen83 pushed a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
@leonchen83
Copy link
Contributor Author

leonchen83 commented Oct 28, 2020

@gregw @lachlan-roberts
hi I made a PR5520 to improve this issue.
could you help me to review that code. If that PR5520 can't merge to branch for some reason, that is OK , hope some idea in that PR5520 that can help you to improve this issue.

leonchen83 pushed a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 pushed a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 pushed a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 pushed a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: chenby <[email protected]>
leonchen83 pushed a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: chenby <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: leonchen83 <[email protected]>
leonchen83 pushed a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: leonchen83 <[email protected]>
@joakime
Copy link
Contributor

joakime commented Oct 28, 2020

Fixing memory is a good goal.

But using a ThreadLocal is not an option here.

The WebSocket implementation in Jetty is asynchronous, meaning that for any websocket message it's very probable that more than 1 thread is used to read from network, parse websocket frames, send frame through extension stack, etc ...

@joakime
Copy link
Contributor

joakime commented Oct 28, 2020

@gregw @lachlan-roberts
hi I made a PR5520 to improve this issue.
could you help me to review that code. If that PR5520 can't merge to branch for some reason, that is OK , hope some idea in that PR5520 that can help you to improve this issue.

Most Important: Fix your ECA, that PR can never be merged unless you have a proper ECA.

leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 28, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 29, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
@leonchen83
Copy link
Contributor Author

leonchen83 commented Oct 30, 2020

@lachlan-roberts @gregw @joakime
after fix the memory allocation is following
image

leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteArray method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteBuffer method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteBuffer method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteBuffer method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteBuffer method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteBuffer method

Signed-off-by: Baoyi Chen <[email protected]>
leonchen83 added a commit to leonchen83/jetty.project that referenced this issue Oct 30, 2020
this PR let the ByteAccumulator recyclable. after invoke ByteAccumulator.transferTo method
we can invoke ByteAccumulator.recycle method to reuse byte[] via ByteAccumulator.newByteBuffer method

Signed-off-by: Baoyi Chen <[email protected]>
lachlan-roberts added a commit that referenced this issue Nov 13, 2020
lachlan-roberts added a commit that referenced this issue Nov 13, 2020
lachlan-roberts added a commit that referenced this issue Nov 17, 2020
lachlan-roberts added a commit that referenced this issue Nov 17, 2020
lachlan-roberts added a commit that referenced this issue Dec 15, 2020
Issue #5499 - Reduce buffer allocations and copying from ByteAccumulator
@lachlan-roberts lachlan-roberts changed the title CompressExtension.decompress use ThreadLocal<byte[]> to reuse byte[] so that aovid allocate extra memory Improve temporary buffer usage for WebSocket PerMessageDeflate. Dec 15, 2020
@lachlan-roberts
Copy link
Contributor

Closing as PR #5574 has been merged and has improved the memory allocation from PerMessageDeflateExtension.

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

No branches or pull requests

4 participants