Как стать автором
Обновить

Как департамент утилизации CPU превратился в департамент экономии железа, выдерживающий нагрузку в 1 млн RPS

Уровень сложностиПростой
Время на прочтение26 мин
Количество просмотров34K
Всего голосов 128: ↑128 и ↓0+128
Комментарии96

Комментарии 96

Простите, что не в личку, но дико задевает. Утилизация в русском языке это про отходы. Вы имели в виду нагрузку или использование.

утилизация ресурсов всегда означала фактическое использование ресурсов. и в русском языке это вполне применимая словарная конструкция.

в вики:
https://ru.wiktionary.org/wiki/утилизация

Этимология

Происходит от лат. utilisation «использование», далее из utiliser «использовать», далее из utile «полезный», из лат. ūtilis «полезный», из utibilis «годный, пригодный, полезный», далее от гл. uti (вульг. лат. usare) «употреблять, применять, пользоваться», далее из арх. oeti, из праит. *oit-. .

Этимология может быть какой угодно, важно значение в современном языке. Вы же не используете слово "санкция" в значении благославление, освящение? А что, sacer «священный, святой; проклятый».

В толковом словаре

УТИЛИЗАЦИЯ, -и; ж. [от лат. utilis - полезный] Использование чего-л. ненужного (отходов производства, быта и т.п.) или не приносящего непосредственной пользы человеку в целях получения (после переработки) какой-л. продукции, энергии и т.п. 

А в чем проблема слова? В профессиональной среди утилизацию использую в таком значении, статья из проф сферы, вроде все сходится:)

Проблема в том, что это не общепринятый термин, это банальный англицизм, который можно заменить на русский эквивалент без потери смысла. Англицизмы сами по себе в профессиональной сфере это нормально, но не когда они пересекаются с существующими русскими словами. Если я скажу, что испытываю симпатию к девушке, то я сочувствую нелёгкой доле (sympathy) или всё же она мне нравится? Жаргон и термины должны избавлять от разночтений, а не добавлять их. В "департаменте утилизации CPU" есть разночтения. Использование б/у железа - очень даже актуальная тема.

сочувствую нелёгкой доле

Симпатизирую?

не общепринятый термин

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

А мне недавно посоветовали не использовать выражение «выделение кода», ведь для этого есть «хайлайтинг кода». Поэтому тут под каждого не подстроишься, к сожалению

Могу представить, чем не нравится "выделение" в разных контекстах, можно спутать с выделением (переносом) в отдельный класс/модуль. Но есть же и альтернативы: подсвечивание (дословно highlighting, кстати), обозначение. Да, тут можно спутать с подсветкой синтаксиса (которая тоже highlight), но скорее всего это значение и нужно. В русском произношение хайлайтинга язык ломает, особенно на склонениях. Получится улучшить слайд хайлайтингами?

Вы же не используете слово "санкция" в значении благославление, освящение

Как же нет, если несанкционированные мероприятия всё время на слуху?

По-моему в хайлоуде всегда такое значение было у слова, как в статье описано. Да и в общем то какие могут быть вопросы, если в статье пояснили о чем речь, иначе бы и вовсе не поняли:)

Словосочетание "утилизация CPU" сейчас достаточно устойчиво в профессиональной среде, оно используется в публичных докладах на IT конференциях, поэтому посчитала, что для большинства людей оно будет понятным. А если нет, то станет понятным из содержания статьи.

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

Классная статейка!

Спасибо!)

Вот это я понимаю хайлоад!

стараемся!

Очень рада, что откликнулось)

Эх... а где-то в параллельной вселенной народ просто закидывает wordpress плюс woocommerce какой-нть, плюс 150 плагинчиков "ну очень нужных"... и все это на какой-нть 1-ядерной 2ггц самой дешевой vps, за нагрузкой на которой даже мысли не возникает ни у кого следить. Страницы генерируются по 5сек и им норм... вот как будет 10сек, тогда решается вопрос переездом на более дорогой тариф. Но опять же, даже мысли не возникает что надо может хотяб кэш-плагинчик установить чтоли.

Или еще лучше, все это на shared хостинге, от которого вскоре прилетает "превышение нагрузки на cpu". И конечно же для клиента - это хостинг плохой, надо менять... я же ничего такого не сделал, просто стандартный WP с обычными плагинами установил и даже траффика еще нет...

ахах) какое разное IT)

