Привет, Хабр. Меня зовут Любовь Вайгель. Я системный аналитик в СберЗдоровье — MedTech-компании №1 в России.
Во многих сценариях, сталкиваясь со снижением скорости ответа системы, компании приходят к необходимости внедрения кэша и довольно быстро реализуют кэширование на уровне технологий. Но правда в том, что кэширование, которое часто воспринимают как простой тактический приём для ускорения работы приложения, на практике может сильно изменить свойства системы: согласованность данных, поведение при сбоях, требования к актуальности и доступности информации. Поэтому для системного аналитика важно четко понимать, что мы кэшируем, зачем, на каких условиях и как это будет отражено в требованиях.
В этой статье я разберу пять неочевидных истин о кэшировании, которые часто остаются «за кадром», и покажу, как они влияют на работу системного аналитика.
1. Кэш — это распределённая система
Основная ошибка — воспринимать кэш как изолированный вспомогательный компонент. Как только в системе появляется кэш, у вас становится как минимум два источника данных:
основной источник истины — обычно база данных;
кэш.
То есть система начинает вести себя как распределённая. В результате появляется необходимость решать вопросы согласованности данных, порядка операций и распространения изменений. Именно поэтому простая на первый взгляд задача, такая как инвалидация кэша, быстро превращается в нетривиальную.
Например, вопрос «как кэш узнаёт, что данные изменились?» — это не техническая мелочь, а архитектурное решение, ведь возможны разные варианты, в том числе:
инвалидация по событию;
обновление по расписанию;
инвалидация по TTL;
комбинация подходов.
Для системного аналитика это означает простую вещь: в требованиях должна быть зафиксирована стратегия согласования данных между источником истины и кэшем. Если этого нет, поведение системы останется неуправляемым, а проблемы всплывут уже в продакшене.
Исходя из этого, в требованиях важно зафиксировать:
какие данные считаются источником истины;
когда и по какому событию кэш обновляется или инвалидируется;
что происходит, если кэш и основной источник временно расходятся.
2. Кэш ускоряет чтение, но усложняет согласованность данных
Кэширование всегда означает компромисс: мы ускоряем систему, но платим за это потенциальной неактуальностью данных и риском расхождения версий.
Причем расхождение может привести к разным последствиям, например:
пользователь видит устаревшие данные;
разные пользователи получают разные версии одной и той же информации;
система принимает решение на основе данных, которые уже изменились в источнике истины.
Важно отметить, что подобное расхождение не всегда критично — допустимость использования устаревших данных напрямую зависит от бизнес-контекста:
для каталога товаров устаревшее описание или рейтинг на несколько минут обычно терпимы;
для цены, остатка на складе, финансового баланса или медицинских данных требования к актуальности должны быть намного строже.
Поэтому задача системного аналитика — не просто проработать кэширование, а перевести этот компромисс согласованности в измеримые требования:
насколько свежими должны быть данные;
какая задержка обновления допустима;
в каких сценариях устаревшие данные недопустимы;
что пользователь или система должны увидеть, если данные могут быть неактуальны.
На практике это чаще всего выражается через требования к TTL, допустимому возрасту данных и сценариям, где кэш использовать нельзя.
3. Отказ кэша может обрушить всю систему
Существует распространённый миф: кэш — это необязательный компонент, и если он откажет, система просто станет медленнее.
В реальности в высоконагруженных системах отказ кэша может привести к полному падению приложения. Подтверждением этому является классический сценарий — thundering herd problem, при котором кэш становится недоступным или очищается и, как следствие:
множество параллельных запросов одновременно не находят данные в кэше;
все они идут напрямую в основной источник данных;
база данных получает лавинообразную нагрузку и тоже выходит из строя.
С технической стороны эту проблему часто решают с помощью паттерна Singleflight или аналогичных механизмов дедупликации запросов. Аналитику не обязательно выбирать конкретный механизм реализации, но важно зафиксировать требуемое поведение системы. Например:
одновременные запросы к одним и тем же данным не должны мультиплицировать нагрузку на источник истины;
при недоступности кэша система должна деградировать предсказуемо, а не создавать каскадный отказ;
критичные пользовательские сценарии должны иметь описанное поведение при отказе кэша.
Кроме того, требования к надёжности должны явно учитывать сценарий отказа кэша:
как система деградирует;
что происходит с пользовательскими запросами;
какие компоненты считаются критичными;
какие метрики и алерты нужны, чтобы заметить проблему до массового инцидента.
4. Иногда устаревшие данные лучше, чем их отсутствие
Это контринтуитивная, но важная идея: в ряде сценариев доступность важнее абсолютной актуальности.
Хороший пример — пользовательские ленты, списки, каталоги. Если сервис профилей временно недоступен, пустые блоки вместо имён и аватаров создают ощущение «сломанной системы», даже если формально данные просто не загрузились. Поэтому в таких случаях лучше показать немного устаревшие данные, чем не показать ничего.
Для этого используют резервное использование устаревшего кэша в пределах допустимого окна:
cacheTtl — время, в течение которого данные считаются актуальными;
fallbackTtl — время, в течение которого устаревшие данные допустимы как резервный вариант.
Если основной источник недоступен, система продолжает работать, отдавая данные из кэша, пока их возраст не превысил fallbackTtl.
Для аналитика это напрямую связано с требованиями к доступности и отказоустойчивости: где мы готовы пожертвовать свежестью данных ради пользовательского опыта, а где — нет.
Исходя из этого, в требованиях важно зафиксировать:
можно ли показывать устаревшие данные;
какой максимальный возраст таких данных допустим;
нужно ли сообщать пользователю, что данные могут быть неактуальны;
для каких сценариев fallback запрещён.
5. Кэшировать нужно не самые «дорогие», а подходящие данные
Часто можно услышать: «давайте кэшировать самые тяжёлые запросы». Стоимость получения данных действительно важна, но это не единственный критерий.
Хороший кандидат для кэширования обычно:
часто читается;
редко изменяется;
дорог в получении, например из-за сложных запросов или внешних API;
невелик по объёму;
имеет понятные правила актуализации.
Кэширование редко используемых или часто изменяющихся данных может не только не дать выигрыша, но и создать дополнительную нагрузку из-за постоянной инвалидации.
Поэтому в требованиях аналитик должен фиксировать не абстрактное «реализовать кэширование», а конкретный перечень данных или типов данных, которые подлежат кэшированию, и обоснование этого выбора.
Чек-лист требований к кэшированию для системного аналитика
Таким образом, перед тем как согласовывать кэширование, стоит ответить на ряд вопросов:
Какие данные кэшируем?
Где находится источник истины?
Какой допустимый возраст данных?
Что инвалидирует кэш?
Что происходит при недоступности кэша?
Можно ли отдавать устаревшие данные?
Как система защищает источник истины от лавинообразной нагрузки?
Какие метрики покажут, что кэш работает неправильно?
При этом ответы на эти и другие вопросы можно упаковать в полный и информативный набор требований. Например:
Требование к TTL. Система должна кэшировать данные профиля пользователя на 15 минут. По истечении TTL при первом запросе данные должны обновляться из основного хранилища.
Требование к инвалидации. При изменении пользователем аватара соответствующая запись в кэше должна быть немедленно инвалидирована.
Требование к отказоустойчивости. В случае недоступности основной базы данных система должна предоставлять данные профилей из кэша, если их возраст не превышает 60 минут.
Функциональное требование. В кэш должны помещаться следующие данные: профиль пользователя, список друзей, каталог товаров.
Требование к защите источника истины. При одновременных запросах к одним и тем же отсутствующим в кэше данным система должна выполнять не более одного запроса к основному хранилищу на ключ кэша за заданный интервал.
Такие формулировки позволяют избежать двусмысленностей и заранее определить поведение системы в критических сценариях.
Заключение
Кэширование — это мощный архитектурный инструмент. Оно почти никогда не ломает систему сразу: чаще всего это происходит позже — когда появляются расхождения в данных, каскадные отказы и неочевидные баги.
Именно поэтому без системного аналитика, который зафикисирует условия, ограничения и компромиссы, внедрить кэширование без ущерба всей системе в перспективе практически невозможно. При этом, для удобства работы с кэшем и учета всех ключевых аспектов, системные аналитики могут опираться на чек-лист, доступный по ссылке.
Если посмотреть на ваши текущие требования, какие из них стоило бы пересмотреть с учётом этих неочевидных истин?
Mr_Makadamia
Салют!
Совсем недавно начал погружаться в этот дивный мир, точнее технологичный мир, или еще точнее самих технологий, внутри этого, читай, форума. Поэтому, сразу, требую, именно так! Снисхождения за глупые вопросы.
То есть живой человек внутри огромной механичнской бюрократической машины, пишет требования, согласует их по отделам, потом создаёт задачу, исполнителем ставит тимлида отдела разработчиков, в копию ставит своего начальника, и ещё множество лиц, совершенно ни как не связанных с решением этой странной задачи. Далее в отделе разработки, задачу на себя берет Синьёр, в ручную добавляет одним глаголом Одно слово, после чего ставит задачу на проверку, идёт процесс некоей валидации между участниками таска, после чего Кэш выходит в релиз... Ну тут ни какого здоровья не хватит, в погоне за лёгким кэшем...
Как информация остается свеженькой, пышненькой, актуальной, в такой мясной бюрократической мясорубке? То есть механизма, понимания изначального, или какого-то счётчика - автоматического переключателя нет? Тут null сарказма, реально не понимаю как это всё работает...