Bug 60523 - Reduce number of network packets that server sends to client via WebSocket connection
Summary: Reduce number of network packets that server sends to client via WebSocket co...
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 9
Classification: Unclassified
Component: WebSocket (show other bugs)
Version: 9.0.0.M15
Hardware: All All
: P2 enhancement (vote)
Target Milestone: -----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-12-27 11:59 UTC by Ilgar Kovalyov
Modified: 2017-09-04 16:50 UTC (History)
0 users



Attachments
Patch for WsRemoteEndpointImplBase.java (777 bytes, text/plain)
2016-12-27 11:59 UTC, Ilgar Kovalyov
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ilgar Kovalyov 2016-12-27 11:59:34 UTC
Created attachment 34559 [details]
Patch for WsRemoteEndpointImplBase.java

I am using Tomcat 9 and Spring.

My web application has a websocket service.

My application sends binary messages to client using sendMessage of:

org.springframework.web.socket.WebSocketSession.

I collected tcp packets by wireshark. I see that every binary websocket message uses at least 2 TCP packets.

The first packet is the header, it is small.

There is patch for WsRemoteEndpointImplBase.java from version 9.0.0.M15 in attachement, it
creates one packet from header and tail if it's size not more than 65536 bytes.
Comment 1 Mark Thomas 2017-01-03 17:22:01 UTC
What does this patch do to performance? It adds a couple of copies.
Comment 2 Ilgar Kovalyov 2017-01-09 05:34:54 UTC
(In reply to Mark Thomas from comment #1)
> What does this patch do to performance? It adds a couple of copies.

Yes, it adds a couple of copies in memory but reduces number of network packets.
Network packet transmission takes more time than operations with memory and we have perfomance benefit sending less network packets.
If you wish this perfomance benefit can be checked by test.
Comment 3 Ilgar Kovalyov 2017-01-11 11:00:46 UTC
Yes, it adds a couple of copies in memory but reduces number of network packets.
Network packet transmission takes more time than operations with memory and we have perfomance benefit sending less network packets.
If you wish this perfomance benefit can be checked by test.
Comment 4 Ilgar Kovalyov 2017-01-11 11:01:58 UTC
Answered in previous comment
Comment 5 Mark Thomas 2017-01-11 12:26:14 UTC
The proposed patch will not be applied because it results in significant performance degradation rather than an improvement.

Testing with the Autobahn WebSocket testsuite showed performance decreased more than 2 orders of magnitude when the proposed patch was applied.

Whether the additional copies, the additional allocations or other factors are responsible for the performance degradation might be an interesting topic to research.

Performance bottlenecks are notoriously difficult to identify via code inspection in all but the most trivial of cases.
Comment 6 Ilgar Kovalyov 2017-01-12 08:05:43 UTC
Hello, Mark.
I just installed Autobahn WebSocket testsuite.
Can you tell me more about your tests?
I want to reproduce test results.
What web application did you deployed at tomcat for test purposes?
What test did you run?
Comment 7 Mark Thomas 2017-01-12 09:06:45 UTC
(In reply to Ilgar Kovalyov from comment #6)
> Hello, Mark.
> I just installed Autobahn WebSocket testsuite.
> Can you tell me more about your tests?
> I want to reproduce test results.
> What web application did you deployed at tomcat for test purposes?

The programmatic WebSocket echo example in the Tomcat examples 

> What test did you run?

All of the Autobhan WebSocket server tests.

There are some very old results that give you an idea of the tests being run here:
http://home.apache.org/~markt/dev/autobahn/

I ran a more recent version of those tests (but not the latest).
Comment 8 Joseph Dean 2017-07-19 22:32:13 UTC
I'm experiencing the same behavior. The client library I use to send data to my server over websockets properly bundles the payload length and payload in a single tcp datagram. Data coming from my tomcat server is always sending two datagrams for a single message: one with 2 bytes of payload which is the websocket header + payload length, and the 2nd which is the payload.

From what I can see the doWrite(SendHandler, long, ByteBuffer...) sends each provided buffer in a separate frame. We can see inside this method it invokes:

for (ByteBuffer buffer : buffers) {
  socketWrapper.write(true, buffer);
  // Snip
  socketWrapper.setWriteTimeout(timeout);
  socketWrapper.flush(true);
}

The original patch allocates a new buffer to place both the header and payload in a single buffer before handing it to this method, which resolves the network behavior but results in extra memory copies. Perhaps the more correct solution is to modify WsRemoteEndpointImplServer::doWrite to only do a single socket flush after writing all provided buffers?

The protocol I'm working on sends numerous very small packets; about 90% of my traffic is TCP header overhead. Doubling the number of packets thus nearly doubles my overall bandwidth usage. This is extremely important to my application.
Comment 9 Mark Thomas 2017-07-20 09:23:11 UTC
Re-open to review the most recent comment.
Comment 10 Mark Thomas 2017-09-04 16:50:58 UTC
Fixed in:
- trunk for 9.0.0.M27 onwards
- 8.5.x for 8.5.21 onwards

Fixing this for 8.0.x and earlier would require significant refactoring - effectively the refactoring that took place for 8.5.x.