Меня зовут Ескендиров Мурат, я — архитектор сайта в Ви.Tech, IT-дочке ВсеИнструменты.ру. В этой статье расскажу, как мы строили сервис для выдачи карточек товаров, обратывающий до 5 миллиардов запросов в сутки, какие архитектурные решения приняли и с какими проблемами столкнулись в процессе. Расскажу, какие решения сработали, а какие до сих пор остаются нашей головной болью.

Наш e-commerce-сайт за ~20 лет вырос из небольшого PHP-проекта в крупный монолит с несколькими миллионами уникальных товаров.

Несколько лет назад перед сайтом во весь рост встали проблемы, характерные для продуктов, выросших из «гаражного» стартапа в крупный корпоративный продукт:

  • Никто не знает, как это на самом деле работает.

  • Любые изменения — это долго и дорого.

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

В какой-то момент мы, намучившись, решили вынести в отдельные сервисы наиболее нагруженные части монолита.

Одним из таких сервисов стал сервис информации о товаре. Его задача — агрегировать информацию непосредственно о товаре (название, описание, технические характеристики, габариты, картинки и т. п.), наложить на эту информацию определенную бизнес-логику и отдать её фронту.

Одним из самых жестких требований к сервису было отдавать всю эту информацию в 99% случаев не более чем за 30 мс. При этом необходимо было иметь возможность хранить не менее 10 млн уникальных товаров и выдерживать в пике не менее 300 тысяч запросов в минуту.

Ситуация усугублялась тем, что некоторые мастер-системы, которые поставляют информацию для формирования карточки товара, сами являются достаточно медленными монолитами на PHP. Причем одна из них ни при каких обстоятельствах не смогла бы выдержать синхронное с ней взаимодействие. Ждать их рефакторинга мы не могли, производительность сайта ухудшалась с непрерывным ростом нагрузки. «Заливание железом» уже мало помогало, а нагрузочные тестирования показывали, что при текущем росте трафика на горизонте полугода-год мы сложимся в самый неподходящий момент.

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

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


Как мы выбрали хранилище данных

Требования к времени ответа определили то, как мы будем хранить данные.

Ниже на картинке (картинку надо немного другую, добавить вместо ВЗУ Memcached, Redis, БД и т. д.) приведены примерные времена ответа различных уровней памяти. Откинув чересчур мелкие, мы видим, что наибольшей скоростью обладает оперативная память. На ней и было решено остановиться.

Проблема объема данных и выбор механизма вытеснения

После примерного подсчета объема данных стало понятно, что хранить все в горячем хранилище нерационально. Тут мы пришли к тому, что необходимо реализовать механизм, вытесняющий «лишние» объекты и тем самым ограничивающий максимальный объем данных в горячем хранилище.

Варианты вытеснения:

  • FIFO

  • LIFO

  • LRU

  • LFU

Более глубокое изучение вопроса привело к тому, что существуют более экзотические варианты, которые при небольшом усложнении дают приятные бонусы. Например, 2Q и ARC, которые защищают кеш от вытеснения данных при последовательном переборе всех элементов. Второй вариант более продвинутый, но по не вполне понятным сейчас причинам мы решили остановиться на 2Q.

В чем же преимущество 2Q перед широко распространенными LRU и LFU?
2Q по сути состоит из двух с половиной независимых кешей:

  • Входящая очередь по схеме FIFO.

  • Кеш часто используемых элементов по схеме LRU.

  • Исходящая очередь FIFO, которая содержит только идентификаторы элементов (та самая «половинка»), но не содержит их данных.

Принцип работы:
Чтобы элемент задержался в кеше надолго, он должен «доказать», что действительно часто используется и имеет право занимать память, а не попал туда случайно, вытеснив более полезного соседа.


Проблема многопоточности и оптимизация доступа

У всех этих видов кешей есть один существенный недостаток — они по сути своей однопоточные. Любое чтение приводит к обновлению служебной информации (передвижение элемента в очереди), а любая запись требует приостановки чтения до завершения записи.

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

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


