Уже лет 20 существует миф (или не миф), что современный Highload-проект невозможен без кэшей. Они всегда нас выручали, когда не справлялись базы данных. Но с тех пор, как появились первые кэши, key-value баз данных и другие технологии, многое изменилось и традиционные СУБД значительно эволюционировали. И так ли теперь нужен кэш?

Мы протестировали самые известные кэш-сервисы и СУБД и попробовали выжать из них миллион запросов в секунду в разных условиях. Делимся с вами результатами в этой статье.

Привет, Хабр! Я Алексей Рыбак, предприниматель и основатель R&D-лаборатории DevHands, автор телеграм-канала про System Design и Highload. В прошлом — СТО и руководитель московского офиса Badoo. Работал во втором по размеру такси-сервисе «Везёт», который мы после продажи интегрировали с Яндекс.Такси. Сейчас наша компания разрабатывает образовательные программы по Highload и перформансу.

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

Чтобы сравнить производительность баз данных и кэшей, мы взяли самые современные версии продуктов — Postgres, MySQL, Valkey, Redis и Memcached и провели серию исследований, где выжали из них миллион RPS на определённой нагрузке. 

Два взгляда на Highload: кэш-слой или традиционные СУБД?

В мире высоконагруженных проектов есть два противоречащих друг другу мнения:

  1. «Умение использовать кэш-слой — это основа успешного Highload-проекта».

Его сторонники считают, что без кэша ничего нельзя сделать. Что он решает если не все, то подавляющее большинство проблем с производительностью.

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

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

Первое мнение скорее отражает мир инженеров, активно экспериментирующих с архитектурными компонентами, новыми базами данных и открытых к новым решениям. Они развиваются значительно быстрее, чем рынок традиционных СУБД — key-value хранилища, NoSQL, NewSQL. Второе мнение  представляет мир «традиционных» СУБД и всех, кто «прикипел» к родным инструментам.

Почему кэш = неконсистентность?

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

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

В начале 2000-х Дэн Кигель создал страницу, посвящённую «проблеме 10 тысяч соединений» (C10K), эта страница существует до сих пор. Уже тогда было понятно, что существующие подходы не справляются с одновременным обслуживанием такого количества соединений, и Кигель собрал наиболее распространенные способы решения «проблемы 10 тысяч соединений». С тех пор произошли существенные трансформации в серверостроении, они затронули все виды серверов, включая базы данных. Ведь количество онлайн-пользователей постоянно росло, а базы не успевали обрабатывать поступающие запросы.

И хотя комьюнити и рынок осознали ресурсоёмкость и сложность парсинга SQL, поддержки транзакций ACID и других особенностей мира традиционных СУБД, сами базы данных были и остаются довольно консервативными. В  результате произошло несколько важных событий:

  • 2004 год. Для Livejournal Брэд Фитцпатрик и Анатолий Воробей запустили проект Memcached, который позволял значительно ускорить генерацию динамических веб-страниц, существенно превосходил по показателям производительности базы данных и стал повсеместно использоваться в крупных интернет-проектах.

  • 2009 год. Salvatore Sanfilippo создал Redis, добавив в него множество возможностей, которых не хватало программистам в кэш-сервисе и не было в Memcached. Это дало толчок к разработке множества KV-, NoSQL- и NewSQL-решений.

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

Что умеет кэш в базовой версии

В нулевом приближении кэш или легковесная база обладает такими свойствами:

  • «Мультиплексирование» соединений

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

  • Лёгкий протокол: отсутствует SQL

Протокол, по которому приложение общается с кэш-сервисом, априори значительно проще SQL. Значит, меньше ресурсов будет тратиться на приём-передачу данных.

  • Лёгкий «внутри»

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

Как результат, кэш способен обрабатывать свыше 100K RPS на одно ядро и выполнять миллион запросов в секунду для тысяч (а то и десятков тысяч) одновременных соединений.

СУБД и кэш-сервисы в 2024 году

Давайте теперь сравним современные кэши с традиционными СУБД:

  • Мультиплексирование соединений

У традиционных СУБД есть ограничения. Например, PostgreSQL изначально не поддерживал мультиплексирование соединений, так как использует модель «process per connection». Однако, начиная с версии 15 (возможно, уже с 14) PostgreSQL сделал фантастический скачок вперёд. Теперь он может работать с большим количеством соединений, благодаря менее ресурсоёмким процессам и ряду оптимизаций. Конечно, это не скейлится бесконечно и в какой-то момент перестаёт работать, но ситуация значительно лучше, чем 5−10 лет назад.

