3.0 KiB
3. Payload: the one comparison that needs no benchmark
Previous: 2. Benchmarks · Next: 4. Back-pressure
Five fields — a symbol, a sequence number, two doubles and a timestamp — encoded three
ways (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 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-rsocketbringsjackson-dataformat-cbor. If you are debugging withtcpdumpand expecting to read your payloads, that is why you cannot. The mechanism is codec ordering, printed byRSocketDefaultsTest: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 — anRSocketRequesterbuilt without injecting Boot's strategies cannot encode your objects at all. And the class names follow the Boot 4 rule:JacksonCborEncoder, notJackson2…. -
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 · Next: 4. Back-pressure