緩存預(yù)留模式是根據(jù)需求從數(shù)據(jù)存儲緩存加載數(shù)據(jù)。這種模式可以提高性能,并有助于維持在基礎(chǔ)數(shù)據(jù)存儲在高速緩存中保持的數(shù)據(jù)和數(shù)據(jù)之間的一致性。
應(yīng)用程序使用的高速緩存來優(yōu)化重復(fù)訪問的數(shù)據(jù)存儲中保持的信息。然而,它通常是不切實際的期望緩存的數(shù)據(jù)將始終與在數(shù)據(jù)存儲器中的數(shù)據(jù)完全一致。應(yīng)用程序要實現(xiàn)一種策略,有助于確保在高速緩存中的數(shù)據(jù)是最新的,只要有可能,但也可以檢測和處理的過程中出現(xiàn),當(dāng)在高速緩存中的數(shù)據(jù)已經(jīng)變得陳舊的情況。
許多商業(yè)緩存系統(tǒng)提供通讀和直寫式/后寫操作。在這些系統(tǒng)中,應(yīng)用程序通過引用高速緩存中檢索數(shù)據(jù)。如果數(shù)據(jù)不在緩存中,它被透明地從數(shù)據(jù)存儲中檢索并添加到高速緩存。任何修改在高速緩存中保持的數(shù)據(jù)被自動地寫入到數(shù)據(jù)存儲區(qū)以及。
為緩存不提供此功能,則使用該緩存保持在高速緩存中的數(shù)據(jù)的應(yīng)用程序的責(zé)任。
一個應(yīng)用程序可以通過實現(xiàn)高速緩存預(yù)留戰(zhàn)略模擬的讀式高速緩存的功能。這種策略有效地將數(shù)據(jù)加載需求的高速緩存。圖 1 總結(jié)了在該過程中的步驟。
圖1 - 使用Cache-除了圖案來將數(shù)據(jù)存儲在高速緩沖存儲器
如果一個應(yīng)用程序?qū)⒏碌男畔?,它可以模擬通寫策略如下:
當(dāng)該項目被下一個需要,可使用高速緩存預(yù)留策略將導(dǎo)致從數(shù)據(jù)存儲中檢索和重新添加到高速緩存中的更新數(shù)據(jù)。
在決定如何實現(xiàn)這個模式時,請考慮以下幾點:
使用這種模式時:
這種模式可能不適合:
在微軟的 Azure,您可以使用 Azure 的緩存來創(chuàng)建一個分布式緩存,可以通過一個應(yīng)用程序的多個實例可以共享。下面的代碼示例中的 GetMyEntityAsync 方法給出了基于 Azure 的緩存 Cache 后備模式的實現(xiàn)。此方法從利用讀雖然方法緩存中的對象。
一個目的是確定用一個整數(shù)ID作為鍵。該 GetMyEntityAsync 方法生成基于此鍵(在 Azure 緩存 API 使用的鍵值字符串)的字符串值,并嘗試檢索與從緩存中這一關(guān)鍵的項目。如果匹配的項目被發(fā)現(xiàn),它被返回。如果在緩存中沒有匹配,則 GetMyEntityAsync 方法從一個數(shù)據(jù)存儲中的對象時,把它添加到緩存中,然后將其返回(即實際上獲得從數(shù)據(jù)存儲中的數(shù)據(jù)的代碼已經(jīng)被省略,因為它是數(shù)據(jù)存儲依賴)。注意,緩存項被配置以防止其成為陳舊如果是在別處更新過期。
private DataCache cache;
...
?
public async Task<MyEntity> GetMyEntityAsync(int id)
{
// Define a unique key for this method and its parameters.
var key = string.Format("StoreWithCache_GetAsync_{0}", id);
var expiration = TimeSpan.FromMinutes(3);
bool cacheException = false;
?
try
{
// Try to get the entity from the cache.
var cacheItem = cache.GetCacheItem(key);
if (cacheItem != null)
{
return cacheItem.Value as MyEntity;
}
}
catch (DataCacheException)
{
// If there is a cache related issue, raise an exception
// and avoid using the cache for the rest of the call.
cacheException = true;
}
?
// If there is a cache miss, get the entity from the original store and cache it.
// Code has been omitted because it is data store dependent.
var entity = ...;
?
if (!cacheException)
{
try
{
// Avoid caching a null value.
if (entity != null)
{
// Put the item in the cache with a custom expiration time that
// depends on how critical it might be to have stale data.
cache.Put(key, entity, timeout: expiration);
}
}
catch (DataCacheException)
{
// If there is a cache related issue, ignore it
// and just return the entity.
}
}
?
return entity;
}
注意:
該示例使用了 Azure 的緩存 API 來訪問存儲和檢索的緩存信息。有關(guān) Azure 的緩存 API 的更多信息,請參閱MSDN 上使用微軟的 Azure 緩存。
下面所示的 UpdateEntityAsync 方法說明如何在高速緩存中的對象無效,當(dāng)該值是由應(yīng)用程序改變。這是一個寫通方法的實例。該代碼更新原始數(shù)據(jù)存儲,然后通過調(diào)用 Remove 方法,指定鍵(這部分功能的代碼已經(jīng)被省略了,因為這將是數(shù)據(jù)存儲相關(guān))從緩存中刪除緩存項。
注意
在這個序列中的步驟的次序是重要的。如果之前的緩存更新的項被刪除,對于客戶端應(yīng)用程序中的數(shù)據(jù)存儲中的項目之前獲取的數(shù)據(jù)(因為它沒有在高速緩存中發(fā)現(xiàn)的)的機(jī)會已經(jīng)改變一個小窗口,從而在緩存包含過期數(shù)據(jù)。
public async Task UpdateEntityAsync(MyEntity entity)
{
// Update the object in the original data store
await this.store.UpdateEntityAsync(entity).ConfigureAwait(false);
?
// Get the correct key for the cached object.
var key = this.GetAsyncCacheKey(entity.Id);
?
// Then, invalidate the current cache object
this.cache.Remove(key);
}
?
private string GetAsyncCacheKey(int objectId)
{
return string.Format("StoreWithCache_GetAsync_{0}", objectId);
}
更多建議: