Распределенное кэширование (создание Real-World облачных приложений с помощью Azure)

Рик Андерсон(Rick Anderson),Том Дайкстра (Tom Dykstra)

Скачать проект Fix It или скачать электронную книгу

Электронная книга "Создание реальных облачных приложений с помощью Azure " основана на презентации, разработанной Скоттом Гатри. В нем объясняется 13 шаблонов и методик, которые помогут вам успешно разрабатывать веб-приложения для облака. Сведения об электронной книге см. в первой главе.

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

Что такое распределенное кэширование

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

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

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

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

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

Когда следует использовать распределенное кэширование

Кэширование лучше всего работает для рабочих нагрузок приложений, которые выполняют больший объем чтения, чем запись данных, и когда модель данных поддерживает организацию "ключ—значение", используемую для хранения и извлечения данных в кэше. Это также более полезно, когда пользователи приложения совместно используют много общих данных; Например, кэш не будет предоставлять столько преимуществ, если каждый пользователь обычно получает данные, уникальные для этого пользователя. Примером, в котором кэширование может оказаться очень полезным, является каталог продуктов, так как данные меняются редко, и все клиенты просматривают одни и те же данные.

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

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

  • По запросу / кэш в сторону

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

  • Отправка фоновых данных

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

  • Автоматическое выключение

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

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

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

Пример кода в стороне от кэша для приложения Fix It

В следующем примере кода мы проверка кэш сначала при получении задачи Исправить. Если задача найдена в кэше, мы возвращаем ее; Если он не найден, мы получаем его из базы данных и сохраняем в кэше. Будут выделены изменения, внесенные для добавления кэширования в FindTaskByIdAsync метод.

public async Task<FixItTask> FindTaskByIdAsync(int id)
 {
    FixItTask fixItTask = null;
    Stopwatch timespan = Stopwatch.StartNew();
    string hitMiss = "Hit";

    try
    {
       fixItTask = (FixItTask)cache.Get(id.ToString());
       if (fixItTask == null)
       {
          fixItTask = await db.FixItTasks.FindAsync(id);
          cache.Put(id.ToString(), fixItTask);
          hitMiss = "Miss";
       }

       timespan.Stop();
       log.TraceApi("SQL Database", "FixItTaskRepository.FindTaskByIdAsync", timespan.Elapsed, 
                    "cache {0}, id={1}", hitMiss, id);
    }
    catch (Exception e)
    {
       log.Error(e, "Error in FixItTaskRepository.FindTaskByIdAsynx(id={0})", id);
    }

    return fixItTask;
 }

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

public async Task UpdateAsync(FixItTask taskToSave)
{
   Stopwatch timespan = Stopwatch.StartNew();

   try
   {
      cache.Remove(taskToSave.FixItTaskId.ToString());
      db.Entry(taskToSave).State = EntityState.Modified;
      await db.SaveChangesAsync();

      timespan.Stop();
      log.TraceApi("SQL Database", "FixItTaskRepository.UpdateAsync", timespan.Elapsed, "taskToSave={0}", taskToSave);
   }
   catch (Exception e)
   {
      log.Error(e, "Error in FixItTaskRepository.UpdateAsync(taskToSave={0})", taskToSave);
   }
}

Это примеры для демонстрации простого кода кэширования; кэширование не реализовано в загружаемом проекте Fix It.

Службы кэширования Azure

Azure предлагает следующие службы кэширования: Кэш Redis для Azure и Управляемый кэш Azure. Кэш Redis для Azure основан на популярном кэше Redis открытый код и является первым выбором для большинства сценариев кэширования.

ASP.NET состояния сеанса с помощью поставщика кэша

Как упоминалось в разделе Рекомендации по веб-разработке, рекомендуется избегать использования состояния сеанса. Если приложению требуется состояние сеанса, рекомендуется избегать использования поставщика по умолчанию в памяти, так как это не позволяет масштабировать (несколько экземпляров веб-сервера). Поставщик состояний сеансов ASP.NET SQL Server позволяет сайту, работающему на нескольких веб-серверах, использовать состояние сеанса, но это влечет за собой высокую задержку по сравнению с поставщиком в памяти. Лучшее решение, если необходимо использовать состояние сеанса, — использовать поставщик кэша, например поставщик состояний сеансов для кэша Azure.

Итоги

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

Ресурсы

Дополнительные сведения о кэшировании см. в следующих ресурсах.

Документация

Видео

  • FailSafe: создание масштабируемых, устойчивых Облачные службы. Серия из девяти частей Ульрих Хоманн, Марк Меркури и Марк Симмс. Предоставляет 400-уровневое представление о том, как проектировать облачные приложения. В этой серии основное внимание уделяется теории и причинам, почему; Дополнительные инструкции см. в серии Building Big Марк Симмс. См. обсуждение кэширования в эпизоде 3, начиная с 1:24:14.
  • Создание больших объемов. Уроки, извлеченные от клиентов Azure. Часть I. Саймон Дэвис обсуждает распределенное кэширование, начиная с 46:00. Похож на серию Failsafe, но в нем подробно описаны дополнительные инструкции. Презентация была представлена 31 октября 2012 года, поэтому она не охватывает службу кэширования веб-приложения в Служба приложений Azure, которая была представлена в 2013 году.

Пример кода