Add the protocol-comparison module
This commit is contained in:
56
protocol-comparison/docs/03-payload.md
Normal file
56
protocol-comparison/docs/03-payload.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 3. Payload: the one comparison that needs no benchmark
|
||||
|
||||
Previous: [2. Benchmarks](02-benchmarks.md) · Next: [4. Back-pressure](04-backpressure.md)
|
||||
|
||||
---
|
||||
|
||||
Five fields — a symbol, a sequence number, two doubles and a timestamp — encoded three
|
||||
ways ([`payload-sizes.txt`](output/payload-sizes.txt)):
|
||||
|
||||
```
|
||||
protobuf : 35 bytes 0a044141504c102a197b14ae47e11a5940215c8fc2f5281c5940288080abb4fef39203
|
||||
JSON : 83 bytes {"symbol":"AAPL","seq":42,"bid":100.42,"ask":100.44,"epochMicros":1772000000000000}
|
||||
CBOR : 67 bytes bf6673796d626f6c644141504c63736571182a63626964fb40591ae147ae147b6361736bfb40591c28f5c28f5c6b65706f63684d6963726f731b00064b9fe68ac000ff
|
||||
JSON is 2.37x protobuf; CBOR is 1.91x protobuf
|
||||
```
|
||||
|
||||
This is a property of the formats, not of a machine, so it is the one row of the comparison that
|
||||
transfers to your hardware unchanged.
|
||||
|
||||
**Protobuf is 35 bytes because field names are integers.** `0a04 41 41 50 4c` is field 1, length
|
||||
4, `AAPL`. There is no `"symbol"` on the wire at all — the name lives in the `.proto` file
|
||||
that both sides compiled against. That is where the size comes from, and it is also the whole
|
||||
argument about schemas: the saving and the coupling are the same fact.
|
||||
|
||||
**CBOR is 67 bytes and still writes the field names.** `6673796d626f6c` is a 6-character text
|
||||
string, `symbol`. CBOR is binary JSON, not a schema format: it saves the punctuation and encodes
|
||||
numbers compactly, and it keeps every key. So its advantage over JSON is real but modest, and it
|
||||
does not require the coupling.
|
||||
|
||||
Concretely, on a stream of a million quotes: 35 MB, 67 MB, 83 MB. On a loopback
|
||||
that difference disappears into memory bandwidth — which is exactly why the benchmarks in
|
||||
[chapter 2](02-benchmarks.md) do not reward it and a real link would.
|
||||
|
||||
Two practical notes:
|
||||
|
||||
- **Spring's RSocket default is CBOR**, not JSON, which is why
|
||||
`spring-boot-starter-rsocket` brings `jackson-dataformat-cbor`. If you are debugging with
|
||||
`tcpdump` and expecting to read your payloads, that is why you cannot. The mechanism is codec
|
||||
ordering, printed by
|
||||
[`RSocketDefaultsTest`](../src/test/java/com/ankurm/protocols/RSocketDefaultsTest.java):
|
||||
|
||||
```
|
||||
encoders : [CharSequenceEncoder, ByteBufferEncoder, ByteArrayEncoder, DataBufferEncoder, JacksonCborEncoder, JacksonJsonEncoder]
|
||||
bare RSocketStrategies.create() : [CharSequenceEncoder, ByteBufferEncoder, ByteArrayEncoder, DataBufferEncoder]
|
||||
```
|
||||
|
||||
CBOR sits *ahead of* JSON in the Boot-configured list, which is the whole of why it wins. Note
|
||||
also that a bare `RSocketStrategies.create()` carries neither — an `RSocketRequester` built
|
||||
without injecting Boot's strategies cannot encode your objects at all. And the class names
|
||||
follow the Boot 4 rule: `JacksonCborEncoder`, not `Jackson2…`.
|
||||
- **You can put protobuf on RSocket.** The encoding and the protocol are independent choices;
|
||||
the row above is what each stack does *by default*, not what it is capable of.
|
||||
|
||||
---
|
||||
|
||||
Previous: [2. Benchmarks](02-benchmarks.md) · Next: [4. Back-pressure](04-backpressure.md)
|
||||
Reference in New Issue
Block a user