緩存預(yù)留模式是根據(jù)需求從數(shù)據(jù)存儲(chǔ)緩存加載數(shù)據(jù)。這種模式可以提高性能,并有助于維持在基礎(chǔ)數(shù)據(jù)存儲(chǔ)在高速緩存中保持的數(shù)據(jù)和數(shù)據(jù)之間的一致性。
應(yīng)用程序使用的高速緩存來(lái)優(yōu)化重復(fù)訪問(wèn)的數(shù)據(jù)存儲(chǔ)中保持的信息。然而,它通常是不切實(shí)際的期望緩存的數(shù)據(jù)將始終與在數(shù)據(jù)存儲(chǔ)器中的數(shù)據(jù)完全一致。應(yīng)用程序要實(shí)現(xiàn)一種策略,有助于確保在高速緩存中的數(shù)據(jù)是最新的,只要有可能,但也可以檢測(cè)和處理的過(guò)程中出現(xiàn),當(dāng)在高速緩存中的數(shù)據(jù)已經(jīng)變得陳舊的情況。
許多商業(yè)緩存系統(tǒng)提供通讀和直寫式/后寫操作。在這些系統(tǒng)中,應(yīng)用程序通過(guò)引用高速緩存中檢索數(shù)據(jù)。如果數(shù)據(jù)不在緩存中,它被透明地從數(shù)據(jù)存儲(chǔ)中檢索并添加到高速緩存。任何修改在高速緩存中保持的數(shù)據(jù)被自動(dòng)地寫入到數(shù)據(jù)存儲(chǔ)區(qū)以及。
為緩存不提供此功能,則使用該緩存保持在高速緩存中的數(shù)據(jù)的應(yīng)用程序的責(zé)任。
一個(gè)應(yīng)用程序可以通過(guò)實(shí)現(xiàn)高速緩存預(yù)留戰(zhàn)略模擬的讀式高速緩存的功能。這種策略有效地將數(shù)據(jù)加載需求的高速緩存。圖 1 總結(jié)了在該過(guò)程中的步驟。
圖1 - 使用Cache-除了圖案來(lái)將數(shù)據(jù)存儲(chǔ)在高速緩沖存儲(chǔ)器
如果一個(gè)應(yīng)用程序?qū)⒏碌男畔ⅲ梢阅M通寫策略如下:
當(dāng)該項(xiàng)目被下一個(gè)需要,可使用高速緩存預(yù)留策略將導(dǎo)致從數(shù)據(jù)存儲(chǔ)中檢索和重新添加到高速緩存中的更新數(shù)據(jù)。
在決定如何實(shí)現(xiàn)這個(gè)模式時(shí),請(qǐng)考慮以下幾點(diǎn):
使用這種模式時(shí):
這種模式可能不適合:
在微軟的 Azure,您可以使用 Azure 的緩存來(lái)創(chuàng)建一個(gè)分布式緩存,可以通過(guò)一個(gè)應(yīng)用程序的多個(gè)實(shí)例可以共享。下面的代碼示例中的 GetMyEntityAsync 方法給出了基于 Azure 的緩存 Cache 后備模式的實(shí)現(xiàn)。此方法從利用讀雖然方法緩存中的對(duì)象。
一個(gè)目的是確定用一個(gè)整數(shù)ID作為鍵。該 GetMyEntityAsync 方法生成基于此鍵(在 Azure 緩存 API 使用的鍵值字符串)的字符串值,并嘗試檢索與從緩存中這一關(guān)鍵的項(xiàng)目。如果匹配的項(xiàng)目被發(fā)現(xiàn),它被返回。如果在緩存中沒(méi)有匹配,則 GetMyEntityAsync 方法從一個(gè)數(shù)據(jù)存儲(chǔ)中的對(duì)象時(shí),把它添加到緩存中,然后將其返回(即實(shí)際上獲得從數(shù)據(jù)存儲(chǔ)中的數(shù)據(jù)的代碼已經(jīng)被省略,因?yàn)樗菙?shù)據(jù)存儲(chǔ)依賴)。注意,緩存項(xiàng)被配置以防止其成為陳舊如果是在別處更新過(guò)期。
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 來(lái)訪問(wèn)存儲(chǔ)和檢索的緩存信息。有關(guān) Azure 的緩存 API 的更多信息,請(qǐng)參閱MSDN 上使用微軟的 Azure 緩存。
下面所示的 UpdateEntityAsync 方法說(shuō)明如何在高速緩存中的對(duì)象無(wú)效,當(dāng)該值是由應(yīng)用程序改變。這是一個(gè)寫通方法的實(shí)例。該代碼更新原始數(shù)據(jù)存儲(chǔ),然后通過(guò)調(diào)用 Remove 方法,指定鍵(這部分功能的代碼已經(jīng)被省略了,因?yàn)檫@將是數(shù)據(jù)存儲(chǔ)相關(guān))從緩存中刪除緩存項(xiàng)。
注意
在這個(gè)序列中的步驟的次序是重要的。如果之前的緩存更新的項(xiàng)被刪除,對(duì)于客戶端應(yīng)用程序中的數(shù)據(jù)存儲(chǔ)中的項(xiàng)目之前獲取的數(shù)據(jù)(因?yàn)樗鼪](méi)有在高速緩存中發(fā)現(xiàn)的)的機(jī)會(huì)已經(jīng)改變一個(gè)小窗口,從而在緩存包含過(guò)期數(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);
}
更多建議: