Learning Platform
Глоссарий Troubleshooting
Урок 06.04 · 25 мин
Средний
MessagePackBinary JSONFormat FamiliesExtension TypesTimestampSchemaless Serialization

MessagePack Format

Что такое MessagePack

MessagePack — бинарный формат сериализации, позиционируемый как «JSON, но быстрее и компактнее». Schemaless — не требует предварительного определения схемы (в отличие от Protobuf и Thrift). Формат самоописывающий: первый байт каждого значения определяет его тип.

Поддержка языков — одна из самых широких: официальные библиотеки для 50+ языков (Python msgpack 1.1.2, Go, Rust, Java, C++, JavaScript, Ruby, PHP, C#, Swift, и др.).

MessagePack vs JSON
JSON (text)Текстовый формат: ключи и значения в ASCII/UTF-8. Overhead: кавычки, двоеточия, запятые, скобки. Human-readable. Нет binary type.
MessagePack (binary)Бинарный формат: тип определяется первым байтом. Нет кавычек, двоеточий, запятых. Компактнее JSON, но не human-readable. Есть binary type.
NOTE

MessagePack — не замена Protobuf или Thrift. Это замена JSON для сценариев, где schema management не нужен, но JSON слишком медленный или объёмный: Redis serialization, WebSocket payloads, game state, IPC между процессами, кэширование.

Определение типа по первому байту

Ключевая идея MessagePack: первый байт каждого значения определяет его тип и (иногда) содержит само значение:

First Byte → Type Determination
ДиапазонДиапазон значений первого байта (hex).
ТипMessagePack тип.
ФорматСколько дополнительных байт после первого.
ОписаниеЧто содержит.
0x00–0x7F0x00-0x7F: positive fixint. Значение хранится прямо в первом байте (7 бит). Нет дополнительных байт.
Positive fixint: целые 0–127 в одном байте.
Ноль дополнительных байт — значение В первом байте.
Один байт = одно число 0-127. Самый частый случай для маленьких чисел.
0x80–0x8F0x80-0x8F: fixmap. Младшие 4 бита = количество пар (0–15). Далее N пар (key, value).
fixmap: map с 0–15 парами.
N * (key + value) — переменное количество.
Маленький map: 1 байт header. 0x82 = map с 2 парами.
0x90–0x9F0x90-0x9F: fixarray. Младшие 4 бита = количество элементов (0–15).
fixarray: array с 0–15 элементами.
N элементов.
Маленький массив: 1 байт header. 0x93 = array с 3 элементами.
0xA0–0xBF0xA0-0xBF: fixstr. Младшие 5 бит = длина строки (0–31 байт). Далее UTF-8 данные.
fixstr: строка 0–31 байт.
N байт UTF-8 данных.
Короткая строка: 1 байт header. 0xA2 = строка из 2 байт.
0xC00xC0: nil (null). Один байт — аналог JSON null.
nil: null value.
Ноль.
Null value. Один байт.
0xE0–0xFF0xE0-0xFF: negative fixint. Значение = signed int8 первого байта (-32 до -1). Один байт.
Negative fixint: целые -32 до -1 в одном байте.
Ноль дополнительных байт.
-1 = 0xFF, -32 = 0xE0.

Format Families

MessagePack организует типы в families — каждая family покрывает диапазон размеров одного логического типа:

Integer Format Family

Integer: выбор формата по значению

Integers: от -2^63 до 2^64-1. MessagePack автоматически выбирает самый компактный формат.
positive fixint (1B)0–127: значение прямо в первом байте. 0 дополнительных байт. Самый частый случай — ID, counters, small enums.
uint 8 (2B)0xCC + 1 байт значения. 128–255.
uint 16 (3B)0xCD + 2 байта big-endian. 256–65535.
uint 32 (5B)0xCE + 4 байта big-endian. До ~4 миллиардов.
uint 64 (9B)0xCF + 8 байт big-endian. Максимальный unsigned.
negative fixint (1B)-32 до -1: значение прямо в первом байте (signed). 0xE0=-32, 0xFF=-1.
int 8 (2B)0xD0 + 1 signed byte. -128 до -33.
int 16/32/640xD1 (3B), 0xD2 (5B), 0xD3 (9B). Signed big-endian.
String Format Family
fixstr (1B + data)0xA0-0xBF: младшие 5 бит = длина (0–31). Один байт header. 'Al' = 0xA2 41 6C (3 байта total).
str 8 (2B + data)0xD9 + 1 байт длины. Строки 32–255 байт.
str 16 (3B + data)0xDA + 2 байта длины (big-endian). До 65535 байт.
str 32 (5B + data)0xDB + 4 байта длины (big-endian). До ~4GB.

Полный пример кодирования

MessagePack: кодирование id=150, name=Al
{"id": 150, "name": "Al"}JSON-like объект. В MessagePack — это map с 2 парами (string key, value).
Map headerfixmap с 2 парами: 0x80 | 2 = 0x82. Один байт.
Пара 1: 'id' → 150Key 'id': fixstr(2) = 0xA2 + 69 64. Value 150: uint8 = 0xCC 96 (150 > 127, не помещается в fixint).
Пара 2: 'name' → 'Al'Key 'name': fixstr(4) = 0xA4 + 6E 61 6D 65. Value 'Al': fixstr(2) = 0xA2 + 41 6C.

Wire: 82 A2 69 64 CC 96 A4 6E 61 6D 65 A2 41 6C (14 байт)

Итого: 1 + 3 + 2 + 5 + 3 = 14 байт. JSON = 23 байта. MessagePack на 39% компактнее. Но Protobuf = 7 байт — вдвое компактнее (нет ключей на wire).
TIP

Protobuf кодирует User(id=150, name="Al") в 7 байт. MessagePack — в 14 байт. Разница — ключи: MessagePack хранит имена полей (“id”, “name”) на wire, Protobuf — только field numbers. Schema-based форматы всегда компактнее schemaless при одинаковых данных.

Bool, Float, Binary

Остальные примитивные типы
Booleanfalse = 0xC2 (1 байт). true = 0xC3 (1 байт). Выделенные байты, не часть fixint диапазона.
Floatfloat 32: 0xCA + 4 байта IEEE 754. float 64: 0xCB + 8 байт IEEE 754. Нет автовыбора — encoder решает.
Binary (bin)bin 8: 0xC4 + 1B length + data. bin 16: 0xC5 + 2B. bin 32: 0xC6 + 4B. В отличие от JSON, MessagePack поддерживает raw binary без base64 encoding.
nil0xC0 — один байт. Аналог JSON null. В отличие от Protobuf, где null = отсутствие поля, MessagePack явно кодирует nil.

Extension Types

MessagePack поддерживает пользовательские типы через extension types — type code (int8) + raw data:

Extension Type Format

Extension: type code (int8) + data bytes

Extension = type byte (application-defined) + data. Позволяет добавлять кастомные типы без изменения формата. Type codes 0-127 для application, -1 to -128 для spec-defined.
fixext 1 (3B total)0xD4 + type(1B) + data(1B). Для расширений с 1 байтом данных.
fixext 2 (4B total)0xD5 + type(1B) + data(2B).
fixext 4 (6B total)0xD6 + type(1B) + data(4B). Для timestamp 32-bit.
fixext 8 (10B total)0xD7 + type(1B) + data(8B). Для timestamp 64-bit.
fixext 16 (18B total)0xD8 + type(1B) + data(16B). Для UUID или timestamp 96-bit.
ext 8/16/320xC7/C8/C9 + length + type + data. Произвольный размер.

Timestamp Extension Type

Единственный spec-defined extension type — Timestamp (type code -1):

Timestamp Extension (type -1)
ФорматТри формата для разной точности и диапазона.
РазмерБайты на wire.
ДиапазонДиапазон дат.
Timestamp 32Timestamp 32: только секунды, 4 байта. До 2106 года. Подходит для большинства timestamp.
fixext 4: 0xD6 FF + 4 bytes = 6 байт total.
1970-01-01 до 2106-02-07. Только секунды, без наносекунд.
Timestamp 64Timestamp 64: секунды + наносекунды, 8 байт. Nanosec в старших 30 битах, seconds в младших 34 битах.
fixext 8: 0xD7 FF + 8 bytes = 10 байт total.
1970-01-01 до 2514. Наносекундная точность.
Timestamp 96Timestamp 96: 4 байта наносекунд + 8 байт signed seconds. Для дат до 1970 и после 2514.
ext 8: 0xC7 0C FF + 12 bytes = 15 байт total.
Полный диапазон int64 секунд + наносекунды.
WARNING

Timestamp 64 упаковывает наносекунды и секунды в одно 64-битное значение: (nanosec << 34) | seconds. Старшие 30 бит — наносекунды (0–999999999), младшие 34 бита — секунды. Это хитрая оптимизация: если наносекунды = 0, всё значение = seconds (timestamp 32 поведение в timestamp 64 формате).

MessagePack vs JSON: когда выбирать

MessagePack vs JSON Decision

Нужна human readability?

Основной вопрос: нужна ли human readability? Если да — JSON. Если нет — MessagePack может быть лучше.
Да → JSONAPI responses (debug), config files, logs, data interchange с external systems. Human readability важнее компактности.
Нет → MessagePackInternal IPC, кэширование, WebSocket binary, game state, Redis values. Компактность и скорость важнее читаемости.
MessagePack: сильные и слабые стороны
Сильные стороныПреимущества MessagePack перед JSON и другими форматами.
Слабые стороныОграничения MessagePack.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. MessagePack определяет тип значения по первому байту. Байт 0x93 — что это и сколько дополнительных байт нужно прочитать?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5