Учитывая, что wordpress это половина сайтов сети, то это не параллельная вселенная, а самая, что ни на есть наша.

Очень понятное изложение, отличная статья, спасибо!

А не рассматривали вариант когда микросервис имеет свой собственный кеширующий прокси спереди, вместо централизованного фасада на все микросервисы?

Спасибо! Рада, что получилось донести что-то интересное)

По поводу кеширующего прокси - не совсем ясна идея, имеется ввиду перед каждым микросервисом свой прокси?

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

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

Опечатка в вопросе. Хотела спросить, чем лучше относить затраты на бизнесовый сервис, а не инфраструктурный?

Спасибо огромное, прекрасная статья!

Радостно очень, что понравилось!

Немного дёгтя в бочку мёда от комментаторов выше.

Сопоставим две цифры:

В пике мы отдаём 350 Gb/s данных о товарах

и

наша цель — держать 1 млн RPS

в результате имеем 350*10^9/10^6 = 350 000 байт на один запрос. Напомню - речь идёт о запросах на остатки товаров. Предположим, что под идентификатор товара используется 8 байт, под количество - ещё 4 байта. Плюс обвязка из бинарного протокола, пусть ещё 8 байт на запрос. Итого - могло бы быть 20 байт вместо 350 килобайт. Как тебе такое, Илон Маск?

Ещё циферка:

666 инстансов сервиса, написанного на Golang, по 7 ядер CPU и 7.5 Gb RAM на каждый

При пике в 1М RPS имеем 1500 запросов к одному серверу в секунду. Да, если всё читать с диска - сервер не потянет. Но на нём, между прочим, есть 7.5 Gb RAM. То есть надо по идентификатору найти в индексированном дереве один узел. Время такого поиска не превышает нескольких микросекунд. То есть, даже с учётом накладных расходов, имеющееся в наличии время в размере 666 микросекунд на запрос является очевидно избыточным. Но ребята не останавливают свою кипучую деятельность и осваивают хитрые схемы управления многоуровневыми кэшами. Ну что тут сказать, чем бы дитя не тешилось - лишь бы не плакало. А бизнес вполне справедливо оплачивает эту потеху.

В целом хочу сказать спасибо за предоставленные цифры. Понимаю, что последует масса возражений про "да ты ничего не понимаешь, у нас всё намного сложнее, и вообще бизнес нами доволен!". Ну да ничего, главное - для умеющих считать в объёме начальной школы уже очевидна неэффективность принятого в данной корпорации подхода. Хотя разумеется, если кому-то нравится всё мерить чем-нибудь вроде "скорости релизов" или ещё каких-нибудь малопонятных попугаев, приводимых без возможности сравнить с альтернативами, то я заранее готов принять на себя огонь критики и признать своё поражение в борьбе с недоказуемыми утверждениями.

У меня при делении 350Гбит/сек на 1млн запросов получается 45кб. Похоже вы перепутали биты и байты.

Также я не очень понял как json с бэкенда со всей хурмой которую видно на странице товара (описание, цвет, производитель и т.п), не говоря уже про метаданные, у вас влезает в 20 байт. Не знаю конечно чего там на 45кб, без картинки я бы предположил 1-10кб на запрос, с картинкой в среднем 45кб легко может выходить.

У меня при делении 350Гбит/сек на...

В исходном тексте было: 350 Gb/s. Автор не уточнил, что это, ну а я выбрал наиболее часто используемый вариант трактовки данной аббревиатуры. Если вы настаиваете именно на гигабитах, то попросите автора прямо подтвердить этот момент.

Также я не очень понял как json с бэкенда со всей хурмой которую видно
на странице товара (описание, цвет, производитель и т.п), не говоря уже
про метаданные, у вас влезает в 20 байт

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

Наиболее частый и общепринятый вариант - все таки гигабиты. https://en.wikipedia.org/wiki/Data-rate_units

Дальше вы как-то не конструктивно пошли, увы.

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

Принимайте, всегда и везде Gb/s это Гбит/сек

После этого утверждения все ваши расчеты можно выбросить

Уточнение: RPS (request per seconds) - это не тоже самое, что PPS (products per seconds), это разные метрики. В одном запросе может быть больше одного товара.

А что заставило вас думать, что речь идёт о "Напомню - речь идёт о запросах на остатки товаров"?

