Caching
Что такое кэширование?
Кэширование — это технология хранения данных.
Она позволяет снизить нагрузку с основного источника данных (зачастую - базы данных) и ускорить время доступа к данным.
В кэш кладут данных, к которым часто обращаются и, которые долго вычислять “на лету”.
Кэши бывают в памяти, на диске и в web (браузер). Они используют различные политики хранения данных (к примеру, LRU или Last Recently Used).
Помимо того, что кэш улучшает производительность системы, он также привносит свои трудности: обслуживание консистентности данных и инвалидация.
Инструменты, используемые в качестве кэша.
Hazelcast — распределенный кэш в памяти, используется для ускорения времени отклика на запросы и вычислений в памяти, работает как часть основного бэкенд приложения.
Ehcache — кэш в памяти одного бэкенд приложения, используется для ускорения времени отклика на запросы.
Redis — распределенный удаленный кэш в памяти с возможностью бэкапов на диск, также используется для ускорения времени отлика на запросы или в качестве NoSQL базы данных, так как предоставляет широкий набор структур данных.
CDN (Content Delivery Network) — такие сервисы как Cloudflare, Akamai или AWS CloudFront распалагают кэши близкие к географическому расположению клиентов, что уменьшает время загрузки сайтов или контента (картинки, видео, шрифты и тд).
Browser Caching — современные браузеры используют свои собственные технологии кэширования для хранения в памяти или на диске ресурсов с веб страниц (html, css, картинки, иконки и тд), чтобы ускорить повторные загрузки этих страниц.
Varnish — обратный HTTP прокси сервер с возможностью кэширования ответов сервера.
Nginx — веб-сервер, обычно используется как фронтенд сервер, лоад балансер или обратный прокси, но также имеет функции по кэшированию веб ресурсов (html, css, картинки, иконки и тд) из ответов от сервера.
Что такое ключ кэширования и как он используется.
Ключ кэширования — уникальный идентификатор, по которому можно сохранить и получить данные в кэше.
Обычно ассоциируется с данными, мета информацией об истечении срока жизни и проверок консистентности между операциями кэша.
Что такое промах по кэшу?
Промахи по кэшу происходят в случаях, когда запрашиваемые данные по ключу не находятся в нем. Тогда необходимые данные запрашиваются из медленного источника данных (база данных, диск, удаленный сервер).
Они могут сильно повлиять на общую производительность системы, если запросы из исходного истоничка данных более медленные, а сами данные очень часто запрашиваются.
Высокий процент промахов может говорить о том, что была выбранна неоптимальная стратегия кэширования.
Обратная сторона - попадание по кэшу, говорит о нахождении данных в кэши.
Инвалидация кэша.
Инвалидация кэша — это набор различных способов для удаления старых данных из кэша.
Time-based — данные удаляют после истечения предопределенного количества времени (TTL).
Event-based — данные удаляются при получении определенного события (к примеру, через броке сообщений, rabbitmq/kafka).
Command-based — данные удаляются по команде, обычно вместе с выполнение других комманд (к примеру, вместе с удалением файла удаляется и кэш файла).
Вытеснение записей в кэше.
Количество данных в кэше всегда ограничено, поэтому существуют различные стратегии по вытеснению (удалению) данных.
Least Recently Used (LRU) — при записи удаляются наименее молодые данные. Алгоритм помечает каждый элемент порядковым номером.
Most Recently Used (MRU) — при записи удаляются часто используемые данные.
Least Frequently Used (LFU) — при записи удаляются наименее часто используемые данные. Алгоритм подсчитывает сколько раз был прочитан каждый из элементов.
Most Frequently Used (MFU) — при записи удаляются наиболее часто используемые данные.
First-In-First-Out (FIFO) — при записи из кэша удаляются данные в обратной последовательности их добавления.
Random Replacement (RR) — при записи удаляется случайный элемент кэша.
Стратегии записи в кэш.
Write-Through — данные записываются в кэш после того, как были записаны в исходный источник данных.
Write-Ahead — данные сначала записываются в кэш, а потом в исходный источник данных.
Read-Through — данные записываются в кэш после того, как были вычитаны из исходного источника данных, в случае, если был промах по кэшу.
Влияние размера кэша на производительность.
В зависимости от размера базы данных и требований бизнеса подбирается размер кэша.
Его размер влияет на количество промахов по кэшу и вытеснениям. При большом количестве промахов, возможно, была выбрана неправильная стратегия вытеснения или размера кэша не хватает для всех запрашиваемых данных.
Сценарии, в которых кэш должен использоваться.
- В случае, если количество чтений многократно превышает количество записей. Основной источник данных может не выдерживать большой нагрузки.
- В случае, когда основной источник данных медленный. В нем может быть не много данных или это данные, которые необходимо вычислить, кэш ускорит время доступа.
- В случае, когда необходимо горизонтально масштабировать бэкенд сервис. При увеличении количества бэкенд сервисов потребуется больше ресурсов и в основном источнике данных для поддержания соединений. Масштабировать кэш проще и дешевле.
- В случае, ожидаемых пиковых нагрузок. Такие нагрузки могут иметь сильное воздействие на основной источник данных, к чему она может быть не готова.
Как синхронизировать кэши в распределенных системах?
- Если это распределенный кэш (redis, memcache, hazelcast), то вопрос синхронизации возьмет на себя сама система кэширования.
- Если это базовый простой кэш (ehcache), то можно синхронизировать кэши через события по брокеру сообщений или базу данных (mysql, postgres), с которой работают все остальные инстансы бэкенд сервисов.