Особенности работы LRU кеша

Ниже схематично изображена структура LRU кеша.

Блок-схема получения данных из LRU кеша

А любая запись по своей природе однопоточная и требует приостановки чтения до завершения записи. Частично это можно решить, разбив хранилище на множество независимых сегментов, тем самым размазав доступ к ним по нескольким потокам. Именно так мы и поступили — разделили хранилище по количеству моделей, участвующих в формировании карточки товара.

Теперь хранилища можно сделать типизированными, хранящими по сути указатели на обычные Go-объекты. Это избавило нас от накладных расходов на сериализацию/десериализацию (кастинг в другом варианте реализации) данных при добавлении и извлечении данных из горячего хранили.

Также мы более пристально посмотрели на наши данные и заметили, что примерно две трети моделей, используемых для формирования карточки товара, имеют небольшое количество сущностей. Например, у нас миллионы товаров, но всего около 15 тысяч категорий товаров. Для таких сущностей, как категория, нет особого смысла городить механизм вытеснения — их очень мало в общей массе данных, и вполне допустимо хранить их в памяти все. К тому же потребность в таких сущностях зачастую выше. (Например, на один товар в среднем необходимо получить 3,5 категории.) Поэтому важно постараться, чтобы такие сущности не вытеснялись из горячего хранилища.

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


Проблема синхронизации данных

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

Тут мы рассмотрели три наиболее распространенных варианта:

  1. Ничего не делаем — данные в кеше хранятся какое-то строго заданное время, а затем сами «протухают».

  2. Тегированный кеш с инвалидацией по тегам.

  3. Инвалидация по событиям.

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

Второй вариант был довольно интересным, но он вызывал накладные расходы на получение данных из кеша, которые порой превышали полезную работу.

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

Тут мы не стали ничего особо изобретать и взяли самый простой вариант — очереди на стримах Redis. При всех недостатках Redis, в нашем случае в качестве шины синхронизации он оказался идеальным.

Все репозитории БД в приложении у нас обернуты в декораторы, которые при любых изменениях хранящихся в них сущностей выкидывают в Redis сообщение, что сущность такая-то с идентификатором таким-то изменена. Все инстансы с горячим хранилищем получают это сообщение. Дальше мы пошли на некоторое усложнение: мы не удаляем старые данные, если они есть в горячем хранилище, а заставляем горячее хранилище, если оно содержит эти данные, перечитать их из холодного. Таким образом, мы избавили клиентов от лишнего ожидания подгрузки данных из холодного хранилища и улучшили время ответа в высоких перцентилях.

Уже после тестового запуска мы натолкнулись еще на одну проблему, которая, на мой взгляд, свойственна всем асинхронным системам — это неконсистентность данных между стороной продюсера и стороной консьюмера. Мы обнаружили, что со временем данные в горячем хранилище разъезжаются с таковыми в холодном. Таких данных в общей массе было немного, но мелких неприятностей они доставляли изрядно. Эту проблему, строго говоря, мы так и не победили до сих пор, а может, и не особо хотели тратить на это время, так как уже имели рабочие варианты обхода. Мы просто написали сверку между горячим и холодным хранилищами. Работает она до неприличия просто: раз в несколько часов мы берем все идентификаторы сущностей, какие есть в горячем хранилище, и тупо перечитываем данные по ним из холодного хранилища. Данная операция сильно размазана по времени, поэтому мы ее особо не замечаем на общем фоне других операций.


Проблема прогрева горячего хранилища после деплоя

Далее, в процессе эксплуатации, возникла еще одна проблема: при передеплоях в горячем хранилище не было данных. И всем клиентам, которые в этот момент заходили на сайт, приходилось «немного» подождать. Не сказать, что мы заранее не знали о том, что так может быть, — просто понадеялись, что это будет относительно незаметно. Но чугунная реальность показала ошибочность наших суждений.

