這篇文章講解分散式快取,即 Distributed caching in ASP.NET Core
Distributed caching in ASP.NET Core
分散式快取是可以在多個應用服務上共享的快取,比較經典的用法是作為多個應用伺服器的一個可到達的外部服務。分散式快取可以提高 ASP.NET Core應用的效能和擴充套件性(performance and scalability), 特別是當應用是部署在雲伺服器或者伺服器叢集上時。
分散式快取比其他快取儲存在獨立伺服器上的場景有幾個優點。
當快取資料是分散式的:
- 跨多個伺服器的請求時,資料是一致的
- 比伺服器重啟和應用部署存在的時間長
- 不使用本地記憶體
不同分散式快取的實現,它們的配置不同。這篇文章會講解怎樣配置 SQL Server分散式快取 和 Redis分散式快取 。第三方實現也是可用的,例如,NCache. 不管選擇那一種實現,應用和快取都是使用 IDistributedCache介面互動。
一.Prerequisites(先決條件)
1. 要使用SQL Server分散式快取,需要引入 Microsoft.AspNetCore.App metapackage 或者 新增 Microsoft.Extensions.Caching.SqlServer 包的引用
2. 要使用Redis 分散式快取,需要引用 Microsoft.AspNetCore.App metapackage 並且新增 Microsoft.Extensions.Caching.StackExchangeRedis 包的引用。因為Redis包沒有包含在 Microsoft.AspNetCore.App 中,所以必須分開引用Redis包。
二. IDistributedCache interface
IDistributedCache介面提供下列方法來操作分散式快取中的資料項:
- Get, GetAsync :接受string型別的key, 如果在快取中找到了,快取資料會以byte[]陣列的形式輸出
- Set, SetAsync :往快取中新增快取資料
- Refresh, RefreshAsync : 根據key值,重新整理快取中的資料項,重置它的過期時間
- Remove, RemoveAsync : 刪除快取的資料項
三. Establish distributed caching services (建立分散式服務)
在Startup.ConfigureServices中註冊一個IDistributedCache的實現。Framework提供的實現在這個主題會做一些描述,包括:
- Distributed Memory Cache(分散式記憶體快取)
- Distributed SQL Server cache(分散式SQL Server快取)
- Distributed Redis cache(分散式Redis快取)
1. Distributed Memory Cache
Distributed Memory Cache 是儲存在記憶體中的 , 它不是一個現實(actual)中的分散式快取。快取資料是儲存在應用執行的伺服器上的。
分散式記憶體快取是一個有用的實現:
-
在開發和測試場景
-
當生產環境是在一個單獨的伺服器,並且記憶體消耗不是一個問題時。實現分散式記憶體快取來簡化資料儲存。它允許在將來實現一個真正的分散式快取解決方案如果多個結點或者容錯成為可能 。(Implementing the Distributed Memory Cache abstracts cached data storage. It allows for implementing a true distributed caching solution in the future if multiple nodes or fault tolerance become necessary.)
這個示例中,應用是執行在開發環境,在 Startup.ConfigureServices中 ,使用 Distributed Memory Cache :
services.AddDistributedMemoryCache();
2. Distributed SQL Server Cache
分散式SQL Server 快取實現允許分散式快取使用SQL Server資料庫作為一個儲存備份。要在SQL Server例項中建立一個SQL Server快取項(cached item),你應該用sql-cache工具。這個工具用你提供的name和schema建立一個table.
在SQL Server中通過執行sql-cache create命令建立一個table. 提供SQL Server例項(Data Source),資料庫(Initial Catalog),schema(例如, dbo),和表名(例如,TestCache):
dotnet sql-cache create "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
成功後,顯示:
Table and index were created successfully.
通過sql-cache工具建立的表(table)有下列的schema:
注意:應用在操作快取值時,應該使用IDistributedCache,而不是一個SqlServerCache.即使用介面的方式
這個示例應用實現了SqlServerCache,在非開發環境,在Startup.ConfigureServices:
services.AddDistributedSqlServerCache(options => { options.ConnectionString = _config["DistCache_ConnectionString"]; options.SchemaName = "dbo"; options.TableName = "TestCache"; });
3. Distributed Redis Cache
Redis是一個開源的in-memory 資料儲存,它經常用作一個分散式快取。你可以在本地使用Redis,並且你可以配置Azure Redis Cache為一個Azure-hosted ASP.NET Core應用。
一個應用配置快取實現,使用一個RedisCache例項在一個非開發環境,在Startup.ConfigureServices:
services.AddStackExchangeRedisCache(options => { options.Configuration = "localhost"; options.InstanceName = "SampleInstance"; });
使用本地機器上的Redis時,需要下載Redis,並且執行redis-server 。
好了,上面的1,2,3是講解不同快取在 Startup.ConfigureServices 中的配置,使新增到專案中。下面講下如何使用
四.Use the distributed cache
要使用IDistributedCache介面,可以從應用中的任意建構函式中,請求一個IDistributedCache例項.這個例項通過依賴注入提供。
當應用啟動時,IDistributedCache被注入到Startup.Configure中。使用IApplicationLifetime使當前時間被快取。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime, IDistributedCache cache) { lifetime.ApplicationStarted.Register(() => { var currentTimeUTC = DateTime.UtcNow.ToString(); //當前時間 byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC); var options = new DistributedCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(20)); cache.Set("cachedTimeUTC", encodedCurrentTimeUTC, options); });
在這個示例應用中,會把 IDistributedCache注入到IndexModel中被Index page使用。
程式碼如下:
public class IndexModel : PageModel { private readonly IDistributedCache _cache; public IndexModel(IDistributedCache cache) { _cache = cache; } public string CachedTimeUTC { get; set; } public async Task OnGetAsync() { CachedTimeUTC = "Cached Time Expired"; var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC"); if (encodedCachedTimeUTC != null) { CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC); } } public async Task<IActionResult> OnPostResetCachedTime() { var currentTimeUTC = DateTime.UtcNow.ToString(); byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC); var options = new DistributedCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(20)); await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options); return RedirectToPage(); } }
注意:對於IDistributedCache例項,沒有必要使用單例(Singleton)或者Scoped lifetime。(至少對於內建的實現沒有必要)
五.Recommendations
當考慮使用IDistributedCache的哪一種實現對於你的應用最合適時,可以考慮下:
-
Existing infrastructure 已存在的基礎設施
-
Performance requirements 表現(效能)要求
-
Cost 花銷
-
Team experience 團隊經驗
快取解決方案通常依賴in-memory storage(記憶體儲存)來提供對快取資料的快速檢索。但是記憶體是一個有限的資源,並且很難擴充套件(costly to expand;costly,昂貴的)。僅將常用資料儲存在快取中。
通常來說,一個Redis cache比一個SQL Server cache 能提供更高的吞吐量(throughput:生產量,生產能力,吞吐量),並且更低的潛伏因素(latency:潛伏,潛伏因素). 然而,大家通常使用 benchmarking來判斷the performance characteristics of caching strategies(快取策略的表現效能)。
當SQL Server被用作一個分散式快取備份儲存。使用同一個資料庫來快取和普通資料的儲存,和檢索,會消極的影響兩者的表現。我們建議為分散式快取備份儲存使用一個專用的SQL Server例項。
參考資料:
https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2