Оптимизация хранимых данных на 93% (Redis)

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Хотелось бы поделиться опытом оптимизации данных с целью уменьшения расходов на ресурсы.

В системе рано или поздно встает вопрос об оптимизации хранимых данных, особенно если данные хранятся в оперативной памяти, как это БД Redis.

Как временное решение, можно увеличить RAM тем самым можно выиграть время.

Redis это no-sql база данных, профилировать ее можно с помощью встроенной команды redis-cli --bigkeys, которая покажет кол-во ключей и сколько в среднем занимает каждый ключ.

Объемными данными оказались исторические данные типо sorted sets. У них была ротация 10 дней из приложения.

Проект в продакшене, поэтому оптимизация никак не должна была сказаться на пользователях.

Данные из себя представляли события измененияцены / даты доставки у оффера. Офферов было очень много – порядка 15000 в каждом фиде (прайслисте).

Рассмотрим следующий пример данных события по офферу:

Сделано с помощью http://json.parser.online.fr/
Сделано с помощью http://json.parser.online.fr/

{"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 байт.

Оптимизация

  1. Для начала я уменьшил ротацию до 7 дней, так как использовалась именно последняя неделя. Здесь стоит отметить, что шаг весьма легкий(в исходном коде изменил 10 на 7), сразу сокращает размер RAM на 30%.

  2. Удалил из хранилища все данные, которые записывались, но не использовались во время чтения, такие как 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 байта.

    1. Переделал формат хранение с json в бинарный protobuf.

      Об этом шаге хотелось бы рассказать подробнее

      1. Составил схему хранение данных, в случее с 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;
        } 
      2. Исходное сообщение в текстовом 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
          }
        }
        
      3. Сообщение в итоговом бинарном 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%.

Источник: https://habr.com/ru/post/546734/


Интересные статьи

Интересные статьи

Настроить хранение данных приложений, запущенных в кластере Kubernetes, можно несколькими способами. Одни из них уже устарели, другие появились совсем недавно. В этой статье рассмотри...
В обновлении «Сидней» Битрикс выпустил новый продукт в составе Битрикс24: магазины. Теперь в любом портале можно создать не только лендинг или многостраничный сайт, но даже интернет-магазин. С корзино...
Михаил Коновалов, руководитель направления отдела сопровождения интеграционных проектов ИТ-дирекции МКБ День добрый, хабровчане! Цель Систематизированный подход к управлению загрузками. Мы...
Введение Язык программирования Rust, невзирая на всеохватывающую идеологию безопасности данных, располагает и небезопасными методиками программирования, ведь порой они могут повышать скорость ...
Эта статья посвящена одному из способов сделать в 1с-Битрикс форму в всплывающем окне. Достоинства метода: - можно использовать любые формы 1с-Битрикс, которые выводятся компонентом. Например, добавле...