В тексте об этом написано и на схеме визуализировала, что речь идет об информации из нескольких десятков разных систем. В общих масштабах информация об остатках товаров - это примерно ничего от общего объема данных.
Если вдаваться в детали, то дальше по тексту упоминается множество атрибутов товара, ещё, есть, например, аспекты - эта другая сущность, их тоже может быть множество.
Помимо существует множество разных сущностей - склеек товаров по разному принципу, чтобы выдавать разного рода рекомендации, и для все них тоже тоже требуется полное описание, и тд и т д и т д.
В самих запросах при этом ни по одному товару, а от 1 до 1 000, в зависимости от задачи.
В очень общих чертах об этом в статье упоминается. Но статья совсем не об этом и не про расчёты, поэтому считаю лишним перегружать её этим.

А что заставило вас думать, что речь идёт о "Напомню - речь идёт о запросах на остатки товаров"?

Ваши слова:

Наш сервис выполняет роль фасада по товарам и рассчитывает на лету доступность товаров для всех сервисов витрины

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

Если вдаваться в детали, то дальше по тексту упоминается множество атрибутов товара...

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

Но в вашей ситуации это всё не нужно. Потому что ваша задача на миллион запросов в секунду намного проще.

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

Нет смысла локально оптимизировать то, что давно мертво в следствии глобальной оптимизации (обычно по критерию "мне так проще", но иногда ещё и деньги участвуют).

Доступность товара, в общепринятом понимании, есть количество в наличии, то есть остатки.

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

Но в вашей ситуации это всё не нужно

Как-то странно Вы сделали такой вывод, только исходя из короткого описания микросервиса в статье, совершенно не зная архитектуры системы.

Если в ответе может быть более одного товара, то 45KB выглядит уже абсолютно нормально. Плюс сервисы аналитики и тп. Но тогда ещё больше удивляет цифра в 300К запросов в секунду. Можете подсказать, какие сервисы генерируют основной RPS, а какие основную нагрузку?

У вас всего 1500 запросов на инстанс в 7 ядер CPU и 7.5 Gb RAM. Подскажете, что так сильно кушает CPU? Спасибо.

НЛО прилетело и опубликовало эту надпись здесь

Вот почему-то захотелось поработать в вашей команде и набрать релевантного опыта... Но увы.. Java мое всё.

Моим первым языком тоже была Java, не пожалела, что перешла на golang)

Статья огонь! Спасибо!


Но не понимаю, что не так с Java. Если нужно экономить потоки, то есть реактивщина (хоть и не всем нравится стиль программирования). А так вышла 21-ая LTS с легкими потоками а-ля Go. Да, пока многие библиотеки еще не адаптированы, и в самой фиче есть, что доработать, но через пару релизов, думаю, будет все окей, к следующему LTS так точно.

К java вопросов нет, в озоне она тоже есть) Конкретно на нашем проекте исторически сложилось так, инфраструктура наиболее развита под go.

Тут скорее хочется узнать чем вас зацепил go, возможно даже без сравнения с Java (а можно и со сравнением). Не для для холивара go-java, а из интереса.

На мой взгляд Go отлично выполняет задачи, которые перед ним поставили разработчики: упрощает вход для новых разработчиков, даёт готовые паттерны, предоставляет единый кодстайл.

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

У Google была ведь проблема, что все эти интерны, джуны, приходили к ним, говнокодили и уходили. А потом убирай за ними. На мой взгляд это всё идет от того в условной Java очень много способов написать одну и ту же программу. В Go же тебе специально заворачивают руки и говорят "пиши так", поэтому я буквально могу встретить такой же кусок кода у коллеги, потому что иначе его написать весьма нетривиально. На больших командах это хорошо работает и позволяет держать код умеренно консистентным.

Высоконагруженная Java в Озоне тоже есть

В тексте опечатка? - "Сейчас мы не держим в памяти product-facade такую информацию, которая не допускает рассинхрона в обновлении". 

Опечатки нет, но два отрицания в одном предложении плохо воспринимаются. Поэтому переформулировала более читаемо, спасибо!