Необходим прогрев горячего хранилища до того, как на него пойдет клиентский трафик.
Если с теми частями хранилища, которые реализованы по схеме ассоциативного массива, проблем нет (грузи все, что есть в холодном хранилище), то с вытесняемыми данными все сильно сложнее. Что именно прогревать? Просто загрузить N первых записей? N последних? Или через одну? Все решения в лоб хуже, чем вообще ничего не греть, так как записи, к которым редко обращаются, попав в горячее хранилище, будут занимать чье-то место, а вытеснение такого элемента — это тоже не бесплатная операция.

Что делать? Мы начали собирать статистику того, что у нас лежит в горячем хранилище. Раз в 6 часов берем все идентификаторы всех сущностей, какие есть во всех инстансах приложения с горячим хранилищем, и выгружаем их в таблицу в БД. Такие дампы мы храним несколько дней. При передеплое мы берем из этой таблицы те идентификаторы сущностей, которые наиболее часто встречались в горячем хранилище за последние несколько дней, и только эти сущности загружаем в горячее хранилище. Таким образом, мы «почти» восстанавливаем предыдущее состояние горячего хранилища, и клиенты не чувствуют никаких задержек.

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


Как данные попадают в холодное хранилище

А как же данные попадают в холодное хранилище? Тут все достаточно просто. Есть порядка 40–50 консьюмеров, которые слушают события в Kafka от мастер-систем и, выполнив максимально возможную предобработку данных, кладут их в холодное хранилище, заодно сообщив горячему хранилищу, что надо обновиться (это описано выше).

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


Результаты нагрузочного тестирования

В итоге, что же мы получили? Чтобы узнать это, мы провели нагрузочное тестирование. Для этого мы взяли виртуальную ноду с 8 CPU и 32 GB RAM и развернули там сервис. Тестирование проводилось при 100% попадании в кеш горячего хранилища.

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

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

А вот так сейчас выглядит время ответа одного из инстансов при рабочей нагрузке:

При этом в пиковые моменты мы показываем до 5 млрд карточек товаров в сутки, сохраняя медиану времени формирования ответа около 348 мкс.

Для формирования одного ответа в среднем требуется выполнить примерно 35 запросов к горячему хранилищу и обработать данные из 130 сущностей.

В итоге

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

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

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