А с MySQL иная ситуация. Здесь используется модель «thread per connection». Она потенциально лучше с точки зрения скейлинга по количеству одновременных соединений, но в последние годы, по сообщениям многих ресёчеров, у MySQL были некоторые деградации по производительности.

  • Лёгкий протокол

Мир СУБД претерпел огромное количество оптимизаций. Но и в целом в нашем кейсе SQL-запросы очень простые, поэтому есть шанс, что здесь базы данных если и проиграют, то несильно.

  • Лёгкие структуры данных

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

  • Скейлинг по ядрам для тысяч одновременных соединений

Остаётся открытым вопрос: какая ситуация со скейлингом по ядрам или по большому количеству одновременных соединений и у кэшей и у СУБД? Сравним их производительность в реальных тестах.

Тестируем СУБД и кэши

Для исследования взяли кэши:

  • Redis — самый распространенный KV-Storage и кэш.

  • Valkey — клон Redis, свежий ответ от cloud-провайдеров на смену лицензии Redis.

  • Memcached — отличный, очень простой и по-прежнему популярный кэш-сервис.

И СУБД:

  • PostgreSQL — одна из самых распространённых и открытых баз данных, наиболее популярная в России.

  • MySQL — также распространённая и открытая база данных, в мире не менее популярная, чем PostgreSQL. Тестировали сборки с дополнительными модулями: Heap, Handler Socket, Memcached plugin. Также протестировали специализированную сборку от первого российского вендора — MyDB. Но по сути это отечественный форк MySQL, так что особенной разницы между MyDB и MySQL нет.

Наши задачи:

  • Попробовать выжать миллион RPS на разных ворклоудах.

  • Проверить, как скейлятся СУБД по количеству открытых соединений.

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

Среда тестирования:

  • Инструменты: sysbench, memtier и redis-benchmark.

  • Железку для тестов взяли не самую дорогую, с процессором Xeon Gold 6312U, 48 виртуальных ядер в режиме гипертрейдинга, 128 ГБ памяти. 

  • Тесты выполнялись в режиме ReadOnly — «чистый» кэш, всё в памяти, никакой дисковой нагрузки.

Мифы о скейлинге и производительности кэшей и СУБД

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

  • Redis не скейлится по ядрам. Многие считают, что Redis плохо скейлится по ядрам, но это не совсем так — Redis предпринял шаги для масштабирования. Я не видел соответствующих графиков и хотел сам проверить.

  • А Valkey тогда что — получается, скейлится? Про его перфоманс было очень много пиар-статей в последнее время, проверим и это.

  • Модель «thread-per-connection» в MySQL якобы превосходит модель «process-per-connection» в PostgreSQL. Значит ли это, что MySQL скейлится лучше PostgreSQL?

  • Обратный миф: PostgreSQL во всём превосходит MySQL. А это мнение удивительно популярно у нас, мол, MySQL старый и проприетарный, PostgreSQL развивающийся и свободный, и ничем не уступает.

  • Современные традиционные СУБД уже настолько хороши, что кэш-слой не нужен. Это, собственно, главная тема нашего исследования. 

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

Redis

Мы тестировали Redis 7.2.5 с redis_benchmark, с базой из 10 млн ключей по 256 байт и режимом appendonly no + save “”. График ниже ликвидирует миф о том, что Redis не масштабируется по ядрам. Redis скейлится,  хоть и не идеально:

На втором графике по оси X отображается параметр io-threads, который конфигурируется в redis.conf, а по оси Y — медианное latency запросов:

В режиме кэша, без использования append-only и снэпшотов, Redis отдаёт примерно 300–400 тысяч запросов в секунду при использовании около восьми io-threads. Притом, что с одного ядра в режиме, когда io-threads равен единице, число достигаемых запросов — около 160000 в секунду. Несмотря на то, что ядер на машине значительно больше, мы не можем выжать ничего сверх этих значений. Latency остаётся на приемлемом уровне: при конфигурации с восемью io-threads всё стабильно. Таким образом, Redis скейлится, но не идеально.

Redis vs Valkey