докину ещё несколько трюков, которые в статье [вроде бы] не упомянуты:

  1. Не ставить TTL константой в 2 часа, а рандомизировать в диапазоне 110-130 минут. Иначе ключи, появляющиеся одновременно (например, по крону), протухают тоже одновременно и разом бьют по базе.

  2. Вместо продлевания TTL в решении проблемы "стаи собак" можно зайти с другой стороны - с некоторой малой вероятностью умышленно проигнорировать кеш и отправить один запрос читать напрямую из баз и обновлять ключ. Например, с вероятностью 0.001%. Если это настоящий хайлод-ключ с 1000qps - он будет обновляться раз в ~100 секунд без нагрузки на базу. Если ключ не по-настоящему хайлодный, то его протухание по ttl не ударит по базе.

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

И вопрос: вместо размазывания ключа по нескольким индексам сразу с разными префиксами/суффиксами вы выбрали in-memory-кеш с кафкой. Если вы знали о схеме с размазыванием ключей, но выбрали другую, то какие критичные для себя минусы вы увидели в схеме с размазыванием?

Почему спрашиваю: когда-то на проекте с такими же qps довольно неплохо жили как раз на размазывании, и массовая инвалидация не требовалась: требовалось массовое обновление до актуального состояния. И тогда тот кусок бизнес-логики, который обновлял данные в бд, сам актуализировал их в N репликах ключа, новая нагрузка на кеши и базу не создавалась, обновлённые данные были видны всем. А если и были ошибки сети на обновлении 1 ключа, то они случались так редко, что залипшая 1 из N реплик данных нам вредила не очень сильно как раз из-за сравнительно быстрой актуализации через трюк №2.

p.s.: имхо, странно, что в статье делается много акцента на инвалидации кешей, а не на их актуализации. Хотя это намного более приятная процедура.

Спасибо за дополнение!

 Если вы знали о схеме с размазыванием ключей, но выбрали другую, то какие критичные для себя минусы вы увидели в схеме с размазыванием?

Критичных минусов в этой схеме для себя не видели, а решили идти таким путем, чтобы заодно снять немного нагрузки с сети. Сеть у нас была "ближайший ботлнек" на наших серверах. Это связано с тем, что мемкешам мало требуется CPU для работы, а данных гоняется очень много. В итоге сетевой интерфейс - это было первое, во что мы уперлись бы.


P. S.: имхо, странно, что в статье делается много акцента на инвалидации кешей, а не на их актуализации. Хотя это намного более приятная процедура.

У нас была мысль сделать так, чтобы при получении ивента об изменениях из кафки мы не просто инвалидировали кэш, а сразу писали новое значение.
Но мы прикинули, что:
1) существенного профита относительно текущего подхода нам это не даст, поэтому пока не стали переделывать. По всем ключам, по которым это возможно, у нас хитрейт итак сейчас около 100%.
2) не для всех ключей у нас это возможно, так как, например, доступность товара у нас кэшируется по локации пользователя. Доступность товара напрямую зависит от неё.

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

существенного профита относительно текущего подхода нам это не даст, поэтому пока не стали переделывать

А почему если не секрет вы такое предположение делаете? Кмк проще сразу новые данные по событию записать чем узнать из него что что-то "протухло" и прийти за новыми данными? )

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

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

Спасибо, понял) Как идея для рефлексии - а может начать с нуля рядом где-нибудь? "контракт" же все равно тот же останется, А/Б тест легко покажет стоит дальше вкладывать или нет )

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

Я все-таки не понял, откуда 300k rps нагрузки на этот сервис?
Или каждый товар на странице ozon всегда приводит к запросу на сервис, т.е. если из поиска показывается, например, 100 товаров, то это дает 100 запросов?
Впрочем, откуда 3000 страниц поиска в секунду в среднем - тоже не очень понятно (да и обычно там гораздо меньше 100 товаров).
Хм, а улучшение поиска как метод борьбы с нагрузкой не рассматривалcя? На порядок-два количество просмотров точно можно уменьшить.

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

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

Про проблему стаи собак: читал где-то, что разработчики Discord решили её за счёт поддержания в памяти набора активных запросов к бекенду. Если приходит запрос на те же данные, на которые уже есть активный запрос, то нового обращения не происходит. Когда данные от бекенда будут получены, они будут отданы всем запросам на них.

Спасибо за дополнение!


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

Спасибо!

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

С чем связан выбор го для бакэнда? В той же Java вопросы перформанса решаются достаточно просто, есть разные библиотеки для кеширования, развитые средства профайлинга и мониторинга, есть куча разработчиков которые понимают как делать быстро и надёжно. Если бы я стал что-то делать на го, то я бы никогда не достиг бы такой производительности как на Java или C++, просто потому что язык малоизвестный и непонятно как его "готовить".

