(一)—— 緩存預(yù)留模式

2018-02-24 15:44 更新

云計算設(shè)計模式(一)——緩存預(yù)留模式

緩存預(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ū)⒏碌男畔?,它可以模擬通寫策略如下:

  • 根據(jù)修改到數(shù)據(jù)存儲
  • 作廢對應(yīng)的項在緩存中。

當(dāng)該項目被下一個需要,可使用高速緩存預(yù)留策略將導(dǎo)致從數(shù)據(jù)存儲中檢索和重新添加到高速緩存中的更新數(shù)據(jù)。

問題和注意事項

在決定如何實現(xiàn)這個模式時,請考慮以下幾點:

  • 緩存數(shù)據(jù)的生命周期。很多緩存實現(xiàn)一個過期策略,導(dǎo)致數(shù)據(jù)無效,并從緩存中移除如果它不是在指定時間內(nèi)訪問。對于緩存一邊是有效的,確保了過期策略相匹配的訪問用于使用數(shù)據(jù)的應(yīng)用程序的模式。不要使有效期限太短,因為這會導(dǎo)致應(yīng)用程序不斷地從數(shù)據(jù)存儲中檢索數(shù)據(jù),并將其添加到緩存中。同樣,不要使保質(zhì)期這么久,緩存的數(shù)據(jù)很可能會變得陳舊。記住,緩存是最有效的相對靜態(tài)的數(shù)據(jù),或者數(shù)據(jù)被頻繁地讀出。
  • 驅(qū)逐數(shù)據(jù)。最高速緩存具有比從其中數(shù)據(jù)源自數(shù)據(jù)存儲區(qū)只有有限的大小,并在必要時它們將收回的數(shù)據(jù)。大多數(shù)緩存采用最近最少使用的政策選擇項目驅(qū)逐,但是這可能是定制的。配置全局到期屬性和高速緩存的其它性能,并且每個高速緩存項的到期屬性,以幫助確保緩存成本效益。它可能并不總是適合于高速緩存中的應(yīng)用全球驅(qū)逐政策,每一個項目。例如,如果緩存項是非常昂貴的,從數(shù)據(jù)存儲中檢索,也可能是有益的,保留在更頻繁地訪問但不昂貴的物品的費用此產(chǎn)品的高速緩存中。
  • 灌注緩存。許多解決方案,預(yù)填充用的應(yīng)用程序可能需要作為啟動處理的一部分的數(shù)據(jù)的高速緩存。如果某些數(shù)據(jù)已到期,被驅(qū)逐的緩存,除了圖案可能仍然是有用的。
  • 一致性。執(zhí)行緩存除了圖案不保證數(shù)據(jù)存儲和高速緩存之間的一致性。在數(shù)據(jù)存儲中的項目可以在任何時候被改變由外部的過程中,這種變化可能不反映在高速緩存中的項目被裝載到高速緩存,直到下一次。在一個系統(tǒng),整個數(shù)據(jù)存儲復(fù)制數(shù)據(jù),如果同步發(fā)生非常頻繁這個問題可能會變得尤為突出。
  • 本地(內(nèi)存)緩存。緩存可以是本地的應(yīng)用程序?qū)嵗?,并存儲在?nèi)存中。緩存預(yù)留如果應(yīng)用程序多次訪問相同的數(shù)據(jù)可以在該環(huán)境中是有用的。然而,本地高速緩存是私有的,因此不同的應(yīng)用程序?qū)嵗筛髯跃哂邢嗤木彺鏀?shù)據(jù)的副本。此數(shù)據(jù)可能很快變成高速緩存之間不一致,所以它可能有必要在到期專用高速緩存中保存的數(shù)據(jù)和更經(jīng)常地刷新。在這些場景中它可能是適當(dāng)?shù)?,調(diào)查使用了共享或分布式緩存機(jī)制。

當(dāng)使用這個模式

使用這種模式時:

  • 緩存不提供原生讀通過,并通過寫操作。
  • 資源的需求是不可預(yù)測的。這種模式使應(yīng)用程序能夠按需加載數(shù)據(jù)。它使任何假設(shè)有關(guān)的數(shù)據(jù)的應(yīng)用程序?qū)⑿枰崆啊?

這種模式可能不適合:

  • 當(dāng)緩存的數(shù)據(jù)集是靜態(tài)的。如果數(shù)據(jù)將適合可用的高速緩存空間,首要的高速緩存中的數(shù)據(jù)在啟動和應(yīng)用,防止數(shù)據(jù)從止政策。
  • 對于托管在 Web 場中的 Web 應(yīng)用程序緩存會話狀態(tài)信息。在這種環(huán)境下,你應(yīng)該避免引入基于客戶端 - 服務(wù)器關(guā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);  
}
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號