Если сравнить Redis и Valkey становится очевидно, что Valkey смог устранить многие узкие места характерные для Redis. На графике ниже видно, что там, где Redis достигает максимума, Valkey без специальных оптимизаций отдаёт чуть меньше миллиона запросов в секунду. Значит, есть потенциал на более мощном железе:

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

Valkey vs Memcached

При аналогичном наборе ключей Memcached демонстрирует значительно большую пропускную способность по сравнению с Valkey. Он способен обрабатывать почти 1,7 млн запросов в секунду. Тогда как Valkey при примерно 1000 одновременных соединениях выдаёт чуть менее 1 млн запросов в секунду.

Из этого можно сделать вывод, что у Memcached, как и Redis, хороший потенциал, если нужен только кэш. На практике Memcached обеспечивает примерно в 1,5 раза лучший throughput.

Scaling PostgreSQL

Настало время взглянуть на базы данных. Первое, что нас интересовало — как масштабируется PostgreSQL при большом количестве одновременных соединений. Это оказалось для меня огромным сюрпризом. График обрывается на определённом значении, и видно, где PostgreSQL перестаёт справляться на достаточно большом числе одновременных соединений, в нашем случае — больше 5000 (в общем случае этот лимит пропорционален размеру памяти):

Представьте сервер, где load average достигает 5000. Вы выполняете команду, вроде ps aux | grep postgres, видите 5000 реальных процессов, и машина при этом отзывается и консоль нормально работает. В общем, сделан действительно значительный шаг вперёд, но сама по себе модель не позволяет скейлиться до очень большого числа соединений на таком размере памяти. В нашем случае уже при превышении 4500 начали возникать проблемы.

На конференции я встретил ребят, которые показывали шкаф с предустановленным и настроенным PostgreSQL, где используется в 5–10 раз больше памяти. Я видел их презентационные материалы: число одновременных соединений достигает нескольких десятков тысяч. Но это очень серьёзная машина с более чем 700 ГБ памяти, и для работы PostgreSQL на такой нагрузке требуется огромное количество оперативной памяти.

PostgreSQL vs MySQL 8.4

Для теста MySQL мы взяли «ванильную» MySQL 8.4 и нагрузили её примерно так же, как PostgreSQL:

  • MySQL 8.4 с оптимизациями (buffer pool + ещё около 10 параметров).

  • PostgreSQL с минимальными изменениями (только max_connections и shared_buffers).

В ходе тестирования в глаза бросилось сразу несколько вещей. Долгое время ходил миф, что MySQL «из коробки» может работать с большими нагрузками без особого тюнинга, а в PostgreSQL нужно менять миллион конфигураций, чтобы добиться хорошего RPS.

По моему опыту, ситуация скорее обратная. Postgres мне совсем не пришлось тюнить. Подкрутили буквально пару параметров, в результате он выдал почти миллион RPS на тестовой кэш-нагрузке. Чтобы MySQL достиг аналогичной производительности, параметров пришлось менять больше.

MyDB

Помимо стандартного MySQL 8.4, мы взяли специально оптимизированную сборку MyDB — российский клон, построенный на основе MySQL, который уже есть в реестре российского ПО.

В MyDB уже применены оптимизации: использование huge pages, особые флаги компиляции и дополнительные изменения в конфигурации. Оказалось, что небольшие исправления и пересборка бинарного файла позволяют выжать из MySQL значительно больше. 

Известно, что за последние несколько лет C++ код MySQL оброс большим количеством усложнений, и многое ещё предстоит оптимизировать. Но большое количество вещей уже оптимизируется определёнными флагами или подходами. Большое спасибо фаундеру MyDB, Алексею Копытову, который подсказал мне эти нюансы.

Итак, наша сборка MyDB была построена на MySQL 8.4 с оптимизациями: LTO, PGO, huge pages и рядом других настроек. В такой конфигурации всё отлично скейлится, выдавая более миллиона запросов в секунду:

MySQL Heap

У нас было много идей, что ещё проверить в экосистеме MySQL. Но больше других хотелось протестировать Heap engine, давно живущий в MySQL и Handler Socket — упрощённый протокол для работы с InnoDB. Это in-memory движок, и, по идее, он должен работать значительно быстрее, чем InnoDB. Мы настроили его и провели тесты.