Если в вашем сообщении поменять местами Java и Go, то смысл не изменится :) Непонятность и малый опыт разработчиков на рынке - это что-то лет так 10 назад, или больше.

С чем связан выбор го для бакэнда? В той же Java вопросы перформанса решаются достаточно просто, есть разные библиотеки для кеширования, развитые средства профайлинга и мониторинга, есть куча разработчиков которые понимают как делать быстро и надёжно.

Выбор связан с уже имеющейся развитой инфраструктурой под go.
Вряд ли среди джавистов намного больше высококвалифицированных, свободных, и находящихся в активном поиске разработчиков, чем в go.
В golang тоже вполне себе неплохие средства профайлинга имеются, ими и пользуемся про поиске мест для потимизаций. https://go.dev/blog/pprof

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

Именно так. Хотя бы потому, что джава существует дольше и у разработчиков больше опыт.

Повторюсь, эффективность зависит не только от квалификации, но и от развитых инструментов и библиотек, книг, в конце концов.

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

В golang тоже вполне себе неплохие средства профайлинга имеются, ими и пользуемся про поиске мест для потимизаций. https://go.dev/blog/pprof

Это то что вы привели по ссылке вы называете "неплохими средствами профайлинга", то что тогда плохое средство??


Хороший инструмент для профайлинга должен выглядеть хотя бы вот так.
Для джавы подобных инструментов я знаю как минимум 6. Сколько подобных инструментов есть для GO?

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

О чём вы, какие конфиги. Я xml уже лет 5 как не видел. Спринг это такая штука, которая позволяет не заниматься фигнёй в сотый раз изобретая велосипед (типа того что в статье описано), а скучно заниматься бизнес-логикой.


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

ну я 3 года назад xml-конфиги видел, когда джавистом был. И про апдейт очень интересно конечно, но скажите это автору недавнего доклада на qiwi митапе, где рассказывалось, как за 2 недели быстро обновить джаву, поменяв везде пакеты с одного нейминга на другой, так как они уехали в другое место, пару мест тут, там и так далее.
Спринг это такая штука, которая позволяет долго сидеть, читать доку и прочее чтобы разобраться, почему она сломалась в этом месте, вместо того, чтобы самому писать код и иметь понимание, что он делает, а не трясти волшебную черную коробку
Самое смешное, что мне попадалось - что без конфига она даже логи не пишет, просто запускается и умирает. Попробуй обьясни новичку, почему у него спуленный с мастера сервис не работает

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

Спринг это такая штука, которая позволяет долго сидеть, читать доку и прочее чтобы разобраться, почему она сломалась в этом месте, вместо того, чтобы самому писать код и иметь понимание, что он делает, а не трясти волшебную черную коробку

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

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

самому писать код и иметь понимание

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

Про малоизвестный вы должно быть шутите? На нём же написано дофига продуктов и инструментов.

Для инвалидации in-memory всех инстансов не нужно заводить редисы и прочие pub-sub. Достаточно каждый инстанс посадить на топик без consumer group и пусть каждый читает одни и теже эвенты.

По thundering herd. Есть простое решение в виде библиотеки singleflight и подобной ей механизмов. Пока один запрос выполняется, все остальные стоят и ждут на локе. После разблокировки все получат один и тот же ответ и дальше пойдет раздача из кэша. Можно сделать лок распределенным, но в большинстве случаев не страшно, если будут локальные локи и каждый инстанс пойдет на промахе один раз в основной стор.

Для инвалидации in-memory всех инстансов не нужно заводить редисы и прочие pub-sub. Достаточно каждый инстанс посадить на топик без consumer group и пусть каждый читает одни и теже эвенты.

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

Хорошая статья. Местами прямо перебор с оверинжинирингом и NIH, о чем, в том числе, часть комментов выше, но и полезное есть.

Спасибо за фидбек! А можно пожалуйста развернуть мысль, в чем NIH?

Наверное, у меня какой-то другой озон. Зашел на главную, набрал в поиске запрос. Через 26 секунд перестали крутиться часы в загрузке страницы и показались картинки верхнего ряда и то не все. Зачем тогда это всё? И это не только сегодня так поиск работает.

Дальше кручу ниже, там такое:

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

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

У нас ведется постоянный мониторинг TTLB, TTFB, LCP, SpeedIndex метрик, и все случаи деградации расследуются для установки причин и их устранения.

У меня нет проблем. Проблемы у озона, и возникают они у разных людей.

Справедливости ради стоит перепроверить как ваши коллеги измеряют циферки

скриншот загрузки изображения первого товара в списке

Какой у вас объем данных во внешних кэшах?

1) Проблему прогрева in-memory кэшов можно решать с помощью файлов. Собирать кэш по частоте запросов в файл с помощью оффлайн процесса. На старте дергать файл из Object Storage и десериализовать в память. Это быстрее и дешевле, чем пиковые нагрузки KV хранилища при рестарте.

Инвалидацию и обновление так же оставить на кафке. Приложение может начать читать обновления с оффсета прописанного в файле кэша.

2) У вас низкое соотношение ядер к памяти. Если поднять до стандартных 1к4 или 1к8 для RAM-оптимизированных, то можно отказать от внешнего кэша совсем при правильном шардировании или sticky-sessions без изменения логики приложения. Я так сэкономил 200к$/месяц перенеся кэши из редиса в память general purpose AWS EC2-инстансов.

3) Посмотрите в сторону memory-mapped файлов на SSD и их индексов в памяти. Сам видел 200Гб информации о товарах на SSD для системы рекоммендации от вашего азиатского конкурента. У них latency SLO  был около полсекунды и это включая рекомендации. Но у них не было обновлений. По идее можно хранить последние обновления в памяти, пока новый индекс не подъедет.

Я так сэкономил 200к$/месяц перенеся кэши из редиса в память general purpose AWS EC2-инстансов.

Вы стали запускать редис на кастомизированном ec2 вместо эластика или сделали in-memory внутри каждого инстанса сервиса?

Ого, ачивку за самый большой хайлоад заказывали для моей команды, когда мы выкатили скидки в начале года

Возможно упустил, но правильно ли я понял что ваша схема не предполагает ответ из кеша на запрос3 если он является сопоставлением данных кеша по запросу1 и запросу2. Т.е. кэш не знает бизнес-смысл данных?

Не очень поняла вопроса, не могли бы переформулировать, о каком сопоставлении идет речь?

Если ответ на запрос1 содержит данные о клиенте и телефоне, ответ за запрос2 - данные о клиенте и email, то кэш не сможет сам ответить на запрос клиент+телефон+мыло? Для него это просто ответ1 и ответ2 и какие данные там ему не очень интересно?

Спасибо за статью! много всего, любопытно.

В своем время я тоже съел собачку на кэшировании и не одну )

Из вещей которые могут оказаться вам полезны, о которых вы не упомянули и которые интересно исследовать это: сжатие данных при записи в кэш (в свое время результаты меня приятно удивили) и тестирование разных оптимизированных реализаций сериализаторов.

Спасибо за отзыв и за дополнение!

Действительно не упомянула про сжатие, и зря, это отдельная очень интересная тема. Мы его используем, в частности библиоткеку github.com/golang/snappy

про хаммеры - я так понимаю все равно система падает, если при заказе просит обновить страницу , а потом говорит товар закончился?

Ну и после этого на главной странце продолжает рисовать картинки с неверными остатками какое то время? Или там разные склады, не те с которых мне повезут?

Система не падает (хотя, что вы имеете ввиду под словом "падает?"), тут есть несколько моментов:

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

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

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

что для вас вернется ошибка? Я делаю заказ , все идет хорошо но вместо закзаза / или отказа что товар кончился , мне говорят перегрузите страницу... Это ошибка вернулась или система отпала?

Интересная и полная статья, спасибо. Появилась идея по прогреву локального кэша -- можно, как минимум, добавить распределенный кэш между локальным и источниками; а в максимуме -- по какому-нибудь gossip-like алгоритму распространять данные по локальным кэшам (но про это ничего не нагуглил :)), либо прямо через балансировщик запрашивать данные с уже прогретых (ready) сервисов

Спасибо за отзыв!

Идея с gossip-like прикольная, но мне кажется, не самое простое и оптимальное решение по прогреву in-memory, хотя все зависит от того, что представляет из себя система в целом)

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

Пишите ещё, спасибо!

Очень мотивируют такие комментарии писать ещё, спасибо!)

>666 инстансов сервиса

не суеверные.

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий