Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Этот шаблон загружает данные по запросу в кэш из хранилища данных. Используйте этот шаблон для повышения производительности и обеспечения согласованности между данными в кэше и данных в базовом хранилище данных.
Контекст и проблема
Приложения используют кэш для повышения производительности для многократного доступа к информации в хранилище данных. Но кэшированные данные не всегда могут оставаться согласованными с хранилищем данных. Приложения должны реализовать стратегию, которая сохраняет данные в кэше максимально актуальными. Стратегия также должна обнаруживать, когда кэшированные данные становятся устаревшими и обрабатывать их соответствующим образом.
Решение
Многие коммерческие системы кэширования обеспечивают операции чтения и записи или записи. В этих системах приложение получает данные, ссылаясь на кэш. Если данные не хранятся в кэше, приложение извлекает его из хранилища данных и добавляет его в кэш. Система автоматически записывает все изменения, внесенные в кэшированные данные обратно в хранилище данных.
Для кэшей, которые не предоставляют эту функциональность, приложения, использующие кэш, должны поддерживать данные.
Приложение может имитировать функции сквозного кэширования, реализуя шаблон Cache-Aside. Эта стратегия загружает данные в кэш по запросу. На следующей схеме используется шаблон Cache-Aside для хранения данных в кэше.
Приложение определяет, находится ли элемент в кэше, пытаясь считывать из кэша.
Если элемент отсутствует в кэше, также известный как пропущенный кэш, приложение извлекает элемент из хранилища данных.
Приложение добавляет элемент в кэш, а затем возвращает его вызывающему объекту.
Если приложение обновляет информацию, оно может следовать стратегии write-through, изменяя хранилище данных и инвалидируя соответствующий элемент в кэше.
Когда элемент понадобится еще раз, шаблон Cache-Aside извлекает обновленные данные из хранилища данных и добавляет его в кэш.
Проблемы и рекомендации
Учитывайте следующие моменты при принятии решения о том, как реализовать этот шаблон.
Время существования кэшированных данных: Многие кэши используют политику истечения срока действия для отмены данных и удаления их из кэша, если доступ к нему не выполняется в течение заданного периода. Чтобы обеспечить эффективное использование кэша, убедитесь, что политика истечения срока действия соответствует шаблону доступа для приложений, использующих данные. Не делайте срок действия слишком коротким, так как преждевременное истечение срока действия может привести к постоянному получению данных из хранилища данных и добавлению его в кэш. Аналогичным образом не делайте срок действия так долго, чтобы кэшированные данные становятся устаревшими. Кэширование лучше всего подходит для относительно статических данных или данных, которые приложения часто считывают.
Вытеснение данных: Большинство кэшей имеют ограниченный размер по сравнению с хранилищем данных, в котором возникают данные. Если кэш превышает его размер, он вытесняет данные. Большинство кэшей следуют политике наименее недавно используемого элемента для вытеснения, но некоторые позволяют настраивать её.
Конфигурации: Поведение кэша можно настроить глобально или на каждый кэшированный элемент. Одна глобальная политика вытеснения может не соответствовать всем элементам. Если элемент является дорогостоящим для извлечения, настройте элемент кэша по отдельности. В этой ситуации имеет смысл сохранить элемент в кэше, даже если он получает доступ реже, чем дешевые элементы.
Подготовка кэша: Многие решения предварительно заполняют кэш данными, которые, скорее всего, требуется приложению в процессе запуска. Шаблон Cache-Aside остается полезным при истечении срока действия некоторых данных или их удаления из кеша.
Согласованности: Шаблон Cache-Aside не гарантирует согласованность между хранилищем данных и кэшем. Например, внешний процесс может изменять элемент в хранилище данных в любое время. Это изменение не отображается в кэше до тех пор, пока элемент снова не загружается. В системе, которая реплицирует данные в хранилищах данных, частое синхронизация может затруднить согласованность.
Локальное кэширование: Кэш может быть локальным для экземпляра приложения и храниться в памяти. Кэш в стороне хорошо работает в этой среде, если приложение неоднократно обращается к тем же данным. Но локальный кэш является частным, поэтому разные экземпляры приложений могут иметь копию одних и тех же кэшированных данных. Эти данные могут быстро стать несогласованными между кэшами, поэтому может потребоваться установить истечение срока действия данных в приватном кэше и обновлять их более часто. В этих сценариях рекомендуется использовать общий или распределенный механизм кэширования.
Семантическое кэширование: Некоторые задачи могут выигрывать от получения кэша на основе семантического значения, а не точных ключей. Такой подход сокращает количество запросов и маркеров, отправленных в языковые модели. Только используйте семантический кэширование, если данные поддерживают семантику эквивалентности, не рискуют возвращать несвязанные ответы и не содержат частные и конфиденциальные данные. Например, "Какова моя годовая чистая зарплата?" по смыслу похоже на "Какова моя годовая чистая оплата?" Но если эти вопросы задают разные пользователи, ответы должны отличаться. Вы также не должны включать эти конфиденциальные данные в кэш.
Когда следует использовать этот шаблон
Используйте этот шаблон в следующих случаях:
В кэше не предоставляются собственные операции сквозного чтения и записи.
Запрос ресурса невозможно спрогнозировать. Этот шаблон позволяет приложениям загружать данные по запросу. Не предполагается заранее, какие данные требуются приложению.
Этот шаблон может быть не подходит, если:
Данные конфиденциальные или связанные с безопасностью. Хранение данных в кэше может быть неуместным, особенно если несколько приложений или пользователей совместно используют кэш. Всегда извлекайте данные такого типа из первичного источника.
Кэшированный набор данных является статическим. Если данные помещаются в доступное пространство кэша, инициализируйте кэш с данными при запуске и примените политику, которая предотвращает удаление данных.
Большинство запросов не имеют кэш-хита. В этой ситуации затраты на проверку кэша и загрузку данных в нее могут перевесить преимущества кэширования.
Сведения о состоянии сеанса кэшируются в веб-приложении, размещенном в веб-ферме. В этой среде избегайте внедрения зависимостей на основе сопоставления между клиентом и сервером.
Проектирование рабочей нагрузки
Оцените, как использовать шаблон Cache-Aside в проектировании рабочей нагрузки для достижения целей и принципов, описанных в основах Azure Well-Architected Framework. В следующей таблице приведены рекомендации по использованию этого шаблона для целей каждого компонента.
| Столп | Как этот шаблон поддерживает цели основных компонентов |
|---|---|
| Решения по проектированию надежности помогают рабочей нагрузке стать устойчивой к сбоям и гарантировать, что она восстанавливается до полнофункционального состояния после сбоя. | Кэширование реплицирует данные. С ограниченными возможностями он может сохранить доступность часто доступных данных, если исходное хранилище данных становится временно недоступным. Если кэш не работает, рабочая нагрузка может вернуться в исходное хранилище данных. - RE:05 ИЗБЫТОЧНОСТЬ |
| Эффективность производительности помогает рабочей нагрузке эффективно соответствовать требованиям путем оптимизации масштабирования, данных и кода. | Кэширование повышает производительность для данных с большим объемом чтения, которые редко изменяются и допускают некоторое устаревание. - PE:08 производительность данных - Оптимизация непрерывной производительности PE:12 |
Если этот шаблон вводит компромиссы внутри столпа, рассмотрите их против целей других столпов.
Пример
Рассмотрите возможность использования Azure Управляемый Redis для создания распределенного кэша, который может совместно использовать несколько экземпляров приложений.
В следующем примере используется клиент StackExchange.Redis , который является клиентской библиотекой Redis, написанной для .NET. Чтобы подключиться к экземпляру Управляемого Redis в Azure, вызовите статический ConnectionMultiplexer.Connect метод и передайте строку подключения. Этот метод возвращает ConnectionMultiplexer, представляющий подключение.
Один из способов совместного использования экземпляра ConnectionMultiplexer в приложении — иметь статическое свойство, которое возвращает подключенный экземпляр, как показано в следующем примере. Этот подход помогает потокобезопасно инициализировать только отдельный подключенный экземпляр.
private static ConnectionMultiplexer Connection;
// Redis connection string information
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
string cacheConnection = ConfigurationManager.AppSettings["CacheConnection"].ToString();
return ConnectionMultiplexer.Connect(cacheConnection);
});
public static ConnectionMultiplexer Connection => lazyConnection.Value;
В следующем примере показан метод GetMyEntityAsync, реализующий шаблон Cache-Aside. Этот метод извлекает объект из кэша с помощью метода чтения.
Метод определяет объект с помощью целочисленного идентификатора в качестве ключа. Он пытается получить элемент из кэша с помощью этого ключа. Если кэш содержит соответствующий элемент, он возвращает элемент. Если кэш не содержит совпадения, GetMyEntityAsync метод извлекает объект из хранилища данных, добавляет его в кэш, а затем возвращает его. В этом примере пропущен код, который отвечает за считывание данных из хранилища данных, потому что эта логика зависит от хранилища данных. Кэшированный элемент настроен на истечение срока действия, чтобы предотвратить его устареть, если другая служба или процесс его обновляет.
// Set five minute expiration as a default
private const double DefaultExpirationTimeInMinutes = 5.0;
public async Task<MyEntity> GetMyEntityAsync(int id)
{
// Define a unique key for this method and its parameters.
var key = $"MyEntity:{id}";
var cache = Connection.GetDatabase();
// Try to get the entity from the cache.
var json = await cache.StringGetAsync(key).ConfigureAwait(false);
var value = string.IsNullOrWhiteSpace(json)
? default(MyEntity)
: JsonConvert.DeserializeObject<MyEntity>(json);
if (value == null) // Cache miss
{
// If there's a cache miss, get the entity from the original store and cache it.
// Code has been omitted because it is data store dependent.
value = ...;
// Avoid caching a null value.
if (value != null)
{
// Put the item in the cache with a custom expiration time that
// depends on how critical it is to have stale data.
await cache.StringSetAsync(key, JsonConvert.SerializeObject(value)).ConfigureAwait(false);
await cache.KeyExpireAsync(key, TimeSpan.FromMinutes(DefaultExpirationTimeInMinutes)).ConfigureAwait(false);
}
}
return value;
}
Примечание.
В примерах используется Azure Managed Redis для доступа к хранилищу и получения сведений из кэша. Для получения дополнительной информации см. Создание экземпляра Azure Managed Redis и Использование Azure Managed Redis в .NET Core.
В следующем методе UpdateEntityAsync показано, как аннулировать объект в кэше, когда приложение изменяет значение. Этот код обновляет хранилище исходных данных, а затем удаляет кэшированный элемент из кэша.
public async Task UpdateEntityAsync(MyEntity entity)
{
// Update the object in the original data store.
await this.store.UpdateEntityAsync(entity).ConfigureAwait(false);
// Invalidate the current cache object.
var cache = Connection.GetDatabase();
var id = entity.Id;
var key = $"MyEntity:{id}"; // The key for the cached object.
await cache.KeyDeleteAsync(key).ConfigureAwait(false); // Delete this key from the cache.
}
Примечание.
Порядок шагов очень важен. Обновите хранилище данных, прежде чем удалять элемент из кэша. Если сначала удалить кэшированный элемент, то есть небольшое окно времени, когда клиент может получить элемент перед обновлением хранилища данных. В этой ситуации запрос приводит к промаху кэша, поскольку элемента нет в кэше. Пропуск кэша приводит к тому, что приложение извлекает устаревший элемент из хранилища данных и добавляет его обратно в кэш. Эта последовательность приводит к устаревшим данным в кэше.
Дальнейшие действия
Праймер согласованности данных: этот праймер описывает проблемы с согласованность между распределенными данными. В нем также приводится сводка о том, как приложение может реализовать в конечном итоге согласованность для поддержания доступности данных. Облачные приложения обычно хранят данные в нескольких хранилищах данных и расположениях. Необходимо эффективно управлять и поддерживать согласованность данных в этой среде, особенно из-за проблем параллелизма и доступности, которые могут возникнуть.
Используйте Управляемый Redis Azure в качестве семантического кэша. В этом руководстве показано, как реализовать семантические кэширования с помощью Управляемого Redis в Azure.
Связанные ресурсы
Шаблон надежных веб-приложений: этот шаблон применяет шаблон Cache-Aside к веб-приложениям в облаке.
Руководство по кэшированию. В этом руководстве содержатся дополнительные сведения о том, как кэшировать данные в облачном решении, а также о проблемах, которые следует учитывать при реализации кэша.