Все о кеш-памяти

К сожалению, эта статья не имеет ничего общего с Джонни. Все еще читаете? Тогда давай поговорим о технике.

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

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

Если это так просто, зачем об этом говорить? Потому что даже самое простое в жизни требует усилий, чтобы овладеть им. Несмотря на то, что концепция проста, есть некоторые моменты, которые следует учитывать при ее реализации.

Что

Есть много вещей, которые можно кэшировать. Когда мы говорим о кеше, мы обычно имеем в виду HTML-страницы, созданные веб-приложением, или ресурсы на странице. Однако часто бывает интереснее кэшировать фрагменты вычислений. Это кеши функций / мемоизации. Кеши могут существовать на нескольких уровнях: например, от полных результатов в браузерах до кешей CPU, GPU или Disk.

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

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

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

Где

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

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

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

Это подводит нас к теме согласованного хеширования. В основном это означает, что ваш ключ всегда будет приводить вас к одному и тому же серверу в кластере. Допустим, у вас есть три сервера с памятью. Все они приблизительно содержат 1/3 вашего кеша. Когда вы просматриваете свой кеш, вы всегда хотите, чтобы вас перенаправили на тот же компьютер, который должен или не должен содержать кеш, и не оставлять его на случай совпадения.

Некоторые из ваших алгоритмов могут генерировать много, много, много возможных ключей кеширования. Хранить их все не всегда полезно. По этой причине рекомендуется ограничить объем пространства, которое вы предоставляете кешу этого алгоритма. Когда вы ограничиваете пространство (для каждого элемента кеша, а также для каждого объекта кеша), ваша система хранения должна будет выселить кеши. Выселение (освобождение памяти для хранения новых вещей) сопряжено с риском. Например, вы обычно не хотите удалять самый запрашиваемый кеш. Вам нужно будет выбрать алгоритм / стратегию кеширования, которые лучше всего подходят для управления вашим пространством, например, выселить L восток R в последнее время U sed. (Применяя стратегию кэширования LRU) или наименее часто используемую (LFU).

Часто Memcached (или производное от него, например, Couchbase) используется для выполнения всего вышеперечисленного. Некоторые предпочитают Redis с конфигурациями выселения. Я предпочитаю чистый Memcached, так как мне нравится его атомарность. Он предназначен для работы как кластер кэширования LRU, и ничего больше.

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

  • публичный или частный кешируемый
  • как долго это можно кешировать
  • какие заголовки определяют ключ кеширования удаленно (варьируются)

Когда

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

Когда дело доходит до файлов, рекомендуется применить очистку кеша, просто переименовав файл при повторном создании ресурса. Это позволяет клиенту кэшировать файл бесконечно (поскольку после изменения будет новый файл; это особенно хорошо работает, когда у вас есть CDN).

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

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

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

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

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

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

Вывод

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