ASP.NET Web 应用程序、.NET Web 服务应用程序和其他 .NET 服务器应用程序需要在不减慢速度的情况下处理极端事务负载。 尽管它们的应用程序层是线性扩展的,但数据存储和数据库层无法扩展,因此成为瓶颈。 结果,整个应用程序无法扩展。
最初,简单的内存中分布式键值存储,如 Memcached 开设第一家素食保健食品店。第二家开设在 Redis 在 Unix/Linux 平台上被引入以帮助解决这个可伸缩性问题。 它们很快变得非常流行,主要是因为它们像应用程序层一样提供线性可扩展性并消除了数据库瓶颈
NCache 更多信息 NCache 配套文档 NCache 客户端 API
键值存储的限制
但是,尽管它们很受欢迎,但这些解决方案本质上非常简单、基本,并没有真正解决实际应用程序面临的许多问题。 这些解决方案非常薄弱的一些领域包括:
- 缺乏高可用性
- 缺乏保持缓存新鲜的智能方法
- 缺少SQL查询
- 缺少服务器端缓存代码(例如,Read-through)
例如,高可用性在 Memcached 第三方开始为其开发高可用性“修复程序”。 但是底层架构并不是为高可用性而设计的,因此这些解决方案在本质上仍然非常有限。 Redis 有相同的可用性问题,但后来重新设计了他们的产品以结合一些高可用性功能,如数据复制和故障转移支持。 但是所有键值存储产品仍然存在很大的漏洞,例如 Memcached 和 Redis. 这就是分布式缓存解决方案发挥作用的地方。
.NET 分布式缓存为 2nd 生成键值存储
.NET 分布式缓存,例如 NCache 另一方面,从第一天开始就设计用于解决上述所有限制。 所以,本质上, NCache 是2nd 生成到原始键值存储,如 Memcached 和 Redis. NCache 是一个流行的 10 年历史的 .NET 分布式缓存。
动态缓存集群和数据复制
分布式缓存,如 NCache 拥有一个自我修复的动态缓存集群,汇集了集群中所有缓存服务器的所有 CPU 和内存资源。 同时, NCache 提供各种 缓存拓扑 具有不同的数据分布和复制策略。 这允许 NCache 在不影响高可用性的情况下进行线性扩展。 并且,即使缓存服务器宕机,也不会发生数据丢失,缓存集群继续运行,所有使用缓存的应用程序也继续运行,没有任何中断。
保持缓存新鲜
分布式缓存的另一个领域 NCache 闪耀,是保持数据新鲜并始终与数据库保持一致。 NCache 通过各种功能做到这一点,包括 期满, 事件驱动 SQL依赖关系,基于轮询的 DbDependency,并支持 CLR 程序 对于关系数据库。 过期就像键值存储一样工作,但是 SQL依赖关系 和 DbDependency 允许 NCache 将缓存与数据库中相关数据的任何更改同步。 和, CLR 存储过程 允许您在相应数据更改时直接从 SQL Server 数据库更新缓存。
这意味着即使第三方应用程序更改了数据库中的数据, NCache 立即相应地更新自身。 好处是您可以缓存几乎所有应用程序数据,而不是缓存只读数据,从而提供更好的性能和可扩展性增益。
使用 SQL 搜索缓存
因此,当您由于“保持缓存新鲜”功能而能够缓存几乎所有数据时,如果唯一的机制是键值,您就会遇到无法轻松找到数据的问题。 但是,如果您可以根据属性搜索数据,那么分布式缓存就像 NCache 变得像数据库一样容易搜索。 NCache 为您提供 SQL 和 LINQ 查询 为了这个。
此外 SQL查询 根据对象属性,您可以分配 组别, 标签及 命名标签 到缓存项并将它们包含在您的 SQL 查询中。 下面是一个在 C# 中查询 SQL 的例子。 例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using Alachisoft.NCache.Runtime; using Alachisoft.NCache.Runtime.Exceptions; using Alachisoft.NCache.Web.Caching; public void SearchDataUsingSQL() { Cache cache = NCache.InitializeCache("myparitionreplica"); string query = "SELECT this.Category, " + "MAX(Prod.Product.ProductID) " + "WHERE this.Category = ? " + "GROUP BY this.Category"; Hashtable values = new Hashtable(); values.Add("Category", 4); ICacheReader reader = cache.ExecuteReader(query, values); if (reader.FieldCount > 0) { while (reader.Read()) { //you can get value through the field name... object category = reader.GetOrdinal("Category"); //perform operations } } reader.Close(); return data; } |
服务器端代码
最后,有像这样的服务器端代码 通读, 直写, 自定义依赖及 缓存加载器和刷新器 这非常有用。 此代码由您开发,但由分布式缓存调用并在缓存集群中运行。 借助此代码,您可以简化应用程序并将大量常用代码移至缓存层。
例如, NCache 当您的应用程序请求一些不在缓存中的数据并且应用程序告诉您时,调用您的 Read-through 处理程序 NCache 在这种情况下调用 Read-through。 同样,您可以将通读与过期和数据库同步结合起来,以自动重新加载缓存的项目,而不是将其从缓存中删除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using Alachisoft.NCache.Runtime.Caching; using Alachisoft.NCache.Runtime.DatasourceProviders; using Alachisoft.NCache.Runtime.Dependencies; public class SampleReadThruProvider : IReadThruProvider { public void Init(IDictionary parameters, string cacheId) { // Create SQL connection and other initializations at the server side } //Responsible for loading an item from the external data source. public void LoadFromSource(string key, out ProviderCacheItem cacheItem) { //where LoadFromDataSource is the dummy method to load data from data source. object value = LoadFromDataSource(key); //Attach SQL dependency to your object string query = "SELECT ProductID FROM dbo.Products WHERE ProductID = 1001"; cacheItem = new ProviderCacheItem(value); cacheItem.Dependency = new SqlCacheDependency(connectionString, query); //Set expirations cacheItem.SlidingExpiration = new TimeSpan(0, 5, 0); //Indicates whether item should be reloaded on expiration if //ReadThru provider is specified. cacheItem.ResyncItemOnExpiration = true; } public void Dispose() { //... } } |
直写的工作方式与直读相同,但用于更新。 当您的应用程序更新缓存时,它会更新您的数据库。 而且,如果您愿意,即使缓存同步更新,Write-behind 也会异步更新数据库。 最后,缓存加载器在缓存启动时被调用,因此您可以使用所需的数据预加载它。
结论
正如你可以看到, NCache,一个开源的 .NET 分布式缓存,比简单的缓存提供更多的功能 Redis 键值存储或 Memcached. 下面是与分布式缓存服务的详细键值存储比较,即 Redis vs NCache 和 Memcached vs NCache.