Результаты, как видно на графике выше, показали, что ни Heap, ни Handler Socket не дали нужного эффекта. Оба решения масштабируются по ядрам значительно хуже.

MySQL memcached plugin

У MySQL есть по-настоящему волшебный memcached-плагин, который довольно редко используется в продакшене.

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

Memcached-плагин берёт InnoDB таблицу и создаёт к ней интерфейс через протокол Memcached, когда можно открыть соединение на дефолтный 11211 порт, по Memcached-протоколу выполнить операции GET и SET. Всё это сохранится в персистентную таблицу, с которой можно работать, в том числе, через SQL.

Мы выставили следующие значения для тестирования:

  • innodb_memcache.cache_policies

    • get_policy: caching 

    • set_policy, delete_policy, flush_policy: innodb_only

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

Получается, что если у вас есть Memcached не персистентный, а нужна персистентность, то в качестве альтернативы перехода на Redis или Valkey есть дешёвый способ реализовать это с помощью Memcached-плагина MySQL.

Чтобы плагин заработал, пришлось даунгрейдиться до дистрибутива MySQL 8.0, и не использовать более новую версию 8.4. Это третий дистрибутив, в котором отсутствуют многие оптимизации, применяемые в тестах MyDB. Возможно, если пересобрать MySQL с определёнными флагами и ещё что-то сделать с инсталляцией, то с Memcached плагином из неё можно выжать и больше.

Что получилось в итоге

Вернёмся к мифам о скейлинге и производительности современных кэшей и СУБД. Что мы получили в этом исследовании:

  • Redis не скейлится по ядрам → Формально — нет, но вообще — да.

Redis скейлится, но не идеально. При использовании примерно 8 io-threads Redis достигает около 300–400 тыс. запросов в секунду, тогда как при одном io-thread — около 160 тыс.

  • Valkey скейлится → Не совсем, но точно лучше Redis.

Valkey показывает примерно в 2,5 раза больший RPS по сравнению с Redis при схожих условиях. При этом, увеличение числа ядер свыше 6–8 уже не даёт существенного прироста.

  • MySQL скейлится лучше PostgreSQL → Тут скорее паритет по производительности.

Несмотря на паритет, у модели «thread-per-connection» в MySQL показатели скейлинга по количеству одновременных соединений лучше, чем у «process-per-connection» в PostgreSQL.

  • PostgreSQL во всём превосходит MySQL → Это не так.

Лично меня сильно обрадовало то, как PostgreSQL справляется с большими нагрузками. Да, в какой-то момент возникают проблемы, всё-таки модель даёт о себе знать. Но было сюрпризом увидеть машину, на которой штатно работают тысячи соединений Postgres.

  • Современные традиционные СУБД уже настолько хороши, что кэш-слой не нужен → Во многом, да, если рассматривать СУБД в целом, но есть важные нюансы.

Гибридные решения, key-value базы данных и подобное появились как раз для того, чтобы обрабатывать нагрузки в сотни тысяч и миллионы RPS. Но если говорить о традиционных СУБД, таких как MySQL и PostgreSQL, они уже могут обрабатывать большое количество RPS и достаточно хороши, если выполнено два условия: нагрузка строго Read-Only и запросы строго point select (по первичному ключу).

В реальной жизни всегда присутствует какой-то процент операций не Read-Only, и когда нагрузка смешанная, перформанс СУБД значительно падает. Если нагрузка почти полностью на чтение или близка к этому, то можно обойтись без кэш-слоя, но при большой доле записи — надо смотреть, и вполне вероятно, что нет. 

Если основная часть операций — это выборка по первичному ключу, СУБД справляются хорошо. Однако, в кэш можно «запихнуть» практически всё и хранить в key-value, а в базе данных не всё реализуется через point select, поэтому могут возникнуть ситуации, которые приведут к просадке производительности.

Можно ли всё это гарантировать на практике? Увы, нет, нельзя гарантировать, что не случится неожиданный поток апдейтов или неоптимизированный сканирующий запрос. Если вы готовы изолировать свою базу данных так, что туда точно не провалится ничего плохого, то флаг вам в руки. Но, честно говоря, я как СТО на это бы не решился. Даже если я всем командам запрещу делать те или иные вещи, наступит момент, когда какой-то запрос провалится, и мы получим очевидную проблему в продакшене.

