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

Use one websocket per browser client #2606

Merged
merged 14 commits into from
Oct 27, 2022

Conversation

niloc132
Copy link
Member

@niloc132 niloc132 commented Jun 29, 2022

Creates a new websocket protocol to let the websocket behave only as a transport on which multiple streams, across services, can be conveyed. The websocket will be opened to the path matching the first stream, but after the websocket has started, other streams can be sent on it, using custom metadata/header to give the path to the desired rpc.

By reusing existing paths, the client can signal that it supports either old or new websockets, so it in theory can connect to the old grpc-websockets implementation. Unfortunately, the reference implementation can't handle alternative requested subprotocols, and will just fail the entire request, so this patch breaks our compatibility with that proxy, and so with our netty implementation.

On the other hand, the server will maintain compatibility for both protocols for now, enabling stale js api clients to still be able to connect. We may also find that there are issues with longlived sockets, and might end up wanting to ask the client in some circumstances to use the old implementation.

Fixes #2510

@niloc132
Copy link
Member Author

niloc132 commented Jul 8, 2022

Note that this is dependent on improbable-eng/grpc-web#1112 (and a subsequent release) to correctly allow clients of a netty server to use this client. Alternatively, we could build our own jetty grpc proxy, or build the JS output differently for netty than jetty so that it defaults to non-multiplexed, or drop support for netty as a server entirely.

@niloc132 niloc132 force-pushed the 2510-multiplexed-websocket branch 2 times, most recently from 808fd51 to 1cc40d8 Compare July 11, 2022 13:51
@pete-petey pete-petey modified the milestones: Jul 2022, Sept 2022 Aug 30, 2022
@niloc132 niloc132 force-pushed the 2510-multiplexed-websocket branch from ba25c9b to a6e850b Compare October 6, 2022 19:44
@niloc132 niloc132 changed the title DRAFT: Use one websocket per browser client Use one websocket per browser client Oct 7, 2022
@niloc132 niloc132 marked this pull request as ready for review October 7, 2022 18:41
Copy link
Member

@devinrsmith devinrsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to have server configuration to disable multiplex, as chatted about.

Comment on lines 101 to 113
Map<String, Supplier<Endpoint>> endpoints = Map.of(
"grpc-websockets", () -> filter.create(WebSocketServerStream::new),
"grpc-websockets-multiplex", () -> filter.create(MultiplexedWebSocketServerStream::new));
container.addEndpoint(ServerEndpointConfig.Builder.create(GrpcWebsocket.class, "/{service}/{method}")
.configurator(new ServerEndpointConfig.Configurator() {
@Override
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
// noinspection unchecked
return (T) new GrpcWebsocket(endpoints);
}
})
.subprotocols(Arrays.asList("grpc-websockets", "grpc-websockets-multiplex"))
.build()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move the string constants into GrpcWebsocket, and simplify the constructor to GrpcWebsocket(Supplier<Endpoint> vanilla, Supplier<Endpoint> multiplexed)? A bit more explicit interface between parts IMO.

if (frame != null) {
int numBytes = frame.readableBytes();
if (numBytes > 0) {
onSendingBytes(numBytes);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be numBytes + 4?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this is for grpc internally to decide if it should send more. We don't tell it about http2 framing bytes, so we likewise shouldnt tell it about ws framing.

payload.flip();

websocketSession.getBasicRemote().sendBinary(payload);
transportState.runOnTransportThread(() -> transportState.onSentBytes(numBytes));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be numBytes + 4?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, I don't think that would work.

@devinrsmith devinrsmith self-requested a review October 27, 2022 17:42
@niloc132 niloc132 merged commit f4c230b into deephaven:main Oct 27, 2022
@github-actions github-actions bot locked and limited conversation to collaborators Oct 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Introduce multiplexed grpc-over-websocket proxy to reduce open websockets at runtime
3 participants