За счет чего в Protobuf payload меньше чем в JSON
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Сравнение размеров payload Protobuf и JSON
Основное преимущество Protocol Buffers (Protobuf) перед JSON в плане размера передаваемых данных достигается за счет нескольких ключевых особенностей:
1. Бинарное кодирование против текстового формата
Protobuf использует компактное бинарное представление данных, в то время как JSON — это текстовый формат.
JSON пример:
{
"id": 42,
"name": "John Doe",
"email": "john@example.com",
"age": 30,
"active": true
}
В JSON все данные представлены как текст (включая числа), используются кавычки для ключей и строк, дополнительные символы форматирования.
Protobuf пример:
message Person {
int32 id = 1;
string name = 2;
string email = 3;
int32 age = 4;
bool active = 5;
}
// Кодирование в бинарный формат
person := &Person{
Id: 42,
Name: "John Doe",
Email: "john@example.com",
Age: 30,
Active: true,
}
data, _ := proto.Marshal(person) // Компактный бинарный payload
2. Отсутствие метаданных и ключей в payload
- В JSON каждый объект включает имена полей (ключи) в каждом сообщении
- В Protobuf имена полей заменяются числовыми идентификаторами (тегами)
При кодировании Protobuf передает только:
- Тег поля (компактное varint-число)
- Тип данных (часто выводится из контекста)
- Значение
3. Компактное представление чисел
- JSON: Числа кодируются как ASCII-текст ("42" → 2 байта)
- Protobuf: Использует varint кодирование для целых чисел
- Маленькие числа занимают 1 байт
- Числа до 127 → 1 байт
- Числа до 16383 → 2 байта
// Пример varint кодирования в Protobuf
func EncodeVarint(x uint64) []byte {
var buf [10]byte
var n int
for n = 0; x > 127; n++ {
buf[n] = 0x80 | uint8(x&0x7F)
x >>= 7
}
buf[n] = uint8(x)
n++
return buf[:n]
}
4. Пропуск не установленных значений
- В JSON все поля присутствуют (даже если
null) - Protobuf не включает в сообщение поля, которые не были установлены
// Если установить только id и name
person := &Person{Id: 42, Name: "John Doe"}
data, _ := proto.Marshal(person)
// В data будут только теги 1 и 2 с их значениями
5. Эффективное кодирование строк и массивов
- Длина строки кодируется varint перед содержимым
- Повторяющиеся поля упаковываются компактнее
- Фиксированные 32/64-битные числа для float/double всегда занимают 4/8 байт
6. Схема и типизация
Наличие заранее определенной схемы позволяет:
- Избежать передачи информации о типах данных
- Оптимизировать парсинг (не нужна проверка типов в runtime)
- Применять предварительную аллокацию памяти
// Парсинг Protobuf vs JSON
func BenchmarkParsing(b *testing.B) {
jsonData := []byte(`{"id":42,"name":"John"}`)
protoData, _ := proto.Marshal(&Person{Id: 42, Name: "John"})
b.Run("JSON", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var person Person
json.Unmarshal(jsonData, &person)
}
})
b.Run("Protobuf", func(b *testing.B) {
for i := 0; i < b.N; i++ {
person := &Person{}
proto.Unmarshal(protoData, person)
}
})
}
Количественное сравнение
Для типичного сообщения среднего размера:
- Protobuf обычно на 30-50% меньше чем JSON
- При передаче чисел и бинарных данных разница может достигать 70-80%
- В microservices коммуникации это дает существенную экономию трафика и повышает производительность
Практический пример
package main
import (
"encoding/json"
"fmt"
"github.com/golang/protobuf/proto"
)
func main() {
// JSON
jsonData := []byte(`{"id":12345,"name":"Alice","email":"alice@example.com","age":28,"active":true}`)
fmt.Printf("JSON size: %d bytes\n", len(jsonData))
// Protobuf
person := &Person{
Id: 12345,
Name: "Alice",
Email: "alice@example.com",
Age: 28,
Active: true,
}
protoData, _ := proto.Marshal(person)
fmt.Printf("Protobuf size: %d bytes\n", len(protoData))
fmt.Printf("Reduction: %.1f%%\n",
(1-float64(len(protoData))/float64(len(jsonData)))*100)
}
Вывод может показать: JSON 120 байт vs Protobuf 65 байт (уменьшение на ~46%).
Вывод
Protobuf обеспечивает меньший размер payload благодаря бинарному кодированию, замене строковых ключей числовыми тегами, компактному varint представлению чисел и исключению не установленных полей. Это делает его предпочтительным выбором для высоконагруженных систем, микросервисной архитектуры и мобильных приложений, где важна эффективность передачи данных. Однако стоит учиты trade-off: JSON остается более удобным для отладки и совместимости с веб-технологиями.