[О блоге] [наверх] [пред] [2023-06-15 11:34:29+03:00] [2d7649ccf65833e80de24d980ac1ff4536daf2bc]

Parquet, ORC, Avro, Arrow, Protobuf, Thrift и MessagePack...

https://habr.com/ru/companies/vk/articles/741702/
Честно говоря, я вот только названия слышал Parquet, ORC, Avro, Arrow,
даже не вспомнив о чём это примерно. Не сталкивался с подобными задачами.
Точнее только в составе уже готовых решений типа Hadoop. А вот с
форматами серилиазции при общении между микросервисами уже имел дело.

В ivi (сейчас не знаю как, ибо возможно уже всё переписано) тоже было
много микросервисов: когда пользовательское приложение делает REST
запрос, то за ним ещё с полдюжины запросов к разным БД и другим серверам
может породиться. В основном всё общение между ними было по REST-like
протоколу, где кидались всякие JSON-ы. Время затрачиваемое на
(де)сериализацию JSON-а -- очень ощутимо в Python было (тогда никаких
Py3 не использовалось). Даже если доли миллисекунды, то если
просуммировать все многочисленные round-trip-ы между разными
микросервисами, выдут десятки миллисекунд запросто.

Я написал middleware для Flask, который прозрачно при запросах/ответах
может смотреть на Content-Encoding заголовок и видеть в нём поддержку
lz4 сжатия. lz4 для Python использовал Си-библиотеку и поэтому был очень
быстрым. Это позволяло ощутимо экономить на трафике, на количестве
пакетов передаваемых по сети, уменьшая задержки (размен CPU на кол-во
пакетов в сети). Смотря на Content-Type и видя в нём поддержку BSON, для
сериализации мог применяться BSON: он значительно быстрее JSON, хотя
размер мог быть и больше. Но после lz4 сжатия размер уже роли не играл.
Связка из прозрачных BSON+lz4 позволяла в разы, насколько помню,
сократить задержки.

Самое главное было конечно же минимизировать задержки связанные с сетью.
Вместо того, чтобы просто из Flask программы подключаться
requests/urllib/whatever к другому серверу, поднимался локальный nginx
(не мой выбор, я то не люблю nginx) и подключения шли к нему. На
противоположной стороне тоже был nginx. Между собой они поддерживали
keep-alive HTTP соединение, существенно экономя на TCP roundtrip-ах.

BSON был выбран потому что достаточно было поменять "json.encode" (или
как там?) на "bson.encode". А сам BSON, как зависимость, уже
присутствовала из-за MongoDB. Но позже поменяли это на MessagePack,
который Си-binding-и имел к Python. Он был ощутимо компактнее и,
действительно, очень быстрым. Насколько помню, сериализация BSON была
сравнима по скорости с Python, а десериализация быстрее. MsgPack же в
обе стороны был шустрее. Не все типы данных в него можно было засунуть
как в JSON, но то ли нам повезло, то ли нужны были тривиальные правки к
Python словарикам сериализуемым.

А вот на серверах связанных с кэшированием контента, использовался
Protocol Buffers. Между собой они широковещательно рассылали огромные
потоки UDP пакетов со знаниями о том, у кого какой контент присутствует.
Эта лавина UDP пакетов далеко не всегда полностью успевала
обрабатываться и часть пакетов терялась по сути. Так как этот процесс
происходил регулярно, то рано или поздно знания о соседях
актуализировались. Так вот, чтобы уменьшить вероятность потерь пакетов,
можно просто попытаться уменьшить их количество. В protobuf можно
написать схему структуры данных которые мы хотим передавать, а дальше
генератор напишет эффективный код по (де)сериализации онных.
Действительно, получалось очень компактно (даже целые числа там имели
варьируемой длины формат) и очень быстро даже в Python коде. Это первый
и единственный раз когда я встречался с protobuf, но впечатления
остались самые положительные, хотя это десять лет назад было. Причём
protobuf сообщения нужно было в последствии слать между Python и Go
программами -- никаких проблем тут не возникло.

    [оставить комментарий]