Глава 4. Кодирование и эволюция
Tags: клеппман, высоконагруженныесистемы, книги
Published: 2023-11-13 21:36:24

## Введение

С течением времени приложение меняется. Однако данные, с которыми работает новая версия приложение, могли быть созданы еще при старой версии приложения.
Тем не менее приложение должно уметь работать как со старым форматом данных, так и с новым. Это называется *обратной совместимостью*.

Также бывает нужно, чтобы старая версия приложения умела работать с данными, созданными более новой версией приложения.
Например, при плавающем обновлении, когда на некоторых нодах развернута уже новая версия приложения, а где-то старая. Это называется *прямой соместимостью*.


## Форматы кодирования данных

Для разных целей одни и те же данные могут представляться по-разному. Для хранения использоваться один формат, а для пересылки по сети - другой.
Преобразование из формата для хранения в формат для пересылки называется кодированием, маршаллингом или сериализацией. Обратное преобразование, когда получатель получил данные - декодированием, демаршаллингом или десериализацией.

### Форматы, ориентированные на ЯП

В большинстве языков программирования есть "нативная" сериализация, достигаемая минимумом кода (например, java.io.Serializable в Java). Однако такие реализации имеют много минусов:

- Она заточена под один язык программирования. А значит, программы, написанные на разных ЯП, не смогут "общаться".

- Как правило, низкая эффективность по скорости и размеру потребляемой памяти.

- Проблемы с безопасностью - если подложить для декодирования вредоносные данные, то после декодирования будет в памяти объект, способный выполнять вредные вещи.

- Плохо продуманы вопросы, касающиеся совместимости.


### Текстовые форматы данных

#### XML

Многословный текстовый формат, часто применяющийся к корпоративных приложениях, особенно, если они были написаны в 90-е и 2000-е. В XML нет типов данных как таковых. Все можно считать строкой.
Но можно подключить схему валидации (своего рода костыль). Для XML использование схем валидации частое явление.

#### JSON

Текстовый формат, часто применяющийся в современных приложениях. Менее многословный, чем XML. Также поддерживает схемы валидации, однако для JSON они на практике очень редко используются.
Зато есть поддержка типов данных (boolean, string, int64). Однако есть проблема с большими числами - числа более 2^53 кодируются с неточностями из-за представления числа с плавающей точкой по стандарту IEEE-754.

Также есть двочные кодирования для JSON - BSON, MessagePack и др. Но они редко использутся и дают не настолько сильный выигрыш в снижении объема данных, чтобы терять в удобочитаемости. Я встречал в БД его использование.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4butcc77hc72z72sght.png)




Стоит отметить, что оба формат не поддерживают работу с бинарными строками. Поэтому использутся костыль в виде base64 кодирования, который примерно на 30% увеличивает объем данных.

### Двоичные форматы данных


Apache Thrift и Protocol Buffers - популярные библиотеки для кодирования данных. Оба требуют предварительно иметь на отправителе и получателе схему.
Отчасти благодаря тому, что часть необходимой для кодирования/декодирования данных информации зашита в схему, достигается сильное снижение объема данных.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6h7duy91iclsbsb9raoc.png)
Apache Thrift



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7dw0ips7zub5ii8au48x.png)
Protobuf









Так как protobuf популярнее, рассмотрим его устройство подробнее.

Вместо названия полей в protobuf в закодированных данных хранятся тип значения (число), теги полей - числа (что-то вроде псевдонимов для полей), длина (для строки) и сами данные.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sm81lcjd72dyb0r5p5i2.png)




В итоге данные, которые в JSON весили 84 байта, в protobuf весят 33. 



Однако что с совместимостью у бинарных форматов?

Как видно, закодированная запись это просто конкатенация закодированных полей.

Если поле добавляется, то чтобы новый код мог работать со старыми данными, новое поле должно быть необязательным или иметь дефолтное значение - тогда новая версия приложения может читать старые данные.
Если поле удаляется, то чтобы старый код мог работать с новым форматом поле удаляемое поле должно быть необязательным изначально и тег для него нельзя будет использовать для новых полей.




## Способы обмена данными

Теперь рассмотрим способы отправки данных в форматах, описанных ранее.

Существует 3 способа обмена данными между процессами на одной ноде или разных:

- через общую БД

- через REST или RPC

- асинхронный обмен через очередь сообщений


### Общая БД

Самый примитивный способ интеграции приложений, дающей сильное связывание между компонентами. Однако есть и плюс - актуальная схема данных хорошо видна.
Для достижения прямой совместимости нельзя допускать, чтобы старая версия приложения целиком перезаписывала всю строку.

### REST и RPC


RPC - удаленный вызов процедур. В коде приложения это выглядит как вызов локальной функции. Популярный паттерн коммуникации в SOA (сервис ориентированной) архитектуре.
Чаще всего RPC реализуется через SOAP протокол. В его основе лежит протокол HTTP. Однако SOAP не использует никакие  его возможности, такие как использование кодов ответов, заголовков.
API сервиса, поддерживающего общение по SOAP, описывается на XML через WSDL схему. На основе этой схеме генерируются нужные методы на языках программирования. 

REST - подход к проектированю систем, общающихся по http и по-максимому использующих его возможности. В качестве формата данных могут использоваться разные форматы, однако чаще всего это JSON.



### Очереди сообщения

RPC - синхронный способ обмена сообщениями.

БД - асинхронный, но изначально предполагающий использование в качестве хранилища данных.

Очередь - тоже асинхронный способ, но изначально предполагающий использование для обемена сообщениями. Поэтому имеет такие сущности как топик, смещение, издатель и подписчик. Благодаря этим абстракциям обмен данными многими с многими упрощается.

Преимущества ипользования очередей по сравнению с RPC:

- очередь является буфером, смягчающим скачки нагрузки на приложение

- уменьшает связанность компонетов системы (отправителю не нужно знать адрес получателя)

- автоматически повтор отправки в случае сбоя

Примеры часто использующихся брокеров сообщения: RabbitMQ, Apache Kafka, NATS.