分布式缓存已被公认为高性能 .NET Web 应用程序的重要组成部分。 这适用于那些需要部署的中间层服务或 Web 组件快速响应的最终用户应用程序。 出于这些原因,微软推出了 AppFabric,一个内存分布式缓存,为使用 .NET Framework.
AppFabric 缓存主要用于存储 ASP.NET 会话状态数据并提供基本的对象缓存功能。 但即使缓存是任何 N 层系统不可或缺的一部分,微软在博客中写道 AppFabric 支持结束 截至11年20月XNUMX日17 适用于所有版本。 这对于 .NET 堆栈采用 AppFabric 移动到更好的、受支持的分布式缓存。
那么,结局支持什么 其实是说? 它的意思是:
因此,这意味着您将使用 AppFabric 风险自负。 Microsoft 不对事故或错误负责。 因此,我们必须评估业务运营是否可以因无法快速解决的错误而导致停机。
这样的问题可能会驱使您寻找替代方案。 如果您准备好使用替代方案,那么有一个可以提供从当前设置到 .NET 分布式缓存的无缝迁移,只需最少的代码更改,因此根本不会引入任何错误。 这种替代的分布式缓存不仅支持无缝迁移,而且速度更快,提供的功能比 AppFabric.
NCache 作为替代方案是一个强有力的选择。 微软实际上推荐 NCache 在他们的 公告 结束 AppFabric 支持。 NCache 获得此推荐,因为它在 .NET 社区中被广泛使用,并且一直是 .NET 分布式缓存的市场领导者 10年运行. NCache 提供卓越的性能以及广泛的功能,包括:
其他好处 NCache 包括易用性(它被领先的分析公司评为最容易使用的分布式缓存)通过其专用的 GUI 工具提供强大的管理和监控功能,并且它可以作为开源(在 GitHub 上)以几乎零成本的形式提供迁移前后。 具有官方支持的开源和企业版可在本地和云端(Amazon Web Services 和 Azure)中使用。
而 Redis 是一个很好的内存缓存, Redis 社区指出 Redis 尚未准备好 Windows,尽管有可用的 Redis Windows 端口。 Redis 不完全可扩展,也不提供高可用性功能。 Redis' 监控和管理工具集只是 CLI。 NCache 提供了许多优势 Redis 如图所示 视频链接 (和这张幻灯片分享 智能向导) 包含。
满足任何操作环境的需求, NCache 提供三种迁移 .NET 应用程序的方法 AppFabric 至 NCache; 每种方法都有其自身的优势。
三种迁移方法是:
NCache AppFabric Wrappers 提供了更顺畅、更无缝的迁移,但通过直接 API 调用进行迁移提供了更多控制,并允许您利用 NCache.
对于那些寻求从 AppFabric,这个包装器提供了有史以来最简单的迁移。 在 .NET 应用程序中只需要进行三个小的更改即可 NCache 完全不引入任何可能的错误。 这些变化是:
<appSettings>
<add key="region1" value="myPartitionedCache"/>
<add key="Expirable" value="True"/>
<add key="TTL" value="5"/>
</appSettings>
using Microsoft.ApplicationServer.Caching.Client;
using Microsoft.ApplicationServer.Caching.core;
使用:
using Alachisoft.NCache.Data.Caching;
就是这样! .NET 应用程序中不需要任何其他代码更改。
运用 NCache Open Source 允许您从 AppFabric 免费,因为这两种产品都是免费的。 NCache Open Source 与企业版相比,具有更有限的一组功能,但核心缓存性能没有任何下降。
为了便于迁移,单独的版本 AppFabric 包装器提供给 NCache OSS,兼容开源API。 鉴于较少的功能 NCache Open Source是, NCache Open Source wrapper 围绕缺少的功能工作,其中包括:
NCache Open Source 包装器 AppFabric 通过将每个对象封装在另一个类中,克服了维护项目版本控制的挑战。 这是通过在修改后的包装器中引入一个名为 MetaDataCapsule 的新类来完成的。
namespace Alachisoft.NCache.Data.Caching.Util
{
[Serializable]
class MetaDataCapsule
{
private object value;
public ItemVersion CacheItemVersion { get; set; }
public string Group { get; set; }
public object Value { get { return this.value; } }
private MetaDataCapsule(object value, ItemVersion version, string group)
{
this.CacheItemVersion = version;
this.Group = group;
this.value = value;
}
public static MetaDataCapsule Encapsulate(object value, string region)
{
return new MetaDataCapsule(value, 1, region);
}
}
}
这有助于维护对象的项目版本并在需要时携带其他有用的信息。 该类被标记为可序列化,因为它需要通过网络传输。
为了确保项目版本和对象在不同或相似应用程序的所有多个实例中的一致性,使用了分布式锁定。 分布式锁定是 NCache 这允许多个应用程序访问和修改同一资源,而不会影响数据一致性并避免任何可能的竞争条件。
LockHandle lockhandle = null;
MetaDataCapsule oldMetadata;
bool lockAcquired = GetLock(_key, ref lockhandle, out oldMetadata);
if(!lockAcquired)
{
_NCache.Unlock(key);
throw new DataCacheException("Unable to acqurie lock to update Item Version");
}
//Return in case of version provided
if (oldVersion != null && oldMetadata.CacheItemVersion == oldVersion._itemVersion)
{
_NCache.Unlock(key);
return null;
}
if (lockAcquired)
(_item.Value as MetaDataCapsule).CacheItemVersion = ++metadata.CacheItemVersion;
_NCache.Insert(_key, _item, lockhandle, true);
总之,在每个 Put 操作上:
如果另一个应用程序尝试修改相同的密钥,则在上述情况下锁定将确保没有其他应用程序可以更新或删除该项目。
在上面的代码中,有一个名为GetLock的方法,实现如下。
// <summary>
// Tries to acqurie lock and return LockHandle and MetaDataCapsule object.
// If LockHandle is provided uses that instead.
// <para>Default Lock Timeout (default 5 seconds), Retry Count (default 3)
// and retry interval (default 100 ms) is set when Cache Handler is instantiated.
// </para>
// </summary>
// <param name="key">Formatted Key i.e compile from formatter</param>
// <param name="lockHandle">Either provide a lock or keep it null to acquire a new lock
// </param>
// <param name="metadata">The returned object for internal use</param>
// <returns>true if lock was acquired</returns>
internal bool GetLock(string key, ref LockHandle lockHandle,
out MetaDataCapsule metadata)
{
//Item is locked
int count = _retries;
while (count != 0)
{
//If lock was provided attempt to acquire the lock from the given handle
if (lockHandle == null)
{
lockHandle = new LockHandle();
}
object obj = _NCache.Get(key, _defaultLockTime, ref lockHandle, true);
//obj is null of the lock was not acquired
if (obj == null)
{
count--;
Thread.Sleep(_retryTimeOut);
}
else
{
metadata = obj as MetaDataCapsule;
return true;
}
}
lockHandle = null;
metadata = null;
return false;
}
GetLock 方法将尝试三次获取锁。 如果失败,它将返回“null”,让调用方法处理此异常。 因此,在分布式锁定的帮助下, AppFabric 包装器 NCache Open Source 维护客户端应用程序插入的缓存项版本,包括异常情况。
由于开源版中缺少一些企业特性,以下功能被标记为“废弃”并标记为“抛出编译错误”,以确保代码更改并避免任何意外。
因此,如果您的应用程序严重依赖这些功能,请选择 NCache Enterprise 版本可能是实现更顺畅、无缝和无错误迁移的最佳选择。
对于想要充分利用许多 NCache Enterprise 功能,您可能更喜欢直接调用 NCache API 而不是使用包装器。 您还可以使用 AppFabric 直接使用的包装器 NCache 以及。
无论哪种方式,建议您分两个阶段进行迁移。 在第 1 阶段,继续使用您的 AppFabric 功能,但将您的缓存替换为 NCache. 在第 2 阶段,实施额外的、新的 NCache 中不可用的功能 AppFabric.
在这个阶段,你的重点只是替换 AppFabric. 因此,了解这两个分布式缓存的行为方式很重要(请参阅下面和 参考部分 在末尾)。 如前所述, AppFabric 将数据存储在特定机器上的区域中。 另一方面,要复制您的区域数据 NCache 您可以为每个 AppFabric 区域,或者您可以创建 NCache 举行的团体 AppFabric 区域数据。
NCache Groups/Sub-Groups 提供了对缓存项进行分组的各种方式。 由于区域驻留在命名缓存中, NCache 使用组来重现此行为。 唯一的区别是在 AppFabric 一个键只需要在一个区域内是唯一的,而不是在整个命名缓存中。 而在 NCache,密钥在整个缓存中必须是唯一的,它属于哪个组都没有关系。 如果每个键都预先加上区域名称,则可以快速克服这种障碍。
例如:
In AppFabric,基本的添加操作如下所示:
// AppFabric API
regionCache.Add(stringKey, stringValue);
并在 NCache 基本命令没有什么不同,除了可以在命令中将区域名称指定为组:
// NCache API
cacheInstance.Add(regionName + ":" + stringKey, stringValue, regionName);
// Where regionName is as Group
在这里,每个键都带有区域名称,以实现缓存键之间的唯一性。 一个组被分配给键以便在执行搜索操作时更快地检索或便于使用 SQL 查询检索数据。
对缓存项进行分组的另一种方法是完全放弃区域与组的相关性,并为每个区域使用单独的缓存。 为了获得相同的结果,每个区域都被分配一个单独的缓存,可以存储对应于缓存的区域名称映射。
// NCache API
cacheInstance = map.get(regionName);
cacheInstance.Add(stringKey, stringValue);
在这个例子中,不需要在缓存键之前附加区域键,因为缓存在 NCache 即使它们位于同一个集群中,它们也是互斥的。
如果您的应用程序必须处理许多区域(例如超过 15 个),那么最好将区域用作组,因为每个集群 15 个缓存是建议的最大缓存数量(即使集群在逻辑上可以托管无限数量的缓存) .
在下一阶段,您可以利用以下功能 NCache 提供了哪些 AppFabric 和 Redis 缺少。 特点如:
数据库同步对于任何好的分布式缓存来说都是一个非常重要的特性。 由于缓存的大多数数据都来自关系数据库,因此总是存在其他应用程序或用户可能更改数据并导致缓存数据过时的情况。
应用程序通常希望获取这些数据的子集,如果他们可以使用类似 SQL 的查询语言搜索分布式缓存并将对象属性指定为条件的一部分,那么分布式缓存对他们来说更加有用。
许多人将分布式缓存用作“侧面缓存”,他们直接从数据库中获取数据并将其放入缓存中。 另一种方法是“缓存通过”,您的应用程序只向缓存请求数据。 而且,如果数据不存在,分布式缓存会从您的数据源中获取数据。 直写也是如此。
与此同时, NCache 还支持 MapReduce,它在内存数据中启用大数据分析,近乎实时地产生结果。
客户端缓存只是客户端计算机上的本地 InProc/OutProc 缓存,但它与分布式缓存集群保持连接和同步。 这样,应用程序性能真正受益于这种“紧密性”,而不会影响数据完整性。
WAN 复制是一项重要功能,因为许多应用程序部署在多个数据中心,用于灾难恢复或区域流量的负载平衡。
WAN 复制背后的想法是,它不能因为 WAN 的高延迟而减慢每个地理位置的缓存。 NCache 提供桥接拓扑来处理所有这些。
支持微软的 AppFabric 于 2017 年 XNUMX 月结束。本白皮书介绍了将 .NET 应用程序从 AppFabric 至 NCache,以及进行此更改的优势。 NCache 是一个稳定的、功能齐全的分布式 .NET 缓存,可作为 Azure 和 Amazon Web Services 中的开源以及在 NCache 网站。 也提供全面支持。
免费使用 NCache AppFabric 包装器 NCache Open Source or NCache Enterprise,提供最简单、无编码、无错误的迁移方法。 直接调用迁移 NCache API 提供更多的数据控制并启用所有 NCache 特征。 本白皮书中介绍了所有迁移方法。
请查看这些附加资源以满足您的评估和产品需求。
地区 in AppFabric 是存储在缓存实例中的键值对的逻辑容器,该实例绑定到一台服务器计算机。 因此,无法分发区域内的数据。 这种架构结构声称可以实现更快的获取。 但与分布式缓存相比,它显着降低了整体性能。
NCache 其核心是分布式缓存。 里面的所有数据 NCache 是分布式的,并且如果 分区副本 使用(PR)拓扑。 PR 提供世界一流的超快速性能和故障转移副本,以实现零数据丢失。
因此,地区在 AppFabric 被配置为单独的缓存 NCache 在不影响任何数据获取能力的情况下。 这 AppFabric wrapper 接管了这种复杂性,并自动将所有区域数据存储在提供的缓存名称中。 唯一的要求是缓存在 NCache 应该是预先存在的。 您通过创建缓存 NCache 经理,一个基于 GUI 的集群管理工具。 创建缓存后,驻留在 AppFabric 区域分布到指定的 NCache 集群。 尽管数据是真正分布的,但您执行高级搜索的能力没有任何妥协,包括 SQL 查询(SQL 查询不适用于 AppFabric 完全没有)。
另一个明显的区别 NCache 和 AppFabric 是两种产品的配置方式。 AppFabric 由应用程序在运行时配置(甚至是缓存创建),相反 NCache 在缓存启动之前配置。 例如,缓存拓扑不能在运行时更改,而其他配置(例如缓存默认过期时间等)可以在以后更改,这些配置称为 hotapply-able。 虽然 NCache 可以使用 .NET 应用程序进行管理(包括创建缓存),但最好从 NCache Manager - 用于管理缓存集群的专用单一工具。 也可以从 CLI 创建、配置和维护缓存。
而 NCache AppFabric-wrapper 提供了将 .NET 应用程序迁移到 NCache,这也是尽可能少的代码更改,一些开发人员仍然更喜欢利用所有功能 NCache 必须提供。 那就是直接调用 NCache API 有帮助。 还可以通过调用 Unwrap 方法来使用这两种方法 AppFabric 包装。
AppFabric 集群不是完全动态的。 依赖于 “领导主机多数规则” 意味着即使一个主要主机出现故障,集群也很容易出现故障。 这些主要主机节点也类似于“主”和“从”架构,因此也不是完全对等的。
NCache 而是 高度动态 并允许您在运行时添加或删除缓存服务器,而不会中断缓存或您的应用程序。 数据在运行时自动重新平衡(称为状态传输),不会出现任何中断或性能下降。 NCache 客户端继续与缓存服务器通信,与服务器状态无关。 即使在数据平衡过程中,集群也能确保客户端操作的执行。
这意味着即使对于 NCache,集群中没有“主”或“从”节点。 有一个“主要协调者”节点,它是最高级的节点。 而且,如果它出现故障,下一个最高级的节点会自动成为主要协调者。 所有这些都不会中断客户端操作。