jetty / jetty.project

Eclipse Jetty® - Web Container & Clients - supports HTTP/2, HTTP/1.1, HTTP/1.0, websocket, servlets, and more
https://eclipse.dev/jetty
Other
3.83k stars 1.91k forks source link

Multiple WebSocket threads getting created for every single client connection #10850

Open Spandana806 opened 10 months ago

Spandana806 commented 10 months ago

10.0.13

Multiple websocket threads being instantiated for every WebSocketClient.start() call

WebSocketClient client = new WebSocketClient(); client.start(); client.connect(endpoint, URI.create("ws://host:port/endpoint/"));

Below is the thread dump with websocket threads: "WebSocket@88584176-46" #46 prio=5 os_prio=0 cpu=0.00ms elapsed=41.18s tid=0x000001a262077b00 nid=0x2fd8 runnable [0x0000009ee36fe000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.WEPoll.wait(java.base@17.0.8.1/Native Method) at sun.nio.ch.WEPollSelectorImpl.doSelect(java.base@17.0.8.1/WEPollSelectorImpl.java:111) at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@17.0.8.1/SelectorImpl.java:129)

"WebSocket@88584176-47" #47 prio=5 os_prio=0 cpu=46.88ms elapsed=41.18s tid=0x000001a262072a00 nid=0x4124 waiting on condition [0x0000009ee3efe000] java.lang.Thread.State: TIMED_WAITING (parking) at jdk.internal.misc.Unsafe.park(java.base@17.0.8.1/Native Method)

"WebSocket@88584176-48" #48 prio=5 os_prio=0 cpu=0.00ms elapsed=41.18s tid=0x000001a262073420 nid=0x6b64 runnable [0x0000009ee40ff000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.WEPoll.wait(java.base@17.0.8.1/Native Method) at sun.nio.ch.WEPollSelectorImpl.doSelect(java.base@17.0.8.1/WEPollSelectorImpl.java:111) at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@17.0.8.1/SelectorImpl.java:129)

"WebSocket@88584176-49" #49 prio=5 os_prio=0 cpu=0.00ms elapsed=41.18s tid=0x000001a262073930 nid=0x5140 runnable [0x0000009ee41ff000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.WEPoll.wait(java.base@17.0.8.1/Native Method) at sun.nio.ch.WEPollSelectorImpl.doSelect(java.base@17.0.8.1/WEPollSelectorImpl.java:111) at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@17.0.8.1/SelectorImpl.java:129)

"WebSocket@88584176-50" #50 prio=5 os_prio=0 cpu=0.00ms elapsed=41.18s tid=0x000001a262074860 nid=0x69b4 runnable [0x0000009ee42fe000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.WEPoll.wait(java.base@17.0.8.1/Native Method) at sun.nio.ch.WEPollSelectorImpl.doSelect(java.base@17.0.8.1/WEPollSelectorImpl.java:111) at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@17.0.8.1/SelectorImpl.java:129)

"WebSocket@88584176-51" #51 prio=5 os_prio=0 cpu=0.00ms elapsed=41.18s tid=0x000001a262073e40 nid=0x6178 runnable [0x0000009ee43fe000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.WEPoll.wait(java.base@17.0.8.1/Native Method) at sun.nio.ch.WEPollSelectorImpl.doSelect(java.base@17.0.8.1/WEPollSelectorImpl.java:111) at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@17.0.8.1/SelectorImpl.java:129)

"WebSocket@88584176-52" #52 prio=5 os_prio=0 cpu=15.62ms elapsed=41.18s tid=0x000001a262078520 nid=0x60a0 runnable [0x0000009ee44fe000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.WEPoll.wait(java.base@17.0.8.1/Native Method) at sun.nio.ch.WEPollSelectorImpl.doSelect(java.base@17.0.8.1/WEPollSelectorImpl.java:111) at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@17.0.8.1/SelectorImpl.java:129)

"WebSocket@88584176-53" #53 prio=5 os_prio=0 cpu=437.50ms elapsed=41.18s tid=0x000001a281277510 nid=0x69b8 waiting on condition [0x0000009ee45ff000] java.lang.Thread.State: TIMED_WAITING (parking) at jdk.internal.misc.Unsafe.park(java.base@17.0.8.1/Native Method)

joakime commented 10 months ago

This appears to be a the standard java nio selector allocation based on your hardware. And it's not being created for every single client connection, it's being created for every instance of HttpClient or WebSocketClient. A single HttpClient or WebSocketClient can open and manage hundreds of thousands of client connections (there is no need to be creating / starting multiple clients) All connections will share those selector threads.

Ultimately this is harmless and normal if you use the HttpClient and WebSocketClient properly.

But, If you are not going to be using thousands of websocket connections simultaneously, dial down your selector calculation down to 1. Just keep in mind that you should still use HttpClient and WebSocketClient properly (only 1 instance for however many connections you are going to create) A single selector should be good for around 1000 active connections. (depending on hardware)

Eg:

ClientConnector connector = new ClientConnector();
connector.setSelectors(1);
HttpClient http = new HttpClient(new HttpClientTransportOverHTTP(connector));
http.start();

WebSocketClient ws = new WebSocketClient(http);
ws.start();
Spandana806 commented 10 months ago

Thank you for the quick response.

I am trying to create a websocket proxy server based on discussion in this thread.

I have uploaded the code here

Based on your suggestion, I am creating single instance of WebSocketContainer here.

After which I see the below threads getting created and will stay through out the period my server runs: one - Connector-Scheduler-6e1ae763-1 one - HttpClient@a94a452-scheduler-1 nine - WebSocket

My next set of questions are:

sbordet commented 10 months ago

Why are you worried about those threads? They are necessary for the WebSocket implementation to work.

The scheduler threads are necessary and you see one for the server and one for the client.

The other runnable threads are likely selector threads waiting for connections to be established or readable.

As @joakime you can reduce the number of selectors in both the server and client via configuration.