Комментарии (59)


  1. Coytes
    30.08.2025 08:42

    Впечатляюще, отличная работа и анализ требований для результата!


  1. Dacom_777
    30.08.2025 08:42

    Несколько миллионов уникальных товаров-вот это загнул, конечно)))


    1. MadridianFox
      30.08.2025 08:42

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


      1. MuratYMT Автор
        30.08.2025 08:42

        Их правда несколько миллионов). Не все продаются на сайте, но тем не менее


  1. Mirzapch
    30.08.2025 08:42

    Ваши миллисекунды ничего не значат, когда для получения товара требуется три часа.

    Это после того, как получено сообщение о том, что товар на точке выдачи, и покупатель уже приехал на эту самую точку.


    1. MadridianFox
      30.08.2025 08:42

      Скорость работы сайта влияет на комфорт его использования. Когда ты ищешь в гугле конкретный шуруповерт, и открываешь деталку товара, если деталка не грузится 1-2 секунды, велика вероятность что ты закроешь вкладку и кликнешь на другую ссылку в гугле.

      А время генерации страницы зависит от выполнения десятков запросов, и становится критичным чтобы конкретный запрос отвечал за столько то миллисекунд.


      1. BlakeStone
        30.08.2025 08:42

        А вот это что-то новенькое! Обычные мантры, которую я привык выслушивать за последние пять лет в малом бизнесе, это «Кому нужен наш товар – спокойно подождут 10-15 секунд, пока не загрузится», «Подумаешь, 15 секунд, а вон у них страница товара за 30 секунд загружается», «Да кто там секунды считать будет, у всех так» и пр.


        1. MadridianFox
          30.08.2025 08:42

          Ну про 1-2 секунды я наверное перегнул, но 10-15, в екоме связанном с едой и продуктами, это авария.

          Наверное если товар уникальный, то действительно скорость работы сайта не так важна.


          1. BlakeStone
            30.08.2025 08:42

            Нет, на самом деле про 1-2 секунды – не перегнули. Даже если товар уникальный. Мантры не мои, моё твёрдое убеждение как разработчика: страница с любым товаром должна грузиться максимум в пределах секунды. Кстати, в одной из компаний вопрос именно так и был поставлен: больше 1 секунды – это проблема, которую следует решать в срочном порядке.


          1. MuratYMT Автор
            30.08.2025 08:42

            10-15 секунд на этапе подбора товаров ждать ответа будут только отъявленные флегматики. Большинство будут пылать негодованием уже после 2-3-4 секунды


    1. Bazis007
      30.08.2025 08:42

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


  1. Kahelman
    30.08.2025 08:42

    У вас с математикой проблемы:
    300 000 запросов в минуту * 60* 24 = 430 млн запросов в сутки.

    Откуда 5 млрд?


    1. lear
      30.08.2025 08:42

      5 млрд карточек вроде, а не запросов.
      Но все равно непонятно что это за единица карточка/сутки.
      Может на тот момент у них требования были 300.000, а сейчас выросли больше...

      Вообщем никаких ответов, только предположения.


      1. Kahelman
        30.08.2025 08:42

        Как вы из 10 млн товаров сделаете 5 млрд карточек? Я ниже данные по крупнейшим платформам привел. У Амазона своих товаров около 19 млн и более 200 млн товаров партнеров. А тут одних инструментов набрали на 10 млн наименований


        1. lear
          30.08.2025 08:42

          Если вам действительно интересно, то спросите у автора)
          Смысл вам писать мне вопросы?)


    1. MuratYMT Автор
      30.08.2025 08:42

      Там нет соответствия 1 запрос - 1 карточка товара. Каталог это тоже набор карточек товаров в миниатюре. Там в одном запросе до 80 таких карточек может быть.


  1. Kahelman
    30.08.2025 08:42

    Особенно порадовало:

    «Наш e-commerce-сайт за ~20 лет вырос из небольшого PHP-проекта в крупный монолит с несколькими миллионами уникальных товаров.»

    «Одним из самых жестких требований к сервису было отдавать всю эту информацию в 99% случаев не более чем за 30 мс. При этом необходимо было иметь возможность хранить не менее 10 млн уникальных товаров и выдерживать в пике не менее 300 тысяч запросов в минуту»

    Насколько миллионов это в любом случае меньше 10. Иначе говорят десятки миллионов.

    Даже если у вас 9 млн. Товаров то они тупо влезают в ОЗУ. Если считать что карточка 4096 байт, то надо всего 38 Гб ОЗУ.
    Вы взяли для тестов сервер с 32 Гб. ОЗУ и 8 CPU - возьмите 128 Гб ОЗУ и побольше процессоров и проблем не будет.

    Ещё вопрос кто может генерить 5 млрд. Запросов в сутки?

    Страница выдачи обычно не более 100 товаров.
    Как правило меньше но-фиг с ним.
    Допустим пользователь маньяк и готов просмотреть 100 страниц.
    5 млрд /(10000)= 500 000 пользователей в сутки
    которые шерстят списки товаров 24*7?

    У Амазона 80-90 посетителей в сутки,

    EBay - 20 млн.
    Avito от 6 до 10 млн.

    Вы пишите что у вас 1.6 млн уникальных посетителей в день. Что может быть правдой, но все равно не стыкуется с вашими данными по запросам.

    Странные у вас данные…..


    1. TkachenkoD
      30.08.2025 08:42

      Не понимаю я ваших замечаний.
      Я полагаю, что у них сейчас система способна обработать до 5 млрд запросов в сутки.
      300к запросов в минуту - изначальное требование к системе.
      То, что товары влезают в ОЗУ - так это сейчас они влезают. Добавятся новые данные, увеличится кол-во товаров, и всё, система не работает, нужно больше ОЗУ. Да и все равно останется инвалидация и прогрев.


      1. Naglec
        30.08.2025 08:42

        Партицирование и снова влезают в озу.


      1. Kahelman
        30.08.2025 08:42

        Вы себе цифру 5млрд представляете? У вас 120 млн. Население в России кто вам 5 млрд запросов в сутки сделает?


        1. WizarDX
          30.08.2025 08:42

          Боты.


    1. tuxi
      30.08.2025 08:42

      Ну даже чтобы просто показать первые 100 товаров, надо все равно сформировать весь список согласно правлам выбранной сортировки, акции там на товары и тп маркетинг.


    1. vvberunenko
      30.08.2025 08:42

      Боюсь, что 4кб на карточку товара будет маловато. Тут либо пытаться запихать карточку в требуемый объем, либо таки делать масштабируемую систему. Ребята пошли по второму пути, теперь рост объемов бизнеса не потребует срочного рефакторинга. Нормальный подход.


      1. izibrizi2
        30.08.2025 08:42

        Почему маловато? В оперативке по сути храеятся указатели на атрибуты товара и их значение. Сильно объем может добавить название и описание товара, но это килобайта 2. Поэтому 4кб это прям очень расписанная карточка. К тому же это дело можно шардировать, чтобы распараллелить нагрузку. Объем на самом деле не большой по меркам текущей стоимости оперативки. Тем более это каталог товара, который редко меняется (в плане описания характеристик). В общем, если у вас 5 лярдов запррсов в сутки, то с серверами на 128 и 256 гигов вопросов не должно врзникнуть.


        1. vvberunenko
          30.08.2025 08:42

          Ну смотрите, я отталкиваюсь от указанной в статье задачи сервиса: "Его задача — агрегировать информацию непосредственно о товаре (название, описание, технические характеристики, габариты, картинки и т. п.), наложить на эту информацию определенную бизнес-логику и отдать её фронту". Понимаю, что изображения - это ссылочный тип, но учитывая 2 байта на символ Unicode там и без того за 4кб карточка переедет легко. А еще на фронт ее, небось, в JSON надо отдавать (overhead не XML, конечно, но тоже немаленький). В общем, предположение о размере у меня выше 4 кб.

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

          На самом деле команда автора реализовала CQRS и совместила с кэшированием. Попали на eventual consistency, как и в любой событийной модели и решили задачу. Я бы, правда, решал ее через хэширование объектов и сравнение хэшей, чтобы не перечитывать ровно все данные из холодного хранилища в background-потоке. Быстрее синхронизация будет. Но на суть алгоритма не виляет, это - нюансы имплементации.


  1. Kahelman
    30.08.2025 08:42

    Ещё нашел данные
    У Амазона около 12 млн «своих продуктов» и около 300-600 млн продуктов на маркетлейсе

    Безос не звонил с предложением Вас купить?


    1. GidraVydra
      30.08.2025 08:42

      С такими объемами Безос должен звонить им с предложением, чтобы они его купили


    1. MuratYMT Автор
      30.08.2025 08:42

      Речь же идет не про показы 5 млрд уникальных товаров. Один товар несколько десятков тысяч раз можно показать за сутки.


      1. GidraVydra
        30.08.2025 08:42

        Но это всё равно будет одна карточка товара


  1. slonopotamus
    30.08.2025 08:42

    в нашем случае в качестве шины синхронизации он оказался идеальным.

    Мы обнаружили, что со временем данные в горячем хранилище разъезжаются с таковыми в холодном.

    Идеальная синхронизация.


    1. MuratYMT Автор
      30.08.2025 08:42

      разъезжается все. вопрос в том какой процент "разъездов".


      1. slonopotamus
        30.08.2025 08:42

        Ну так а в чём тогда заключается идеальность?


        1. MuratYMT Автор
          30.08.2025 08:42

          Хорошо изученный, простая настройка, которая по большей части заключается в "включил и забыл". Быстрый, относительно малое потребление ресурсов.


  1. Ingvarr6
    30.08.2025 08:42

    Мы обнаружили, что со временем данные в горячем хранилище разъезжаются с таковыми в холодном.

    Почему возникла эта проблема если при изменении данных в холодном хранилище вызывается событие на обновление данных в горячем?


    1. sunnybear
      30.08.2025 08:42

      Видимо, было много точек изменения данных, не все покрыли хуками


    1. MuratYMT Автор
      30.08.2025 08:42

      да причин много может быть, от неправильной обработки эвентов, до пучка космических протонов попавших в регистры процессора). Мы так до конца и не победили это. Решение с реконсиляцией оказывается в нашем случае дешевле поиска и устранения всех причин


  1. sunnybear
    30.08.2025 08:42

    Можно, пожалуйста, пояснить, в чем была проблема положить весь каталог в оперативную память? 1 Тб не хватило?


    1. bondeg
      30.08.2025 08:42

      Тогда не вышло бы написать сервис на go для кеширования. :)


    1. Bazis007
      30.08.2025 08:42

      Был у меня на эксплуатации такой проект, когда разработка весь каталог в память запихала... Сначала 20к единиц было.. всё летало.. потом 40к.. потом 60к.. всё вроде работало нормально, но стартовало очень долго..
      А потом в одну прекрасную ночь проект взял и не запустился, потому что был зашит таймаут на ожидание данных в 10 минут, за которые данные не успевали прогрузиться из балы..
      Разрабы крепко спят.. а ты ни чего сделать не можешь, так как откат резлиза тут уже не спасёт. В общем не считать оперативку - безлимитным хранилищем, куда всё можно положить.


      1. MuratYMT Автор
        30.08.2025 08:42

        всё вроде работало нормально, но стартовало очень долго..

        Все так) первоначальный прогрев это одна из расплат за скорость.


    1. MuratYMT Автор
      30.08.2025 08:42

      стоимость/эффективность не дает)


      1. sunnybear
        30.08.2025 08:42

        1. tuxi
          30.08.2025 08:42

          Ну как бы серверная память стоит все же других денег)))


  1. tuxi
    30.08.2025 08:42

    Насчет прогрева. Используем ehcache в качестве кешей, самые критичные делаем персистенс на диске, очень хорошо помогает. Единственный неприятный момент, аппсервер (у нас java) падал пару раз из-за проблем с оперативной памятью, кеш не закрывался корректно, и при следующем запуске по факту его не было.


    1. MuratYMT Автор
      30.08.2025 08:42

      Для го есть https://github.com/olric-data/olric . Но мы как то пока не решились отказаться от персистентного хранилища.


      1. tuxi
        30.08.2025 08:42

        Я немного о другом, у Ehcache есть возможность настроить трех-уровневое кеширование включая уровень холодного хранения: https://www.ehcache.org/documentation/3.11/tiering.html
        Очень удобная вещь. Надо только грамотно реализацию сериализатора сделать.


  1. bolonov
    30.08.2025 08:42

    Напомнило обсуждение штатовского McMaster. https://avva.livejournal.com/3696656.html


  1. niksr
    30.08.2025 08:42

    Интересная статья и знакомые страдания. У меня у самого сто раз было такое, что вроде бы простые вещи требуют нереальных наворотов. Однако потом часто оказывается, что изобретал велосипед и нужно все переделывать) В статье ничего не сказано про изучение существующего опыта, а ведь eBay и Amazon уже все это проходили в больших масштабах, и наверняка инфа об их архитектурах открытая


  1. roma780
    30.08.2025 08:42

    Скажите, пожалуйста, был ли анализ применения иерархических баз данных типа ключ - значение? Парк зеркальных серверов такого типа мне кажется решил бы проблему? Такие БД, как правило, хранят актуальные данные в кеше. У вас действительно 5 000 000 000 товарных позиций?


    1. MuratYMT Автор
      30.08.2025 08:42

      Нет не было. Ну и мне кажется все широко распространённые актуальные БД (постгрес, мускул и т.п.) при достаточных объемах выделенного ОЗУ могут засунуть все данные в кеш. Тут другой вопрос, что любое сетевое взаимодействие это очень медленно по сравнению с походом в память). Мы проводили эксперимент где в качестве кеша использовали 2 ноды мемкеша и в памяти процесса ничего не хранили. Время ответа выросло в среднем в 6.6 раза, а в 99 перцинтиле в 17 раз.


      1. roma780
        30.08.2025 08:42

        Ни постгресс, мускул  не идут ни в какое сравнение с иерархическими БД ключ - значение. Эти базы не транзакционны и быстры на много порядков. При этом у их есть накат журналов изменений. Инициация сетевого обмена - проблема, только в том случае, если БД не имеет пула готовых к коннекту соединений и инициирует новый процесс в ОС. Эта проблема давно решена (созданием пула соединений). Мой Вам совет - ройте в направлении иерархичных БД. Классически случай Cache (но он за деньги). Сейчас есть Йота DB. Пробуйте - уверен - это сработает.


        1. roma780
          30.08.2025 08:42

          1. roma780
            30.08.2025 08:42

            Хотя конечно, 30 мс - это не просто жесткое требование - это аномально жесткое требование, учитывая, что ping до сайта идет около 30 мс. 30 мс - это откуда требование? Оно обосновано?


    1. MuratYMT Автор
      30.08.2025 08:42

      у нас более миллиона товаров доступных к продаже, и раза в 4 больше всех остальных.
      5ккк это сколько карточек товаров формирует сервис за одни сутки


      1. Kahelman
        30.08.2025 08:42

        Вы пишете что у вас более 10 млн товаров, теперь количество товаров упало до 1 млн. - в 10 раз. При этом у вас откуда-то 5 млрд карточек который надо в сутки показать.

        При этом, в Т.З было 300 тыс запросов в минуту на максимуме - то похоже тоже перебор.

        Откуда у вас цифры порядка миллиардов???


        1. MuratYMT Автор
          30.08.2025 08:42

          10 млн товаров это по ТЗ нефункциональные требования. Сейчас уникальных SKU которые можно зайти на сайт и купить сильно больше 1 млн. Даже ближе к 2 млн. Всего уникальных SKU про которые "знает" сервис примерно в 3 раза больше того что можно сейчас купить.
          На сервис поступает в пике 300к запросов в минуту. В одном запросе может быть требование выдать карточки товара как для 1го товара так и для например 80. Из этого и прилучается, что сервис за сутки всего формирует 5млрд карточек товара.


          1. Kahelman
            30.08.2025 08:42

            Я уже писал выше:
            У вас с математикой проблемы:
            300 000 запросов в минуту * 60* 24 = 430 млн запросов в сутки.

            10 млн товаров / 300000 запросов /мин = 33 минуты
            Всю вашу базу за пол часа высосут.

            Вы пишите что в запросе от 1 до 80 карточек, пусть будет 100.
            Тогда чтобы 5 млрд карточек скачать надо:
            5 млрд /100 = 50 млн запросов.

            Откуда у вас столько пользователей чтобы сгенерить 50 млн запросов?

            У wildberris вроде как 50 млн пользователей. Не думаю что 50 млн пользователей каждый день в магазине что-то ищут.


  1. gecube
    30.08.2025 08:42

    Статью только переименовать. Какие карточки ? Языковые типа anki ? Лично мне слово карточка в первую очередь вызывает ассоциацию с банковскими продуктами - дебетовыми или кредитными картами. Ну, край, могли быть карточки лояльности.

    У каждого своя профдеформация


  1. cosmichorror
    30.08.2025 08:42

    Можно конечно и на Феррари в магазин ездить - она мощнее и быстрее, но Тойота - для этого дела подходит так же хорошо и даже лучше.. Поэтому в качестве промежуточной базы - у нас Эластик и никаких - велосипедов)) Не нужно вам 300мкс