Real-Time Backend
JSON vs Binary протоколы
Discord в 2020 году передавал 100+ млн сообщений в день через WebSocket Gateway. JSON парсинг занимал значимую долю CPU на gateway серверах. Переход сначала на Erlang ETF (бинарный), затем на Protobuf дал 40% снижение трафика и заметное снижение CPU. Один инженерный выбор - формат сериализации - изменил cost structure инфраструктуры.
- **gRPC (Google, Cloud)** - Protobuf как стандарт для всех внутренних RPC; автогенерация клиентов для 10+ языков
- **MessagePack в Redis** - встроенная сериализация для RESP3 бинарных расширений
- **Apache Kafka** - Schema Registry + Avro/Protobuf для типобезопасной эволюции сообщений
JSON при масштабе: когда парсинг становится узким местом
Discord переключился с JSON на Protobuf и получил 40% снижение трафика. При 100 тысячах сообщений в секунду парсинг JSON начинает доминировать в CPU профиле. Причины: JSON текстовый (числа как строки), имена полей повторяются в каждом сообщении, нет схемы - тип поля нужно угадывать из значения.
| Характеристика | JSON | MessagePack | Protobuf |
|---|---|---|---|
| Размер | Baseline | ~30% меньше | ~60-80% меньше |
| Скорость парсинга | 1x | 2-5x быстрее | 5-10x быстрее |
| Схема | Нет | Нет | Обязательна (.proto) |
| Human-readable | Да | Нет | Нет |
| Backward compat | Мануально | Мануально | Встроена (field numbers) |
Почему JSON неэффективен при высоком трафике (100k+ сообщений/сек)?
MessagePack: бинарный JSON-совместимый формат
MessagePack - бинарная сериализация с той же моделью данных что и JSON: строки, числа, массивы, объекты, null, bool. Нет схемы - имена ключей хранятся в каждом сообщении (как JSON). Главный выигрыш: числа хранятся в бинарном виде, строки - без escape, структура кодируется типовыми байтами.
**Когда MessagePack:** когда нужна бинарная эффективность JSON без изменения архитектуры. Работает как drop-in замена JSON в WebSocket протоколах. Особенно эффективен для числовых данных и коротких строк. Не даёт преимуществ схемы - нет backward compatibility гарантий.
Главное отличие MessagePack от Protobuf:
Protocol Buffers: schema-first с backward compatibility
Protocol Buffers (Protobuf) - Google's бинарный формат с обязательной схемой в `.proto` файле. Компилятор `protoc` генерирует typed код для 10+ языков. Ключевое: каждое поле имеет **field number** вместо имени - это обеспечивает forward и backward compatibility.
Что обеспечивает backward compatibility в Protobuf при добавлении нового поля?
Критерии выбора формата: JSON, MessagePack или Protobuf
Выбор формата - это trade-off между простотой разработки, производительностью и совместимостью. Нет универсального ответа - контекст определяет всё.
| Сценарий | Рекомендация | Причина |
|---|---|---|
| REST API, внешние партнёры | JSON | Human-readable, инструменты everywhere, нет нужды в скорости |
| WebSocket, 10-100k msg/s | MessagePack | Drop-in замена JSON, ~30% экономия без схемы |
| gRPC, внутренние микросервисы | Protobuf | Типобезопасность, codegen, 60-80% компактнее |
| IoT устройства, ограниченный канал | Protobuf или CBOR | Минимальный размер, схема для экономии байт |
| Debugging, logging | JSON | Читаемость важнее размера |
**Гибридный подход:** внешний API - JSON (партнёры, SDK, браузеры), внутренние сервисы - Protobuf/gRPC. Это позволяет сохранить developer experience на внешней границе и производительность внутри.
Protobuf всегда лучше JSON - нужно везде переходить на Protobuf.
Protobuf требует схему, codegen и DevEx overhead. Для внешних API, debugging и малого трафика JSON предпочтителен. Protobuf выигрывает при высоком трафике и строгих требованиях к типам между сервисами.
Выбор формата - engineering trade-off. Developer experience, tooling и совместимость часто важнее нескольких процентов CPU при малом трафике.
Новый WebSocket сервис обменивается 50k сообщений/сек с браузерными клиентами. JSON тормозит, но нет времени писать .proto схемы. Что выбрать?
JSON vs Binary протоколы
- **JSON при масштабе:** имена полей повторяются, числа как строки, текстовый парсинг - CPU bottleneck от 10k+ msg/s
- **MessagePack:** бинарный JSON без схемы; drop-in замена; ~30% компактнее, 2-5x быстрее парсинг
- **Protobuf:** schema-first (.proto); field numbers = backward compatibility; 60-80% компактнее, 5-10x быстрее; codegen для 10+ языков
- **Выбор:** JSON для внешних API и debugging; MessagePack как быстрая замена JSON; Protobuf для высоконагруженных внутренних сервисов и gRPC
Связанные темы
Выбор формата сериализации - часть общей архитектуры real-time систем.
- WebSocket протокол — MessagePack и Protobuf часто используются поверх WebSocket для бинарных фреймов
- gRPC и streaming — gRPC использует Protobuf как транспортный формат с двунаправленным streaming
Вопросы для размышления
- Почему backward compatibility в Protobuf основана на field numbers, а не именах полей - и что это означает при рефакторинге схемы?
- В каком сценарии MessagePack не даёт значимого преимущества над JSON, несмотря на бинарный формат?
- Как выбор формата сериализации влияет на observability системы - логирование, distributed tracing, debugging в production?
Связанные уроки
- rt-07 — First real-time app is built with JSON; knowing what you're optimizing away from matters
- rt-05 — WebSocket carries binary frames natively; protocol knowledge anchors the serialization choice
- rt-09 — Socket.IO uses both JSON and binary - this lesson explains what's happening under the hood
- rt-11 — uWebSockets.js is the performance runtime where binary protocols pay off most
- net-54-rpc