Load data on demand into a cache from a data store. This can improve performance and also helps to maintain consistency between data held in the cache and data in the underlying data store.
將數(shù)據從存儲加載到緩存中担平。 這可以提高性能,并且還有助于保持緩存中保存的數(shù)據與底層數(shù)據存儲中的數(shù)據之間的一致性。
Context and problem
Applications use a cache to improve repeated access to information held in a data store. However, it's impractical to expect that cached data will always be completely consistent with the data in the data store. Applications should implement a strategy that helps to ensure that the data in the cache is as up-to-date as possible, but can also detect and handle situations that arise when the data in the cache has become stale.
應用程序使用緩存來改進對數(shù)據存儲中保存的信息的重復訪問血淌。 然而含友,期望緩存的數(shù)據將始終與數(shù)據存儲中的數(shù)據完全一致是不切實際的改执。 應用程序應實施有助于確保緩存中的數(shù)據盡可能最新的策略絮短,并能夠檢測和處理緩存中的數(shù)據變得過時的情況囚玫。
Solution
Many commercial caching systems provideread-through and write-through/write-behind operations. In these systems, an application retrieves data by referencing the cache. If the data isn't in the cache, it's retrieved from the data store and added to the cache. Any modifications to data held in the cache are automatically written back to the data store as well.
許多商業(yè)緩存系統(tǒng)提供讀寫和寫/寫操作喧锦。 在這些系統(tǒng)中,應用程序通過引用緩存來檢索數(shù)據抓督。 如果數(shù)據不在緩存中燃少,則從數(shù)據存儲中檢索數(shù)據,并將其添加到緩存中铃在。 對緩存中保存的數(shù)據的任何修改也會自動寫回數(shù)據存儲區(qū)阵具。
For caches that don't provide this functionality, it's the responsibility of the applications that use the cache to maintain the data.
對于不提供此功能的緩存,使用緩存的應用程序負責維護數(shù)據定铜。
An application can emulate the functionality of read-through caching by implementing the cache-aside strategy. This strategy loads data into the cache on demand. The figure illustrates using the Cache-Aside pattern to store data in the cache.
應用程序可以通過實現(xiàn)旁路緩存策略來模擬直讀緩存的功能阳液。 此策略將數(shù)據按需加載到緩存中。 下圖說明了使用Cache-Aside模式將數(shù)據存儲在緩存中宿稀。
If an application updates information, it can follow the write-through strategy by making the modification to the data store, and by invalidating the corresponding item in the cache.
如果應用程序更新信息趁舀,則可以通過對數(shù)據存儲進行修改,并使緩存中的相應項目無效祝沸,從而遵循直寫策略矮烹。
When the item is next required, using the cache-aside strategy will cause the updated data to be retrieved from the data store and added back into the cache.
當下一個項目需要時,使用cache-aside策略將導致更新的數(shù)據從數(shù)據存儲中檢索并添加到高速緩存中罩锐。
Issues and considerations
Consider the following points when deciding how to implement this pattern:
Lifetime of cached data. Many caches implement an expiration policy that invalidates data and removes it from the cache if it's not accessed for a specified period. For cache-aside to be effective, ensure that the expiration policy matches the pattern of access for applications that use the data. Don't make the expiration period too short because this can cause applications to continually retrieve data from the data store and add it to the cache. Similarly, don't make the expiration period so long that the cached data is likely to become stale. Remember that caching is most effective for relatively static data, or data that is read frequently.
緩存數(shù)據的生命周期奉狈。 許多高速緩存實現(xiàn)一個到期策略,使數(shù)據無效涩惑,如果在指定的時間段內沒有訪問仁期,則將其從緩存中刪除。 為了使緩存有效竭恬,請確保到期策略與使用數(shù)據的應用程序的訪問模式相匹配跛蛋。 不要使過期期間太短,因為這可能導致應用程序不斷從數(shù)據存儲中檢索數(shù)據并將其添加到緩存痊硕。 同樣赊级,不要讓到期期限長到緩存的數(shù)據可能變得陳舊。 請記住岔绸,緩存對于相對靜態(tài)的數(shù)據或經常讀取的數(shù)據是最有效的理逊。
Evicting data. Most caches have a limited size compared to the data store where the data originates, and they'll evict data if necessary. Most caches adopt a least-recently-used policy for selecting items to evict, but this might be customizable. Configure the global expiration property and other properties of the cache, and the expiration property of each cached item, to ensure that the cache is cost effective. It isn't always appropriate to apply a global eviction policy to every item in the cache. For example, if a cached item is very expensive to retrieve from the data store, it can be beneficial to keep this item in the cache at the expense of more frequently accessed but less costly items.
數(shù)據逐出。 與數(shù)據來源的數(shù)據存儲相比盒揉,大多數(shù)緩存的大小都有限晋被,如果需要,它們將會排除數(shù)據刚盈。 大多數(shù)緩存采用最近最少使用的策略來選擇要逐出的項目羡洛,但這應該是可定制的。 配置緩存的全局過期屬性和其他屬性以及每個緩存項的到期屬性藕漱,以確保緩存具有成本效益欲侮。 將全局逐出策略應用于緩存中的每個項目并不總是適合的。 例如谴分,如果緩存項從數(shù)據存儲中檢索非常昂貴锈麸,則將該項而不是那些頻繁訪問但檢索成本較低的項保留在緩存中是有益的。
Priming the cache. Many solutions prepopulate the cache with the data that an application is likely to need as part of the startup processing. The Cache-Aside pattern can still be useful if some of this data expires or is evicted.
啟動緩存牺蹄。 許多解決方案使用應用程序可能需要的數(shù)據預先填充緩存忘伞,作為啟動處理的一部分。 如果某些數(shù)據到期或被驅逐沙兰,Cache-Aside模式仍然有用氓奈。
Consistency. Implementing the Cache-Aside pattern doesn't guarantee consistency between the data store and the cache. An item in the data store can be changed at any time by an external process, and this change might not be reflected in the cache until the next time the item is loaded. In a system that replicates data across data stores, this problem can become serious if synchronization occurs frequently.
一致性。 實現(xiàn)Cache-Aside模式不能保證數(shù)據存儲和緩存之間的一致性鼎天。 數(shù)據存儲中的項目可以隨時通過外部進程進行更改舀奶,并且在下次加載項目前,此更改可能不會反映在緩存中斋射。 在跨數(shù)據存儲復制數(shù)據的系統(tǒng)中育勺,如果同步頻繁發(fā)生但荤,則此問題可能會變得嚴重。
Local (in-memory) caching. A cache could be local to an application instance and stored in-memory. Cache-aside can be useful in this environment if an application repeatedly accesses the same data. However, a local cache is private and so different application instances could each have a copy of the same cached data. This data could quickly become inconsistent between caches, so it might be necessary to expire data held in a private cache and refresh it more frequently. In these scenarios, consider investigating the use of a shared or a distributed caching mechanism.
本地(內存中)緩存涧至。 緩存可以是應用程序實例的本地腹躁,并存儲在內存中。 如果應用程序重復訪問相同的數(shù)據南蓬,緩存在此環(huán)境中可能很有用纺非。 然而,本地緩存是私有的赘方,因此不同的應用程序實例可以具有相同緩存數(shù)據的副本烧颖。 這些數(shù)據可能會在高速緩存之間迅速變得不一致,因此使保存在私有緩存中的數(shù)據過期窄陡,并更頻繁地刷新數(shù)據變得非常有必要炕淮。 在這些場景下,請考慮調查使用共享或分布式緩存機制泳梆。
When to use this pattern
Use this pattern when:
- A cache doesn't provide native read-through and write-through operations.
- Resource demand is unpredictable. This pattern enables applications to load data on demand. It makes no assumptions about which data an application will require in advance.
- 緩存不提供本機的直讀和直寫操作鳖悠。
- 資源需求是不可預知的。 此模式使應用程序能夠按需加載數(shù)據优妙。 它不會提前預測應用程序需要哪些數(shù)據乘综。
This pattern might not be suitable:
- When the cached data set is static. If the data will fit into the available cache space, prime the cache with the data on startup and apply a policy that prevents the data from expiring.
- For caching session state information in a web application hosted in a web farm. In this environment, you should avoid introducing dependencies based on client-server affinity.
- 當緩存的數(shù)據集是靜態(tài)的。 如果數(shù)據將適合可用的緩存空間套硼,請使用啟動時的數(shù)據引導緩存卡辰,并應用防止數(shù)據過期的策略。
- 用于在Web場中托管的Web應用程序中緩存會話狀態(tài)信息邪意。 在這種環(huán)境中九妈,您應該避免根據客戶端 - 服務器的親和性引入依賴關系。
Example
In Microsoft Azure you can use Azure Redis Cache to create a distributed cache that can be shared by multiple instances of an application.
To connect to an Azure Redis Cache instance, call the static Connect method and pass in the connection string. The method returns a ConnectionMultiplexer that represents the connection. One approach to sharing a ConnectionMultiplexer instance in your application is to have a static property that returns a connected instance, similar to the following example. This approach provides a thread-safe way to initialize only a single connected instance.
在Microsoft Azure中雾鬼,您可以使用Azure Redis Cache創(chuàng)建可由應用程序的多個實例共享的分布式緩存萌朱。
要連接到Azure Redis Cache實例,請調用靜態(tài)Connect方法并傳入連接字符串策菜。 該方法返回表示連接的ConnectionMultiplexer晶疼。 在應用程序中共享ConnectionMultiplexer實例的一種方法是具有返回連接實例的靜態(tài)屬性,類似于以下示例又憨。 這種方法提供了線程安全的方法來初始化一個連接的實例翠霍。
private static ConnectionMultiplexer Connection;
// Redis Connection string info
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
string cacheConnection = ConfigurationManager.AppSettings["CacheConnection"].ToString();
return ConnectionMultiplexer.Connect(cacheConnection);
});
public static ConnectionMultiplexer Connection => lazyConnection.Value;
The GetMyEntityAsync method in the following code example shows an implementation of the Cache-Aside pattern based on Azure Redis Cache. This method retrieves an object from the cache using the read-though approach.
以下代碼示例中的GetMyEntityAsync方法顯示了基于Azure Redis Cache的Cache-Aside模式的實現(xiàn)。 此方法使用只讀方法從緩存中檢索對象蠢莺。
An object is identified by using an integer ID as the key. The GetMyEntityAsync method tries to retrieve an item with this key from the cache. If a matching item is found, it's returned. If there's no match in the cache, the GetMyEntityAsync method retrieves the object from a data store, adds it to the cache, and then returns it. The code that actually reads the data from the data store is not shown here, because it depends on the data store. Note that the cached item is configured to expire to prevent it from becoming stale if it's updated elsewhere.
通過使用整數(shù)ID作為關鍵字來標識對象寒匙。
GetMyEntityAsync方法嘗試使用此鍵從緩存中檢索項目。 如果找到匹配項躏将,則返回锄弱。 如果緩存中沒有匹配項考蕾,GetMyEntityAsync方法將從數(shù)據存儲中檢索該對象,將其添加到緩存中棵癣,然后返回辕翰。 實際上從數(shù)據存儲器讀取數(shù)據的代碼在這里不顯示夺衍,因為它取決于數(shù)據存儲狈谊。 請注意,緩存的項目被配置為過期沟沙,以防止其在其他地方更新河劝。
// 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's 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;
}
The examples use the Azure Redis Cache API to access the store and retrieve information from the cache. For more information, see Using Microsoft Azure Redis Cache and How to create a Web App with Redis Cache
這些示例使用Azure Redis Cache API來訪問存儲并從緩存中檢索信息。 有關詳細信息矛紫,請參閱Using Microsoft Azure Redis Cache and
How to create a Web App with Redis Cache
The UpdateEntityAsync method shown below demonstrates how to invalidate an object in the cache when the value is changed by the application. This is an example of a write-through approach. The code updates the original data store and then removes the cached item from the cache by calling the KeyDeleteAsync method, specifying the key.
下面顯示的UpdateEntityAsync方法演示了當應用程序更改值時赎瞎,如何使緩存中的對象無效。 這是一個寫通方法的例子颊咬。 代碼更新原始數(shù)據存儲务甥,然后通過調用KeyDeleteAsync方法(指定該鍵)從緩存中刪除緩存的項目。
The order of the steps in this sequence is important. If the item is removed before the cache is updated, the client application has a short period of time to fetch the data (because it isn't found in the cache) before the item in the data store has been changed, resulting in the cache containing stale data.
這個順序的順序很重要喳篇。 如果在緩存更新之前刪除該項目敞临,則客戶端應用程序在數(shù)據存儲中的項目已更改之前,具有很短的時間來獲取數(shù)據(因為它在高速緩存中未找到)麸澜,從而導致高速緩存包含陳舊的數(shù)據挺尿。
public async Task UpdateEntityAsync(MyEntity entity)
{
// Invalidate the current cache object
var cache = Connection.GetDatabase();
var id = entity.Id;
var key = $"MyEntity:{id}"; // Get the correct key for the cached object.
await cache.KeyDeleteAsync(key).ConfigureAwait(false);
// Update the object in the original data store
await this.store.UpdateEntityAsync(entity).ConfigureAwait(false);
}
Related guidance
The following information may be relevant when implementing this pattern:
Caching Guidance. Provides additional information on how you can cache data in a cloud solution, and the issues that you should consider when you implement a cache.
Data Consistency Primer. Cloud applications typically use data that's spread across data stores. Managing and maintaining data consistency in this environment is a critical aspect of the system, particularly the concurrency and availability issues that can arise. This primer describes issues about consistency across distributed data, and summarizes how an application can implement eventual consistency to maintain the availability of data.
Caching Guidance. 提供有關如何在云解決方案中緩存數(shù)據的其他信息,以及實現(xiàn)緩存時應考慮的問題炊邦。
Data Consistency Primer. 云應用程序通常使用分布在數(shù)據存儲中的數(shù)據编矾。 管理和維護此環(huán)境中的數(shù)據一致性是系統(tǒng)的一個重要方面,特別是可能出現(xiàn)的并發(fā)和可用性問題馁害。 本引言介紹了有關分布式數(shù)據一致性的問題窄俏,并總結了應用程序如何實現(xiàn)最終的一致性來維護數(shù)據的可用性。