Мы находимся в эпохе «миллионов RPS», что легко достигается при должной сноровке и сравнительно недорогом железе → почти.

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

Что можно было сделать лучше

Предвосхищая вопросы, расскажу, чего не хватало в тестах и что можно было сделать (и будет сделано в будущих исследованиях) лучше:

  • Смешанная нагрузка R/O vs R/W

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

  • Redis/Valkey cluster

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

  • PostgreSQL + Odyssey вместо bouncer

До тестирования Postgres вместе с bouncer руки не дошли, но это интересный вариант.

Из того, что я видел на практике, bouncer сильно ограничивает общий throughput, так как изначально не скейлится по ядрам. Есть Odyssey, который скейлится. Возможно, связка PostgreSQL + Odyssey будет скейлиться лучше, но всё равно миллионов RPS в таком сценарии вряд добьёшся. Если один PostgreSQL на 1000 одновременных соединений делал миллион RPS, то при добавлении посередине bouncer, throughput и latency сразу падал почти вдвое, хотя скейлится такая «связка», конечно, лучше.

  • PostgreSQL + compile optimisations

Компиляция MySQL с определёнными флагами привела к интересным результатам. Мы не делали этого для PostgreSQL, но PostgreSQL написан на C, а MySQL на C++. Это одна из причин, почему за последние несколько лет именно MySQL начал деградировать. Можно ли выжать что-то за счёт флагов из более простого C-кода Postgres, не знаю. Кажется, шансов немного, но протестировать стоит.

  • Другие кэш-сервисы и key-value СУБД: Tarantool, DragonFly, KeyDB и др.

Как минимум эти три продукта известны как быстрые key-value хранилища, которые активно используются и как кэш, и как база данных. В наше тестирование они не вошли, но их сравнение с Redis/Valkey/Memcached могло бы дать интересные графики и выводы.

Если вы дочитали до конца и считаете, что мы что-то забыли, пишите в комментариях. А мы продолжим исследование.

Результатами делился Алексей Рыбак — автор телеграм-канала про System Design и Highload, основатель DevHands.io — проекта по продвинутому обучению программистов и teamwork360.io — сервиса для автоматизации HR-процессов и оценки сотрудников.

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


  1. onyxmaster
    18.02.2025 10:25

    Зря опустили отдельное семейство кэшей -- кэш, который находится в адресном пространстве приложения. Нет сетевых задержек, можно исключить накладные расходы на [де]сериализацию (и, как следствие, нагрузку на систему распределения памяти), масштабируемость при правильной реализации близка к теоретически максимальной, возможно применение более эффективных алгоритмов приёмки и вытеснения чем LRU/LFU.

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


    1. fisher Автор
      18.02.2025 10:25

      Всё-таки это совсем в другой класс, и там конечно можно налопатить на порядок (или на порядки) больше RPS/thoughput.

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


      1. onyxmaster
        18.02.2025 10:25

        Ну ладно.


    1. KReal
      18.02.2025 10:25

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


  1. whoisking
    18.02.2025 10:25

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


    1. gmtd
      18.02.2025 10:25

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

      И как кэш решает эту "проблему"?


      1. whoisking
        18.02.2025 10:25

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


        1. gmtd
          18.02.2025 10:25

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


          1. whoisking
            18.02.2025 10:25

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


            1. redfox0
              18.02.2025 10:25

              materialized view или её ручная реализация с пересчётом по job'у или событию.


              1. whoisking
                18.02.2025 10:25

                или её ручная реализация с пересчётом по job'у или событию

                Так именно об этом я и писал в ветке


              1. ogregor
                18.02.2025 10:25

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


              1. ogregor
                18.02.2025 10:25

                Cdc подход. Распределенные дб и такое поддерживают. Так и обновлять materialized view


      1. ildarz
        18.02.2025 10:25

        Хранит готовый результат запроса, очевидно. СУБД обычно этого не делают и исполняют запрос каждый раз.


        1. gmtd
          18.02.2025 10:25

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


          1. ded_mazay
            18.02.2025 10:25

            Система попросит БД выполнить запрос и запишет результат в кэш


            1. gmtd
              18.02.2025 10:25

              Во-первых, вы используете кэш как хранилище, а не как кэш

              Во-вторых, ещё и оборачиваете работу с ним нетривиальной логикой

              Посмотрите в статье, под кэшем подразумевается просто прокладка между БД и клиентом для улучшения производительности.


              1. ded_mazay
                18.02.2025 10:25

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

                Это самая тривиальная логика работы кэша: не попали - идем за данными в более медленное хранилище.


              1. ildarz
                18.02.2025 10:25

                Я не очень понимаю, почему вы считаете нетривиальной базовую логику работы с кэшами (не только для БД, но и вообще любыми). Не готов судить, что "подразумевают" авторы статьи, но вот что думают по этому поводу в AWS, например - Relational Database Caching Techniques - Database Caching Strategies Using Redis


    1. kirya522
      18.02.2025 10:25

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

      Принимал участие в инцидентах, где без кеша не работало бы вообще ничего и достаточно долго.

      По итогам проводили серию chaos тестирований, чтобы добиться работы основных сценариев при недоступности хранилища на срок до 4 часов.


  1. SabMakc
    18.02.2025 10:25

    Удивлен, что нет KeyDB, учитывая что протокол полностью совместим с Redis.
    Ну и read-only нагрузка - достаточно специфичный вариант, не сказать что это типичная нагрузка.
    Да и в целом, для read-only - горизонтальное масштабирование зарешает (например, запуск нескольких независимых инстансов redis с одинаковыми данными). Опционально можно сделать шардинг инстансов по ключам, чтобы данные не дублировать.


  1. fred_msk
    18.02.2025 10:25

    Леш, редис не скалируется на запись (ибо она однопоточная), и отсюда на R/W нагрузке совсем по другому себя будет вести. Редис в большинстве кейсов с приличным W будет проигрывать упомянутым СУБД с хорошим конкаренси (особенно когда они не в serializable режиме)


    1. fisher Автор
      18.02.2025 10:25

      Ну в целом да, но при 1.000.000 RPS сколько обычно операций на запись - больше 10%? упремся ли мы в одно ядро? Довольно важно, ~100К writes-PS main thread потянет на нормальном железе, там больше будет деградации при синках на диск (будет интересно посмотреть с aof на nvme например). Ну и кластер, write-нагрузку без кластера не смасштабировать.


      1. whoisking
        18.02.2025 10:25

        Ну в целом да, но при 1.000.000 RPS сколько обычно операций на запись - больше 10%

        Сколько работаю, ни разу ещё не было "обычно". Это какое-то среднее по больнице, которое ничего не даёт. У каждой задачи своя специфика.


        1. fisher Автор
          18.02.2025 10:25

          Это общие слова, сори, и кажется, мы не спорим, либо я не понимаю, о чём. О чём?

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


      1. vanxant
        18.02.2025 10:25

        Да хотя бы 1% запросов на запись. Или 3%. Просто 0% это совсем сферический конь в вакууме, очень трудно придумать реальный юз кейс кроме раздачи статики.


        1. fisher Автор
          18.02.2025 10:25

          Предельное число запросов, что на чтение что на запись порядка 100К RPS на ядро на этих xeon gold при датасете в 10 млн 256-байтных ключей, и все эти параметры, кстати, важны. Если точно - около 160K RPS. Значит, если у вас valkey и 1M RPS, то вы "почуствуете" родовую травму редиса (main thread, не "однотредовость" - строго говоря, это неверно) только если R/W ratio > 10 (грубо). 1% или 3% - скорее всего, не почуствуете. Лучше, конечно, было бы это явно промерить - да, я согласен, про это написано в специальном разделе, в ближайшее время мы это проиллюстрируем.


          1. vanxant
            18.02.2025 10:25

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


  1. hogstaberg
    18.02.2025 10:25

    Tarantool, буквально созданный для того, чтобы на нем лепить умные кэши: "Ну да, ну да. Пошел я нафиг."


  1. rendik7Sur
    18.02.2025 10:25

    Полезная статья, тоже вопросом кэша часто интересовался .


  1. iroln
    18.02.2025 10:25

    А почему не рассмотрели Dragonfly как современную альтернативу "немасштабируемому" Redis и Memcached?

    Dragonfly is an in-memory data store built for modern application workloads.

    Fully compatible with Redis and Memcached APIs, Dragonfly requires no code changes to adopt. Compared to legacy in-memory datastores, Dragonfly delivers 25X more throughput, higher cache hit rates with lower tail latency, and can run on up to 80% less resources for the same sized workload.