Add the protocol-comparison module
This commit is contained in:
83
protocol-comparison/docs/01-three-protocols.md
Normal file
83
protocol-comparison/docs/01-three-protocols.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# 1. The same use case, three ways
|
||||
|
||||
Next: [2. How they measure](02-benchmarks.md)
|
||||
|
||||
---
|
||||
|
||||
One application in this module serves the same two operations over gRPC, RSocket and a raw
|
||||
WebSocket: fetch one quote, and stream N quotes. Same JVM, same heap, same
|
||||
[`QuoteSource`](../src/main/java/com/ankurm/protocols/QuoteSource.java), same five fields.
|
||||
|
||||
That constraint is the point. Cross-protocol benchmarks published on the internet almost always
|
||||
compare three different applications, and end up measuring three different serialisation
|
||||
libraries, three JIT states and three thread pools.
|
||||
|
||||
## What each one is, in one sentence
|
||||
|
||||
| | gRPC | RSocket | Raw WebSocket |
|
||||
|---|---|---|---|
|
||||
| Transport | HTTP/2 | TCP, WebSocket, or others | HTTP/1.1 Upgrade |
|
||||
| Schema | `.proto`, mandatory, code-generated | none required | none |
|
||||
| Encoding here | protobuf | CBOR (Spring's default) | JSON |
|
||||
| Interaction models | 4, declared in the `.proto` | 4, chosen by return type | whatever you invent |
|
||||
| Demand signalling | none in the API | `request(n)` on the wire | none at all |
|
||||
| Deadlines | per call, absolute, propagating | none built in | none |
|
||||
| Browser client | needs grpc-web + a proxy | yes, over the WebSocket transport | yes, natively |
|
||||
| Boot 4 starters | `spring-boot-starter-grpc-server` / `-client` | `spring-boot-starter-rsocket` | `spring-boot-starter-websocket` |
|
||||
|
||||
## The three server sides, side by side
|
||||
|
||||
**gRPC** ([`GrpcQuoteService`](../src/main/java/com/ankurm/protocols/GrpcQuoteService.java)) is
|
||||
generated-class inheritance. There is no registration code: the generated `ImplBase` is a
|
||||
`BindableService` and Boot registers every such bean.
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void getQuote(QuoteRequest request, StreamObserver<Quote> observer) {
|
||||
observer.onNext(toProto(source.at(request.getSymbol(), 0)));
|
||||
observer.onCompleted();
|
||||
}
|
||||
```
|
||||
|
||||
**RSocket** ([`RSocketQuoteController`](../src/main/java/com/ankurm/protocols/RSocketQuoteController.java))
|
||||
is annotation routing, and the interaction model *is the return type*:
|
||||
|
||||
```java
|
||||
@MessageMapping("quote")
|
||||
public Mono<Quote> quote(String symbol) { ... } // request/response
|
||||
|
||||
@MessageMapping("quotes")
|
||||
public Flux<Quote> quotes(StreamSpec spec) { ... } // request/stream
|
||||
```
|
||||
|
||||
**Raw WebSocket** ([`WebSocketQuoteHandler`](../src/main/java/com/ankurm/protocols/WebSocketQuoteHandler.java))
|
||||
is a `switch` on a string, because there is nothing else:
|
||||
|
||||
```java
|
||||
switch (parts[0]) {
|
||||
case "QUOTE" -> send(session, source.at(parts[1], 0));
|
||||
case "STREAM" -> { for (int i = 0; i < count; i++) { send(...); } }
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
That third block is the honest summary of what a raw WebSocket gives you: a bidirectional pipe
|
||||
for text or bytes. Everything above it — routing, correlation, errors, versioning, demand
|
||||
— is yours to invent, and inventing it is how teams end up with a private, undocumented
|
||||
protocol that only its authors can debug. STOMP exists to stop that, and is covered in
|
||||
[`../sse-websocket`](../../sse-websocket/README.md).
|
||||
|
||||
## Boot 4 version notes
|
||||
|
||||
Boot 4.1.1's BOM pins **grpc-java 1.83.1** and **protobuf-java 4.35.1**, both deliberately older
|
||||
than the newest releases on Maven Central. Overriding them independently is how you get a
|
||||
`NoSuchMethodError` between grpc-java and its shaded Netty. Note that these have moved since Boot
|
||||
4.1.0, which pinned 1.80.0 and 4.34.2 — so a `spring.grpc.*` guide written against 4.1.0 is
|
||||
already describing different jars.
|
||||
|
||||
RSocket is **rsocket-java 1.1.5**, and `spring-boot-starter-rsocket` brings
|
||||
`jackson-dataformat-cbor` on purpose: CBOR, not JSON, is Spring's default RSocket data mime type.
|
||||
|
||||
---
|
||||
|
||||
Next: [2. How they measure](02-benchmarks.md)
|
||||
Reference in New Issue
Block a user