Хотелось бы поделиться опытом оптимизации данных с целью уменьшения расходов на ресурсы.
В системе рано или поздно встает вопрос об оптимизации хранимых данных, особенно если данные хранятся в оперативной памяти. Примером такой БД является Redis.
Как временное решение, можно увеличить RAM тем самым можно выиграть время.
Redis это no-sql база данных, профилировать ее можно с помощью встроенной команды redis-cli --bigkeys, которая покажет кол-во ключей и сколько в среднем занимает каждый ключ.
Объемными данными оказались исторические данные типо sorted sets. У них была ротация 10 дней из приложения.
Проект в продакшене, поэтому оптимизация никак не должна была сказаться на пользователях.
Данные из себя представляли события изменения цены / даты доставки у оффера. Офферов было очень много – порядка 15000 в каждом фиде (прайслисте).
Рассмотрим следующий пример данных события по офферу:

{"EventName":"DELIVERY_CHANGED","DateTime":"2021-02-22T00:04:00.112593982+03:00","OfferId":"109703","OfferFrom":{"Id":"109703","Name":"Саундбар LG SN11R","Url":"https://www.example.ru/saundbar-lg-sn11r/?utm_source=yandex_market&utm_medium=cpc&utm_content=948&utm_campaign=3&utm_term=109703","Price":99990,"DeliveryAvailable":true,"DeliveryCost":0,"DeliveryDate":"2021-02-24T23:49:00+03:00"},"OfferTo":{"Id":"109703","Name":"Саундбар LG SN11R","Url":"https://www.example.ru/saundbar-lg-sn11r/?utm_source=yandex_market&utm_medium=cpc&utm_content=948&utm_campaign=3&utm_term=109703","Price":99990,"DeliveryAvailable":true,"DeliveryCost":0,"DeliveryDate":"2021-02-23T00:04:00.112593982+03:00"}}
Такое событие занимает 706 байт.
Оптимизация
Для начала я уменьшил ротацию до 7 дней, так как использовалась именно последняя неделя. Здесь стоит отметить, что шаг весьма легкий (в исходном коде изменил 10 на 7), сразу сокращает размер RAM на 30%.
Удалил из хранилища все данные, которые записывались, но не использовались во время чтения, такие как name, url, offerId что сократило еще примерно на 50%.
Cтало:
{"EventName":"DELIVERY_CHANGED","DateTime":"2021-02-22T00:04:00.112593982+03:00","OfferId":"109703","OfferFrom":{"Price":99990,"DeliveryAvailable":true,"DeliveryCost":0,"DeliveryDate":"2021-02-24T23:49:00+03:00"},"OfferTo":{"Price":99990,"DeliveryAvailable":true,"DeliveryCost":0,"DeliveryDate":"2021-02-23T00:04:00.112593982+03:00"}}
Теперь событие занимает 334 байта.
Переделал формат хранение с json в бинарный protobuf.
Об этом шаге хотелось бы рассказать подробнее
Составил схему хранения данных, в случее с protobuf это proto - файл:
syntax = "proto3"; import "google/protobuf/timestamp.proto"; message OfferEvent { enum EventType { PRICE_CHANGED = 0; DELIVERY_CHANGED = 1; DELIVERY_SWITCHED = 2; APPEARED = 3; DISAPPEARED = 4; } EventType event_name = 1; google.protobuf.Timestamp date_time = 2; string offer_id = 3; message Offer { int32 price = 1; bool delivery_available = 2; int32 delivery_cost = 3; google.protobuf.Timestamp delivery_date = 4; } Offer offer_from = 4; Offer offer_to = 5; }
Исходное сообщение в текстовом protobuf формате будет выглядеть так
event_name: DELIVERY_CHANGED date_time { seconds: 1613941440 } offer_id: "109703" offer_from { price: 99990 delivery_available: true delivery_date { seconds: 1614199740 } } offer_to { price: 99990 delivery_available: true delivery_date { seconds: 1614027840 } }
Сообщение в итоговом бинарном protobuf формате будет выглядеть так
echo ' event_name: DELIVERY_CHANGED date_time { seconds: 1613941440 } offer_id: "109703" offer_from { price: 99990 delivery_available: true delivery_date { seconds: 1614199740 } } offer_to { price: 99990 delivery_available: true delivery_date { seconds: 1614027840 } } ' | protoc --encode=OfferEvent offerevent.proto | xxd -p | tr -d "\n" 0801120608c095cb81061a06313039373033220e08968d061001220608bcf7da81062a0e08968d061001220608c0b8d08106
Теперь событие занимает 50 байт. Это сократило потребление памяти на 85%.
Бинарное сообщение без proto-схемы можно посмотреть с помощью онлайн-сервиса https://protogen.marcgravell.com/
Итого
Оптимизация места более, чем в 14 раз (50 байт против 706 байт изначальных), то есть на 93%.
dlazerka
Подскажу как ещё можно значительно сократить размер — использовать Clickhouse, который как раз для хранения иаких эвентов и создан.
ilya_dt Автор
Я делал оптимизацию в текущем стеке с минимальным воздействием на кодовую базу, а так же в приоритете была скорость реализации.
Далее оптимизировать уже не было смысла, так как есть другие узкие места.