最近在研究一項我追蹤已久的記憶體快取技術 Velocity ( 現在已經被納入 Windows Server AppFabric 產品中 ),這是一個分散式記憶體快取的平台,非常適合用來開發 3H ( High Scalability, High Availability, High Performance ) 應用系統開發,他可以將多台伺服器的記憶體融合(fuse)成一個超大記憶體快取,讓你的應用程式能夠非常方便的運用這些記憶體完成應用程式加速的目的,也可減低資料庫的負擔。
這套 Velocity 比我之前用過的 memcached 複雜多了,所以在看 Introduction to Caching with Windows Server AppFabric (Beta 1) 時有點吃力,都要反覆的咬文嚼字、慢慢的看、慢慢的理解才能確認我想的跟文件所描述的是一致的想法,避免錯誤理解導致日後開發上的錯誤。
Windows Server AppFabric Caching 的能力
從上圖可看出 Velocity 在運作時的大致架構,他提供 Clients 一個統一的快取介面(Unified Cache View),他讓 Client 可以不用在意到底實體的快取服務層(Cache Layer)有多複雜,透過統一的 API 介面就可以運用 Velocity 進行 3H 開發。
Windows Server AppFabric Caching 主要特色有:
- 任何可以被序列化的 CLR 物件都可以透過簡單的 Cache API 將資料快取
- 支援企業規模:可支援上百台主機的伺服器架構
- 可彈性的調整設定,並透過網路存取服務
- 支援動態調整規模,可隨時新增節點
- 支援高可用性架構
- 自動負載平衡
- 可與 Event Tracing for Windows (ETW), System Center 等機制整合管理與監控
- 提供與 ASP.NET 的無縫整合,將 Session 資料儲存至快取,也可在 Web farm 架構下將應用程式資料快取,減少資料庫大量存取的負擔
- 第一版遵循 cache-aside architecture ( 明確快取, Explicit Caching ),意即你必須在你的應用程式中明確指明你要新增(Put)或移除(Remove)快取的項目,所有快取資料並不會自動與任何來源資料庫進行同步。
【 分散式記憶體快取基本觀念 】
三種快取資料類型 ( Types of Data )
瞭解不同的快取資料類型可以幫助你決定在何種情境下使用何種快取資料類型,因為不同的快取資料類型適用的快取情境是不同的。
1. 參考資料類型 ( Reference Data )
這種資料類型負責儲存「較重要的資料」而且這類資料都是不會經常變動的資料,而且每次變更資料都會建立一個新的版本,所以這類資料非常適合用來分享給多使用者、多應用程式的情況,用以加速所有應用程式的存取速度,減低各應用程式對資料庫系統造成的負荷。
對於「讀取」需求遠大於「寫入」需求的資料都很適合用這種資料類型進行資料快取,例如:產品型錄。
針對大型應用程式或大流量的網站,參考資料類型也可以設定成自動複寫到快取叢集的多台伺服器,以增加應用系統的延展性。
2. 活動資料類型 ( Activity Data )
所謂活動資料類型指的是短暫的程式資料,這類資料通常不會被各應用程式或不同使用者分享,例如購物車資訊,就屬於這類活動資料。這類資料在大型應用中甚至可以跨伺服器的分割快取空間,可以很輕易的達到高延展性的需求。
3. 資源資料類型 ( Resource Data )
不管是 Reference Data (共享讀取) 或 Activity Data (獨佔寫入) 已經很適合做資料快取,但並非所有應用程式類型都支援這種方式快取,這裡的「資源資料」指的是「共享的」且「同時需要被讀寫」的資料,而且存取量都非常大的情況。 例如「庫存資訊」的庫存量就經常變動,而且必須提供各應用程式即時的資訊,而且可能隨時變更庫存數量,這類資料就稱之為資源資料。
這類型的快取資料通常遇到最大的問題在於很難提供高有效性(High Availability)的支援,由於維護高有效性的資料必須精準的維持資料的一致性,所以必須實做交易處理(transactions)、變更通知(data change notifications)、設定快取失效(invalidations)等特性,透過 Velocity 可讓你設定這類資料自動複寫到不同快取主機,輕易達到 高有效性 的需求。
使用情境
1. 社交網絡網站 ( Social Networking Site )
由於使用者名稱、好友清單都是不會經常變動的資料,所以這種情境很適合採用 參考資料類型 (Reference Data) 來進行快取。
2. 企業商用軟體 ( Enterprise LOB ) -- 例如: ERP, CRM, …
如上圖例,對於供應商資料、價格資訊可以透過 參考資料類型 (Reference Data) 來進行快取,而其他像是訂單資訊、發票資訊、付款資訊 都可以用 活動資料類型 (Activity Data) 來快取。
大型網路通常會實做 NLB (網路負載平衡),所以不會使用者不見得每次都會連接到同壹台 IIS 主機,所以透過這類分散式快取技術就很適合這種快取情境,避免把資料庫操到掛。
【 AppFabric Caching 基本觀念 】
上面講的是關於「分散式快取架構」的基本觀念,這裡講的是「開發模型」的基本觀念,瞭解這些觀念才能讓你在實際利用 AppFabric Caching (Code Name: Velocity) 開發程式時才能有比較清晰的概念,避免看程式看到傻眼。
邏輯階層架構 ( Logical Hierarchy )
邏輯架構依序描述如下:
- 每台 伺服器 (Machine) 可以執行好幾個 快取實體(Cache Instance 或 Cache Host)
註: 就好像壹台機器可以執行好幾個 SQL Server Instance 一樣意思。
- 每個 快取實體 (Cache Host) 可以包含多個 具名快取空間 (Named Cache)
註: 具名快取可以設定跨越多個 Cache Hosts 或 Machines
- 每個 具名快取空間 (Named Cache) 可以包含多個 區域 (Regions)
- 每個 快取區域 (Regions) 可以包含多個 快取項目 (Cache Items)
- 每個 快取項目 (Cache Items) 包含 可序列化的 物件 (Objects)
一個簡單的範例如下:
// CacheFactory class provides methods to return cache objects
// Create instance of CacheFactory (reads appconfig)
DataCacheFactory fac = new DataCacheFactory();
// Get a named cache from the factory
DataCache catalog = fac.GetCache("catalogcache");
//-------------------------------------------------------
// Simple Get/Put
catalog.Put("toy-101", new Toy("thomas", "FunToy"));
// From the same or a different client
Toy toyObj = (Toy)catalog.Get("toy-101");
// ------------------------------------------------------
// Region based Get/Put
catalog.CreateRegion("toyRegion", true);
// Both toy and toyparts are put in the same region
catalog.Put("toy-101", new Toy("FunToy"), "toyRegion");
catalog.Put("toypart-100", new ToyParts("Wheel"), "toyRegion");
Toy toyObj = (Toy)catalog.Get("toy-101", "toyRegion");
快取觀念 ( Cache Concepts )
- 主要節點 ( Primary Node )
- 所有 區域 (Regions) 的資料都會置於主要節點上,任何透過 Cache Client 過來取得快取資料時都會自動被導向(Routed)到主要節點存取快取資料。
- 次要節點 ( Secondary Nodes )
- 如果 具名快取空間 (Named Cache) 為了高可用性(high availability) 而設定「備份」,就會用「次要節點」用來儲存這些「備份用的 區域 (Regions) 」(備註: 區域包含多個快取項目)。如果「主要節點」損毀,快取叢集所收到的要求就會自動轉向到「次要節點」來取得快取資料。
快取型態 ( Cache Types )
AppFabric 支援兩種常見的快取型態:分割快取、本地快取
- 分割快取 ( Partitioned Cache )
- 講「分割快取」很容易誤解其意思,這概念並不像「磁碟分割」那樣一棵實體硬碟分割成好幾個磁區,而是將「所有快取伺服器」全部整合成一個記憶體快取儲存區 (快取叢集),你可以在這個「快取叢集」分割出你想要的任何大小。
- 因此,透過 Partitioned Cache 很適合用在需要大量記憶體快取的應用程式,這可大幅提升應用程式的延展性(Scalability),當記憶體不夠用時就只要增加伺服器即可。
- 當新快取伺服器加入整個快取叢集後,Velocity 會自動進行負載平衡,並將部分快取項目自動移至新主機,當快取項目平均分散在各台主機後也會增加整體快取叢集的吞吐量(Throughtput)。
- 由於是將多台伺服器整合成一個大記憶體,所以快取資料並不會重複儲存,如下圖例:K2,V2 指的是 “Key/Value Pair 2” 的意思,由於透過 Put 指令寫入快取項目時勢將資料寫入到 Cache 2 這個 快取實體(Cache Host) 中,所以當另一台主機從 Cache 3 取得(Get) K2,V2 資料時,就會透過 Velocity 內部的 Routing 機制從 Cache2 取得資料,而這些複雜的 Routing 作業全都由 Velocity 幫你完成。
- Partitioned Cache 還能設定「次要快取節點」,讓「主要快取資料」能自動將快取項目複寫到另一台主機,達到高有效性(High Availability)的目標,如下是 HA 模式的示意圖:
- 本地快取 ( Local Cache )
- Velocity 也支援「本地快取」,透過本地快取可以有效省去「序列化/反序列化」的 CPU 成本,可提升讀寫快取資料時的效能。
- 如下圖示很容易能看出運用本地快取的情境:
過期與回收 ( Expiration and Eviction )
- 快取過期 ( Expiration )
- 在新增快取項目到 Regions 時可以指定該物件的存活時間(TTL; Time To Live)
- 快取回收 ( Eviction )
- 快取項目可以設定優先等級,當快取記憶體不夠用時就會依據 LRU (least-recently-used) 演算法將不常用的快取項目刪除,讓優先權較高的快取項目進入快取伺服器。
一致性模型 ( Consistency Models )
- 樂觀版本更新機制 ( optimistic version-based updates )
- 透過這個機制可享受較高的執行效能,因為就算不同的 Client 端在同時執行 取得快取(Get) 或 寫入快取(Put) 動作可以同時執行,Velocity 會在內部維護一份快取項目的版本資訊,而且會在每次取得(Get)資料時一併傳回用戶端,所以不用維護鎖定(locking)的問題,但版本資訊在 Client 端需自行判斷新舊。
- 悲觀鎖定機制 ( pessimistic locking )
- 透過 API 提供的 GetandLock 取得資料時,若有其他程序也要透過 GetandLock 取得資料時就會發生失敗,但若 Client 使用單純的 Get 取得資料還是可以的。
- 這時透過 PutAndLock 方法可以將資料回寫至 Velocity,這時鎖定狀態就會被解除,但如果直接使用 Put 方法則會直接取消鎖定狀態並直接複寫該物件的值,所以必須小心使用。
- 透過 UnLock 方法也可以直接設定解除鎖定。
變更通知 ( Notifications )
在分散式的架構下,由於多個用戶端同時存取同一份資源,實做變更通知變的非常實用,當另一個用戶端變更了某個 區域 (Regions) 或 快取項目 (Cache Items) 時可以透過事件通知應用程式。
部署拓樸 ( Deployment Topology )
Velocity 是透過 Windows Service 提供服務,可以透過 TCP/IP 從本機或遠端電腦連線,並透過 .NET Client API 直接操作使用。
如下圖是兩種常見的 Velocity 部署模式:
- Embedded
- 將 快取實體(Cache Host) 跟 IIS 主機安裝在一起,並聯合多台主機組成快取叢集
- Cache Service
- 使用 專屬主機 提供 快取實體(Cache Host),提供一個實體的 快取層(Caching Tier)
ASP.NET 整合 ( ASP.NET Integration )
Velocity 預設提供一組 SessionStoreProvider 可讓你無痛的將 Session 移至 AppFabric Caching 平台,並儲存到一個 分割快取 (Partitioned Cache) 中,透過設定也可以達到 HA (High Availability) 與 HS (High Scalability) 的規劃。
效能測試 ( Performance Testing )
如下圖示,只要新增快取伺服器幾乎呈現「線性成長」的吞吐量,可有效提升應用程式的延展性。
結論 ( Conclusion )
透過 AppFabric Caching 可以輕易的讓你將多台伺服器的記憶體融合成一個超大記憶體快取,透過單一 API 即可存取這些記憶體快取,當記憶體不夠時只要增加伺服器即可輕易擴充完成,不止有效降低管理成本,還可輕易的達成 3H ( High Scalability, High Availability, High Performance ) 系統架構。
相關連結