南佛罗里达代码营 2017

使用分布式缓存扩展 .NET 应用程序

伊克巴尔汗
总裁兼技术传播者

由于事务负载的增长,您的 .NET 应用程序可能会遇到数据库或存储瓶颈。 了解如何使用分布式缓存消除瓶颈并扩展您的 .NET 应用程序。 本次演讲涵盖:

  • .NET 应用程序中可扩展性瓶颈的快速概览
  • 分布式缓存的描述以及它如何解决性能问题
  • 您在哪里可以在应用程序中使用分布式缓存
  • 分布式缓存中的一些重要特性
  • 使用分布式缓存的动手示例

今天我将讨论如何使用分布式缓存扩展 .NET 应用程序。 这个谈话不是关于 NCache. 虽然我会提到 NCache 但主要目的是让您了解问题所在以及如何通过缓存解决这些问题。

什么是可扩展性

好的! 为了完整起见,让我们回顾一下我确定您已经知道它们的一些定义,但是,让我们首先定义什么是可伸缩性。 可扩展性不是高性能。 如果您有五个用户,那么您的响应时间非常好,那就是高性能,那就是高性能。 可扩展性是指您能否在峰值负载下保持同样的高性能。 因此,如果您的应用程序没有五个用户的高性能,那么您还有其他问题。 比我们在那里可以解决的要多。

线性可伸缩性

第二,什么是线性可扩展性。 线性可扩展性更多的是部署定义。

线性可扩展性

当您在多服务器环境中部署应用程序时,假设您有一个负载平衡的环境,如果您可以简单地添加更多服务器以获得额外的事务容量,那么您的应用程序是线性可扩展的。 因此,如果您有 1500 个用户和两台服务器,那么您将获得第三台服务器,比如说 500 个用户,然后当您添加更多服务器时,每个服务器将获得 XNUMX 个用户。 我只是假设性地说,但这是线性可扩展性。 如果你能做到这一点,那么这就是目标,因为你是,你永远不会遇到问题,我相信你是来这里解决的。

非线性可扩展性

非线性可扩展性正好相反,你有一个应用程序架构,你不能购买更昂贵的硬件或更多的服务器来解决这个问题。

非线性可扩展性

你有一些基本的瓶颈,所以当你添加更多的服务器,你的应用程序,一段时间,性能或事务容量会上升,但之后,即使你添加更多的服务器,它实际上也会变慢。 所以,你绝对不想要非线性可扩展性。

什么类型的应用程序需要可扩展性?

这些通常是服务器端应用程序。

应用程序需要可扩展性

这些是 Web 应用程序、ASP.NET,这些可能是 Web 服务 WCF,这些可能是任何 IOT 应用程序的后端。 我们有很多不同的物联网设备与某种后端通信。 这可能是大数据处理应用程序,尽管大数据处理更多的是 Java 活动。 由于 Hadoop,.NET 不是一个非常大的大数据处理,但如果你在做大数据处理,你肯定需要扩展,以及任何其他不属于这一类的服务器应用程序。 我的意思是你可能有很多批处理,如果你是一家大公司,你可能需要在午夜或下一个工作日之前更新一定数量的东西,随着你有越来越多的客户,你拥有数以百万计的客户,你当然需要扩展它。

因此,即使是那些后端应用程序,一个很好的例子可能是客户,您的银行和客户正在将资金从一个账户转移到另一个账户,这通常在晚上以批处理模式在后端处理。 因此,您必须以合同方式在特定时间段内完成。 所以,所有这些应用程序,如果它们没有可扩展性,你就会遇到很大的问题。

什么是可扩展性问题?

幸运的是,应用层不是问题所在。 如果你拥有大部分这些应用程序,你可以在应用程序层添加更多服务器,这没什么大不了的。 问题在于数据存储。 而且,当我使用数据存储这个词时,我指的是关系数据库、大型机遗留数据。 这是您的大部分数据所在的位置,它们无法像应用程序那样进行扩展。 现在, NoSQL database存在的用例之一是扩展,但是,问题在于 NoSQL databases,再一次,我们有一个 NoSQL database 我们自己叫 NosDB. 它是一个开源数据库。 所以,限制 NoSQL database 是您无法将所有数据移至其中,因为它们要求您将数据从大型机或关系数据库中移出,而出于各种原因,可能是技术原因,可能是业务原因,您可能无法做到。

因此,关系数据库将继续成为您的主要主数据源。 有很多用例可以放入大量新数据 NoSQL databases 并且当你这样做时,它们会解决可伸缩性瓶颈。 但是,在大多数情况下,您只能对数据的子集执行此操作。 大多数数据仍然需要保留在您的关系数据库或旧的大型机数据源中。 因此,无论您要解决什么问题,这种可扩展性,您都必须在继续使用关系数据库或遗留大型机的同时解决它。 而且,这就是分布式缓存实际解决该问题的地方。 它允许您继续使用关系数据库大型机数据,同时消除所有瓶颈。

分布式缓存部署

所以,这里有一张图片,如果你有,如果这些是你的关系数据库遗留数据,你可以在应用程序和数据库之间放置一个缓存层。

分布式缓存部署

当您这样做时,您会开始缓存您将经常使用的数据。 而且,大约 80% 的时间您甚至不需要访问数据库。 而且,缓存,因为它是一个分布式缓存,你可以添加越来越多的服务器,它的扩展方式与应用层相同。 因此,您至少有两个缓存服务器,然后您在应用程序层和缓存层之间保持四比一或五比一的比率。 现在,该比率可能会根据您的运营性质而变化。 如果您的每个人,比如说,如果您有一个 Web 应用程序,对于每个用户点击,您都会进行数百次缓存调用,那么当然,比率会发生变化,但大多数时候您不会进行数百次缓存调用。

典型的缓存服务器只是一个低成本的服务器。 它是一个配置的Web服务器类型,双CPU,四核类型的盒子,它只是有很多内存。 大量内存意味着 16 到 32 gig 是相当标准的,超过 32 gig 你通常不必这样做。 虽然,我们有很多客户高达 64 gig,但我们建议不要在每个盒子中拥有更多内存,而是添加更多盒子。 而且,原因是每个盒子中的内存越多,你必须拥有的处理器就越强大,然后你的盒子开始看起来越来越像一个数据库,这不是本意。 您希望尽可能降低成本。

现在,分布式缓存是您希望为所有应用程序放置的基础架构。 因此,就像您拥有一个几乎是通用基础架构的数据库一样,新的最佳实践是拥有一个内存分布式缓存。 它也被称为内存 NoSQL 键值存储。 并且,将其作为您的基础架构和架构应用程序的一部分,因此您总是会去这家商店。 因此,您在访问数据库之前检查商店。 一旦您拥有该基础架构,那么您的所有应用程序都会自动变得可扩展。 因此,您永远不必担心数据库会成为瓶颈。 而且,可扩展性或无法扩展的最大问题是,当您的业务进行大量活动时。

假设您是一家航空公司,您刚刚为夏威夷做了一次特别促销活动。 每个人都在周三登录您的网站,我不知道,开始购票。 所以,他们要搜索航班,他们要买票,你的流量是以前的五倍,突然网站速度变慢了,也许它崩溃了,当然也可能崩溃,如果您的数据库不堪重负,但即使它只是减慢到超出可接受的限制,您的业务成本也会非常高,因为人们会离开。 因此,您确实需要确保为可伸缩性进行规划,以免您的业务想要进行更多活动,他们能够产生业务但您无法在应用程序中进行处理。 而且,如果您拥有正确的基础架构,那么您将永远不会遇到这个问题。

我只是在说明为什么应该使用分布式缓存? 解决了什么问题,然后我们将详细介绍您如何实际使用它。 除了拥有更多内存之外,您通常还拥有双 CPU、四核配置、2 个 XNUMX Gb 或更多的网卡。 的情况下 NCache 这些是 Windows 框,以防万一 Redis 这些是 Linux 机器,具体取决于您是否拥有 .NET 或 Java 应用程序。 我的重点是 .NET,但对于 Java,你也有分布式缓存。 他们称它们为内存数据网格,在 .NET 端它被称为分布式缓存。

分布式缓存的常见用例

好的! 所以,既然我们已经建立了一个案例,说明为什么需要将分布式缓存作为最佳实践基础架构的一部分,无论是从 IT 角度,还是更重要的是从开发角度来看,您都希望构建应用程序。 想到的第一个问题也是,我如何使用这个缓存? 有哪些用例? 我在哪里使用它们? 我的意思是我知道我要使用什么类型的应用程序,但是我要缓存什么类型的数据?

用例

所以,主要分为三类。 第一个是每个人都知道的应用程序数据缓存。

应用程序数据缓存

因此,在应用程序数据缓存中,您正在缓存数据库中存在的数据,您正在缓存它,这就是我们刚刚讨论的内容。 因此,当您这样做时,您实际上是在创建数据的两个副本。 一个在数据库中到主服务器,一个在缓存中,它是临时副本。 当这种情况发生时,主要关注的是什么? 当你有两个副本时会出现什么问题? 他们可能会失去同步。 事实上,人们心目中的一个主要恐惧是,大多数人当你问他们你用缓存做什么时,他们说只读数据很好,我不能冒险处理我的事务数据,数据变化,因为如果出现问题怎么办。 如果我的客户从同一个账户两次提取这笔钱,那会发生什么?

好吧,如果你不能缓存事务数据,那么分布式缓存的价值就会下降很多,因为参考数据只是数据的 80% 或 70%。 80% 或 30% 到 XNUMX% 的数据是您的客户、您的帐户、活动、您的交易数据、每 XNUMX 秒、每分钟更改一次的数据,您可能能够保存在缓存中的数据很短的时间。 所以,如果你不能使用缓存来存储事务数据,那么你真的限制了自己。 所以,一个好的分布式缓存必须保证缓存和数据库始终保持同步。 因此,一旦您对缓存始终与数据库同步感到安心,您就可以缓存几乎所有内容,当您这样做时,您会真正看到很多游戏。

而且,我将对此进行更详细的介绍。

ASP.NET 特定缓存

第二个用例是当您有一个 ASP.NET 应用程序时,您可以缓存某些特定于 ASP.NET 的内容。 而且,这个类别的好处是您不需要编程,因为 Microsoft 有一个框架,可以插入缓存。第一是会话状态。 几乎每个 ASP.NET 应用程序都必须具有会话状态。 有些人专门编程不使用它,这不是一个好主意。 您应该使用会话使您的生活更轻松。

会话非常适合缓存,因为如果您将会话存储在数据库中,您会遇到与数据库不是为存储 blob 而设计的问题相同的问题,这就是会话。 所以,性能真的很慢,更重要的是可扩展性消失了。 出于同样的原因,您希望进行应用程序数据缓存,您也希望将会话也不放在数据库中。 您想将它们放在分布式缓存中。

第二个是视图状态。 如果你没有使用 MVC 框架,如果你还在使用旧的 ASP.NET framework 然后查看状态。 对于那些不知道什么是视图状态的人来说,视图状态是一个加密的字符串,它可能小至一百字节,也可能是数百千字节,生成并发送到浏览器只是为了返回当你回帖时。 所以,这是一次相当昂贵的旅行。 当然,它会降低您的性能,因为要传输更多数据。 而且,还会增加您的带宽成本,因为当您托管应用程序时,上面的管道不是免费的。 因此,当您的客户访问您的 Web 应用程序时,您需要为这里的带宽付费。 因此,从视图状态来看,当您将其乘以数以百万计的请求或您的用户或客户将要进行的交易时,您不想承担很多额外的成本。 所以,这是一个非常好的缓存候选者。 因此,您将其缓存在服务器上,然后发送一个小密钥,以便下次发生错误后,该密钥会返回,并且在页面执行之前,会从缓存中获取视图状态。

第三个是输出缓存,它是 ASP 的另一部分.NET framework 如果您的页面输出没有改变,为什么下次执行它? 因为每次执行页面都会消耗 CPU、内存和所有其他资源,包括数据库。 因此,最好只返回最后一次执行的输出,该输出可能是整个页面,也可能是页面的一部分。 因此,对于所有这三个,您只需插入分布式缓存而无需任何编程。 现在我会告诉你。 但是,这个问题的性质与应用程序有很大不同。

在应用程序数据中,我们有两个数据副本,对吧? 所以,问题是同步。 在这里,您只有一个副本,并且保存在内存存储中。 那么,当您将类似的东西保存在内存存储中并且这是唯一的副本时,最大的担忧是什么。 那个也是! 或者,如果任何服务器出现故障,您只是丢失了该缓存。 因此,对于要存储在缓存中的任何内容。 试想一下,我刚经过的同一家航空公司,我花了半个小时寻找完美的航空公司组合,我正要点击提交,会话丢失,这不是一个好的体验,因为网络服务器刚刚关闭。

所以,为此,当你有内存并且你有这个问题时,你如何解决这个问题? 你有冗余。 您拥有多个数据副本。 因此,良好的分布式缓存必须允许您进行数据复制。 如果没有以智能和高性能的方式进行数据复制,您的缓存再次变得不那么有用。

通过事件共享运行时数据

第三个用例是大多数人不知道的,或者它开始变得越来越流行的是你可以使用,你有这个非常可扩展的内存基础设施。 您可以将它用于通过事件共享运行时数据,它有点像消息传递,但它是一个非常简化的版本,它位于单一数据中心类型的环境中,您可以让多个应用程序使用缓存作为一种方式数据共享的 Pub/Sub 类型。 因此,一个应用程序将某些内容放入缓存中,触发一个事件,对该数据感兴趣的消费者收到该事件,他们可以去消费该数据。

因此,与其将其放入数据库或将其放入具有其自身目的的情况的 MSM 队列类型中。 缓存不能替代 MSM 队列,但在许多情况下,它是一种更简单、尤其是更快、更具可扩展性的基础架构,可以进行基于事件的数据共享。 因此,如果您有多个应用程序需要在运行时相互共享数据的需求,那么您绝对应该将其视为一项功能,一项非常重要的功能。

ASP.NET 特定缓存

我将快速向您展示 ASP.NET 缓存,以及您是如何做到这一点的。 它非常简单,我将实际使用……所以,我有一些示例代码。 所以,例如,如果我要... 所以,我有这个 ASP.NET 应用程序。 您所要做的就是转到 web.config,以防万一 NCache 再次,所有缓存都将几乎相同。 您要做的第一件事是添加一个程序集。 所以,这个程序集是会话状态提供者。 所以,ASP.NET framework 有一个分布式缓存必须实现的会话状态提供者接口。 NCache 已经实现了它,这会将程序集加载到您的应用程序中。

因此,一旦您完成了该操作,接下来要做的就是转到会话状态标签。 事实上,并确保模式是自定义的,并且超时确保是您想要的超时。 的情况下 NCache 那你就放这条线。 其他缓存具有类似类型的信息。 所以,你只是有..万一 NCache 你需要做的就是确保你的缓存被命名,我会告诉你这意味着什么。 但是,只要在您的应用程序中进行如此多的更改,您基本上就可以开始存储您的会话了。 因此,您在应用程序层的每个 web.config 中进行更改,当然,您要确保缓存存在。 然后,一旦你完成了,你就可以开始将会话放入缓存中。

动手演示

我将快速向您展示一个缓存集群。 所以,例如,我有这些......呃,我有这些 Azure VM,我有 demo1 和 demo2,我的缓存服务器 VM 和演示客户端就像应用程序服务器一样。 所以,这就是客户。 缓存客户端是您的应用程序服务器框。 所以,我要……

创建缓存集群

而且,我已经登录了,比方说,我已经登录了演示客户端,我将使用它,以防万一 NCache 我将再次使用这个名为 NCache 经理。 这是一个图形工具。 让我们从一个地方配置缓存。 我会来这里,我会说创建一个新的集群缓存。 所有缓存都命名为 NCache. 所以,我将把我的缓存命名为演示缓存。 我不打算深入探讨这些属性的任何细节。

我将选择我的复制策略作为分区副本。 而且,我将选择异步复制。 我做我的第一个缓存服务器。 我将在这里做我的第二个缓存服务器。 所以,我要构建一个双节点缓存集群。 我只是要挑选一切。 所以,这是形成缓存集群的 TCP 端口,如果有端口冲突,您可以更改它。 我将指定我的缓存服务器要用于缓存的内存量。 我把它当作一场演出,当然,你的会更多。

因此,例如,在这里让我快速向您展示这意味着什么。 我只是要去这部分。

缓存拓扑

所以,把它想象成一个缓存服务器,它有另一个缓存服务器。 因此,分区 1 存在于此。 分区 1 本质上是存储桶的集合。 分区 2 有自己的盒子。 所以,有一种情况 NCache 大约有一千个桶,分布在您拥有的多少个分区之间。 每台服务器都有一个分区,并且每台服务器都将分区复制到不同的服务器上。 因此,如果您有三台服务器,您将看到分区 1 已在此处备份。 分区 2 备份在这里。 分区 3 备份在这里。 副本在以下情况下不活动 NCache. 仅当主分区出现故障时,它们才会变为活动状态。

所以,我在这里指定的是分区的大小。 因此,对于分区副本,如果我在此处指定 1 gig,它将实际使用 1 gig 分区和 1 gig 副本。 所以,总共2场演出。 因此,假设您有 16 gig 的内存,您想要做的就是为操作系统和其他进程留下大约两个或两个半 gig,其余的可以使用。 因此,对于 16 场演出,您可以轻松使用 13 场演出。 所以,做一半一半。 因此,它是一个 32 个半演出的分区大小,当然,您可以拥有 29 个演出,而您再次留下三个演出,您就有 14 个演出的一半,XNUMX 个半演出的分区大小。 然后,当您想要更多存储空间时,而不是仅仅为了添加更多服务器而添加更多内存,因为它更易于管理。 它使事情更具可扩展性。 所以,我要在这里打下一个。

接下来是我的驱逐政策。 我不打算详述这些细节。 而且,我现在要添加客户端节点。 完成后,我将启动缓存。 我要开始缓存,我想向你展示这部分,因为这对剩下的谈话有意义。 所以,它正在启动这两个缓存节点。

模拟压力并监控缓存统计信息

所以,我将打开一堆监控工具,并实际运行这个称为压力测试工具的工具。

压力测试工具

这是一个命令行。 它是一个实际上开始在缓存上进行活动的控制台。 现在,这就像它在模拟您的应用程序。 因此,如果您查看它,您的应用程序正在将会话放入缓存中,每个会话都是一个对象。 所以,你正在添加。 所以,缓存计数是 177,在这个盒子上是 172 和 35。所以,它几乎是均匀的,然后最好备份到不同的…

压力后统计

这个备份在这里 这个备份在这里。 因此,正如您所见,复制是自动发生的。 您的应用程序不必担心。 您所做的只是创建了这个集群,并且在应用层上您只需修改 Web.config,其他一切都会自动发生。 当然,您可以监视这些东西,但缓存是命名的。 因此,在我们的例子中,我将缓存命名为演示缓存。 你可以命名它,实际上你可以有多个缓存。 我们在客户中看到的最常见的配置是他们有三个缓存。 他们将其称为一个缓存,比方说,对象缓存。 所以,这是他们的主要事务缓存。 他们将一个缓存称为会话缓存。 因此,它会将所有会话放入该缓存中。 第三个缓存他们称之为参考缓存。 因此,他们会将更多的参考数据放在参考缓存中。

而且,他们为事务数据与参考数据创建单独的缓存的原因是,对于参考数据,您希望使用此称为客户端缓存的功能来进行缓存。

客户端缓存以获得更好的性能

我实际上是在跳,所以如果我混淆了,请原谅我。 如果你有参考数据,其实让我再退一步。 在拥有分布式缓存之前,人们有这个 ASP.NET 缓存对象。 ASP.NET 缓存对象是本地 InProc 缓存。 它在申请过程中,超快,对吧? 如果你把东西放在自己的堆上,没有什么能比得上这种性能。 一旦你进入分布式缓存,它就不同了,它是一个自动进程缓存。 人们没有意识到的是你的表现实际上下降了。

我们有很多客户最初感到困惑并说,我应该获得性能提升,但我的性能从 ASP.NET 缓存下降到现在慢得多,因为他们必须序列化对象。 如果你有一个大对象,序列化是一个相当大的成本,这是你必须独立于任何特定缓存而产生的成本。 而且,一旦您退出进程缓存,您的性能就会比本地 InProc 缓存慢得多。 但是,它仍然比数据库快。 它几乎比数据库快 10 倍,但几乎可以说比 InProc 缓存慢 10 倍。

因此,人们想要从 InProc 缓存中获得这种好处。 好吧,对于不经常更改的数据,有一个称为客户端缓存的功能。 有些人称它为 Near Cache,尤其是在 Java 方面。

近缓存

此功能本质上是一个本地缓存。 这就像您的 InProc ASP.NET 缓存。 它位于应用程序进程中,也可以只是本地 OutProc 缓存,它不如 InProc 快,但仍比进入缓存层快。 但是,不同之处在于这个缓存知道缓存层。 此客户端缓存是缓存之上的缓存,并且是同步的。 因此,您不必担心我们讨论过的最大问题是如何使缓存与数据库保持同步。 好吧,现在你有了三个数据副本。 一个在数据库中,一个在缓存层中,一个在客户端缓存中。 当然,客户端缓存是缓存层的一个子集。 缓存层是数据库的一个子集。 但是,无论它是什么,它都必须同步。 因此,通过拥有客户端缓存,它又是一个 InProc,它将内容保存在对象形式而不是序列化形式中。 它把它放在你的堆上。 因此,您可以获得与本地 InProc ASP.NET 缓存对象相同的好处,但具有可伸缩性的所有其他好处,因为此客户端缓存将是一个小子集。 您可以指定它应该有多大。 它永远不会跨过那个门槛。

因此,每个客户端缓存中可能有一个 gig,缓存层中可能有 32 个 gig,而数据库可能还有更多。 无论如何,即使有一场演出,因为它是一个移动的窗口,对吧? 所以,无论你在做什么,你都会坚持下去。 有些数据会保留很长时间,有些数据可能会保留几分钟,但在这段时间内,您将进行数百次调用,而不必去缓存层,当然,也不必去数据库。 因此,当您启用客户端缓存时,它是一项非常强大的功能。 您这样做是为了获得更多参考数据。 所以,万一 NCache,您可以通过配置更改指定客户端缓存。 没有额外的编程,但它被映射到特定的缓存。 所以,这就是我们的客户通常拥有三个缓存的原因; 对象缓存、会话缓存和引用缓存。 对于参考缓存,他们使用客户端缓存,而其他两个则不使用。

易于配置客户端缓存

现在,他们为什么不使用会话缓存来做客户端缓存呢? 实际上,因为性能变慢了。 原因是只有当你进行更多的读写操作时才会更好。 因为,在写入的情况下会发生什么? 你在这里写,然后你在这里写,然后你在数据库上写。 所以,你在三个地方写。 因此,如果您必须进行更多写入,它不会增加任何价值。 您更新您的副本,然后仅更新它,然后通知所有其他客户端缓存去更新自己。 这是一个延迟更新,并不是说它只是延迟一两毫秒,而是在客户端缓存的情况下它仍然是延迟更新。 客户端缓存之间没有复制。 客户端缓存仅与缓存层同步,然后缓存层将更新传播到其他客户端缓存。 仅当其他缓存具有该数据时。 因为,在客户端缓存的情况下,每个客户端缓存都有基于您的使用模式的不同数据。

在哪里使用客户端缓存

所以,让我们退后一步,在引用数据的情况下,每个客户端缓存都有自己的一组数据所以,比如说 1 到 1000、500 到 1500 等等。 因此,每个之间都有一些重叠,但它们不是相同的副本。 常见的是它们都是此缓存的子集。 所以,当我更新缓存中的项目编号,比如 700 时,它会在缓存中进行更新,缓存会知道哪些其他客户端缓存具有该项目,并且它们会立即在其他缓存中更新。 但是,只要他们都拥有它。 因此,它并没有真正复制,因为在客户端缓存的情况下它们不是相同的副本。 在会话的情况下,我实际上试图解释的是,在会话的情况下,您必须更新客户端缓存和集群缓存,这两个地方没有附加值,因为对于会话,您进行一次读取和一次写入。 因此,在 Web 请求时,您在执行写入的页面末尾进行读取。

因此,现在必须在两个地方进行写入,而读取将在客户端缓存中完成。 因此,如果您将客户端缓存与会话或其他写入密集型操作一起使用,性能实际上会下降,但如果您将其用于更多读取密集型操作,则性能会大大提高。 这有意义吗?

所以,分布式缓存最大的价值,最快最快,最大的就是会话状态。 几乎每个应用程序都有它。 我刚刚创建了一个双节点缓存集群,你看到它花了多长时间,可能是两分钟,以防万一 NCache. 所以,创建一个缓存集群真的很容易,当然,你想做你的测试和东西。 但是,这真的很容易。 没有工程上的努力。 当没有工程方面的工作时,您的日程安排会更容易处理。 您只需要进行健全性测试即可通过。 我强烈建议,如果您要开始使用分布式缓存,请在开始时将其用于会话状态作为第一步,然后跳转到我们稍后将讨论的对象缓存。

应用程序数据缓存

所以,我们已经讨论了会话缓存。 让我们快速进入应用程序数据缓存。 这是一个典型的 NCache API 看起来很像 ASP.NET 缓存,如果你注意到的话,有一个连接。

Cache cache = NCache.InitializeCache("myCache");
cache.Dispose();
获取数据
Employee employee = (Employee) cache.Get("Employee:1000");
Employee employee = (Employee) cache["Employee:1000"];
bool isPresent = cache.Contains("Employee:1000");
写入数据
cache.Add("Employee:1000", employee);
cache.AddAsync("Employee:1000", employee);

cache.Insert("Employee:1000", employee);
cache.InsertAsync("Employee:1000", employee);
cache["Employee:1000"] = employee;

Employee employee = (Employee) cache.Remove("Employee:1000");
cache.RemoveAsync("Employee:1000");

因此,您可以根据名称连接缓存,然后只需使用该名称创建一个缓存。 这就是我给你演示的原因,以便你明白那是什么意思。 而且,此缓存句柄是您保留的东西,就像您将保留数据库句柄一样。 然后,您使用该 Cache 句柄来执行 Cache.Get。 每一个Get,每一个操作,都有一个key。 在以下情况下,键是字符串 NCache 然后你根据你正在做什么来格式化密钥。 因此,对于单个对象,一个好的做法是只指定类名,也许是属性名和值。 然后你就可以得到它。 因此,有一个 Get 和 Get.Contains、Add、AddAsync。 异步意味着不要等待。

好吧,发生的事情是,在它下面,客户端发生了反序列化。 所以,客户端,我们要做一个 Cache.Add,比方说,你给它一个对象,它是一个员工对象,它将基于标准 .NET 序列化或自定义序列化它 NCache 序列化。 然后,将其创建为字节数组并将字节数组发送到缓存。 NCache 不仅如此,因为您可能需要索引某些属性。 它提取这些值。 是的,它会的。 它会。 它立即。 是的! 您缓存的每个对象都必须经过序列化。

所以,只要你打开应用程序,它就会抛出异常。 如果您使用的是 ASP.NET 缓存对象,则不必序列化。 因此,您几乎可以缓存所有内容,而且很多时候发生的事情是您自己的对象可能更容易序列化,但您可能正在使用一些第三方。 比方说,以前数据表对象没有被序列化,但现在它被序列化了。 因此,如果您使用不可序列化的第三方对象,您将无法控制。 因此,如果您要使用分布式缓存,您将无法捕获它们。 的情况下 NCache,我们有自己的自定义序列化,您可以在其中识别这些对象。 NCache 然后在运行时为您创建序列化代码并在内存中编译它。 因此,这允许您也使用那些不可序列化的对象。 但是,这种序列化会立即发生。 因此,如果没有使用正确的序列化,您的应用程序将无法工作。

异步本质上说不要等待缓存更新。 所以,我可以继续。 我相信缓存会添加这个东西。 因此,他们不会解锁更新可能因数据完整性问题而失败的数据库。 缓存不存在数据完整性问题。 只有当你发生崩溃时它才会失败。 当您内存不足或发生其他事情时。 因此,您几乎可以放心,无论您添加什么,您很可能会将其添加到缓存中。 因此,Async 仍然可以为您提供进一步的提升。 因此,如您所见,API 看起来非常简单。

保持缓存新鲜

那么,当您进行应用程序数据缓存时,您如何保持缓存的新鲜度呢? 这真的很重要。 您可以通过多种方式进行缓存。

保持缓存新鲜

使用基于时间的过期

过期,几乎所有的缓存都支持过期。 有一个绝对到期,您可以为每个项目指定此指定,这是我觉得它在缓存中保留多长时间,这可能是从 15 秒到几小时、几天和几周的任何时间。 而且,这是用于应用程序数据缓存的。 还有另一个到期称为滑动到期,它不是用于将缓存与数据库同步。 这是为了清理。 那么,对于 ASP.NET,我们讨论过的所有瞬态数据,当你处理完这些数据后会发生什么? 您不必担心清理它。 因此,您可以指定一个滑动到期时间,并说如果没有人在这么长时间内使用此数据,假设会话 20 分钟,如果没有人在 20 分钟内使用该会话,则将其从缓存中删除。 所以,这更像是一种清理。

到期有什么风险? 过期实际上是你在猜测。 您是说,我认为我可以在五分钟内完成,但不能保证在那段时间内没有人会更新数据库中的数据,尤其是当您有其他应用程序或其他进程更新数据库时。 因此,过期仅在有限的用例中是好的。

使用数据库依赖

另一个非常重要的特性是您可能在数据库中有意外或不可预知的更新。 如果是这种情况,那么缓存应该能够与数据库同步。 所以,缓存应该知道你的数据库。 它应该成为您数据库的客户端并监视您的数据库是否有任何更改。 ADO.NET 中有一个称为 SQL 依赖项的功能。 有人见过吗?

所以,SQL依赖是什么 NCache 用于成为您的 SQL 服务器或 Oracle 数据库的客户端。 因此,在 SQL 服务器的情况下,您可以使用 SQL 依赖的 SQL 服务器 ADO.NET 特性 NCache 用于从数据库中获取事件。 缓存, NCache 成为您数据库的客户。 它接收事件,然后基于它做自己的事情。 在某些情况下,您没有事件。 因此,假设您有 db2 或 MySQL,它们没有事件。 因此,缓存应该能够进行轮询。 NCache 还支持基于轮询。 所以,你做同样的事情,你在缓存中缓存这个项目,你说这个映射到这个表中的这一行,然后 NCache 将进行轮询,然后如果该数据发生更改,它将再次将其从缓存中删除或重新加载新副本。 但是,这个功能,它给你很多的安慰。

再说一次,我所说的同一件事是您要确保 Cache 始终与数据库同步。 过期仅适用于一小部分用例。

因此,如果您不进行自动重新加载,您将获得缓存未命中。 因此,当您启动 SQL 依赖项时,它会删除, NCache 从缓存中删除项目。 因此,如果您的应用程序需要它,这将是缓存未命中,然后您将被迫从数据库中获取新副本。 如果您不希望在许多电子商务应用程序中出现缓存未命中,因为它们读取数据非常频繁,以至于他们不希望任何事情增加数据库的负载,那么您实际上会使用 SQL 依赖项使用此功能称为通读。

实际上,我需要向您展示一些代码,否则它会开始变得非常无聊。 所以,让我快速向您展示。 所以,我只有一个非常简单的控制台应用程序。 的情况下 NCache,您所要做的就是在此处添加一些程序集。 所以,有 NCache.运行时和 NCache.Web。 然后你指定一些命名空间这两个然后你连接到缓存,你有你的缓存句柄,然后你创建一个对象,然后你做 Cache.Add。 并且,您指定密钥。 这不是一把好钥匙。 我的意思是改变它,但是,你的钥匙应该有它的实际价值。 因此,您执行 Cache.Add 并指定对象。

在这种情况下,我也使用一分钟的绝对到期时间。 因此,您指定绝对到期时间,仅此而已。 这就是您将其添加到缓存中所做的所有工作。 下次您需要它时,您只需执行 Cache.Get,指定相同的键即可取回对象。 绝对到期非常非常简单。 你可以对滑动到期做同样的事情。 虽然,您不必指定一个绝对值,而是指定一个时间间隔,如 10 分钟或 20 分钟。 SQL 依赖是我想向你展示的。 它看起来像什么。 那里! 因此,相同类型的应用程序。 您只需要在此处添加这两个并指定名称空间,然后当您将内容添加到缓存时,即指定 SQL 依赖项。

让我来看看它的定义。 因此,我将在此处将其添加到缓存中。 所以,我有我上次给你看的钥匙。 现在,我将添加一个缓存项,而不是添加对象。 那是一个 NCache 结构体。 因此,它存储实际对象,并且还将存储 SQL 依赖项。 所以, NCache 有一个缓存依赖对象。 所以,我做了一个新的 SQL 缓存依赖。 那是一个 NCache 内部映射到 SQL 服务器 SQL 依赖项的类。 因此,您向它传递一个连接字符串,该连接字符串是您的 SQL 服务器连接字符串,您向它传递一个 SQL 语句。 所以,在我的例子中,我指定选择这个,其中产品 ID 是我的值。 所以,我只是将它映射到产品表中的一行。 而且,通过指定这么多,我现在刚刚告诉 NCache 成为 SQL 服务器的客户端。 并且,如果此更改,如果数据库中的此行更改,则删除此项目。

所以,这取决于 SQL 语句是什么。 因此,如果序列方法仅包含一行,则它映射为仅执行一行,这就是它的样子。 通常您不能在此进行联接,这是 ADO.NET 中 SQL 依赖项功能的限制,但是对于单个表,您可以轻松地执行此操作。 所以,这就是你将如何做......

所以,SQL Server 有一个叫做 SQL 代理的东西。 因此,它实际上是在 SQL Server 端创建一个数据集或数据结构来监控这些数据集。 因此,您创建的所有 SQL 依赖项,SQL 服务器都会创建数据结构来监控数据集。 并且,基于此,它会向您发送 SQL 通知。

因此,您必须在 SQL 服务器端进行配置,因为这也是一个安全问题,因此您的数据库必须参与配置 SQL 服务器,但这非常简单。 我的意思是服务器上不需要编程或任何东西,只是配置。 所有的东西都由客户端处理。

通读和通写

好的! 所以,我们已经完成了 SQL 依赖。 我想告诉你,如果你不想从缓存中删除这个项目,你可以通过通读来重新加载。 所以,通读是另一个非常非常强大的功能。

读通写通

通读是服务器端代码。 实际上,通读是您在缓存集群上运行的代码。 因此,您实际上注册了您的代码,它在缓存集群上运行。 它被称为双 NCache. 而且,通读的价值……让我首先向您展示通读的样子,然后我将向您展示其价值是什么,我的意思是您为什么要通读。 所以,这就是典型的通读的样子。 这是一个 IReadThrough 接口。 您执行 InIt 以便可以连接到数据源。 当然,您进行了一次处置,然后从源头加载。 它传递您的密钥,它期望并返回一个缓存项目。 因此,缓存项包含您的对象和一堆其他东西,您可以在其中指定到期时间和其他东西。 非常简单的界面。

这被称为 NCache 因此,您实现了这个接口并注册了您的程序集。 的情况下 NCache,您使用缓存注册您的程序集,现在当您执行 Cache.Get 并且缓存中不存在该项目时,缓存实际上会, NCache 将调用您的通读并从您的数据源中获取它。 您的数据源可以是数据库,也可以是大型机,任何数据源。 因此,通过通读,您可以确保缓存始终包含数据以及应用程序看到的内容。 所以,这是一个好处。

第二个好处是重新加载……所以,你实际上可以结合阅读。 因此,您可以在到期和数据库同步时,否则该项目将从缓存中删除并且您不希望它删除,因为无论如何您只是要重新加载它。 那么,为什么不让缓存以这种方式为您重新加载它,因为如果您想一想,您的缓存中有数百万个项目,而且它们都会一直过期,对吧? 因为这就是你配置它的方式。 而且,你有一个电子商务和一个非常高流量的应用程序,每次有东西过期时,你都会同时收到很多请求。 他们都将进入数据库。 所以,突然间数据库流量无缘无故地增加了,即使你只是,你也不需要它在缓存中。

因此,由于这种情况一直在发生,尽管有缓存,您仍会看到数据库流量激增。 因此,这就是重新加载意味着它永远不会从缓存中删除的地方。 它只是得到更新。 因此,您的应用程序永远不会进入数据库。 他们将继续获取旧副本,直到您对其进行更新。 因此,您突然删除或处理了这个问题,即使您拥有缓存,但由于过期或数据库同步,您会看到数据库流量出现大量峰值。 所以,通过让缓存通过读取重新加载它,真的让它变得非常强大。

当然,通读的另一个好处是你在集中化,你在简化应用层,因为越来越多的数据库访问是由缓存完成的。 因此,如果您有多个应用程序访问相同的数据,您可以真正将数据访问集中在缓存层中。 当然,你不能对所有数据都这样做,但你可以对很多数据这样做。

直写的工作方式与通读相同。 让我去直写。 它以同样的方式工作。 它有一个直写提供程序,同样是 InIt,已处理,现在不是加载,而是对数据源的写入,它有另一种类型的批量写入。 直写,一个好处与通读相同,你可以集中所有内容。 第二个好处是您可以执行写入操作,即更新缓存,正如我所说,它比数据库快十倍,然后您要求缓存去更新数据库。 而且,write-behind 本质上与 write-through 相同,但是以异步方式完成的。 这是一个被创建并被处理的队列。 该队列也被复制以防万一 NCache. 因此,如果任何一台服务器出现故障,任何更新都不会丢失。 但是,write-after 确实加快了应用程序的速度,因为,我的意思是,您已经通过缓存来完成所有读取操作,对吗? 因此,现在大约 70% 到 80% 的读取或事务将进入缓存。 为什么不加快写入速度呢? 如果你能以一种后写的方式做到这一点,如果你能负担得起异步写入。 如果数据在您负担不起的地方过于敏感,那么您进行直写,那么您只会获得第一个好处,即代码的集中化。 更快性能的第二个好处只有在您可以执行异步操作时才会出现。

结论

整个想法是,当你开始进行缓存时,不要认为缓存只是一个简单的键值,我的意思是,我这样做的全部目的是首先让你相信你真的需要一个分布式缓存作为您的基础架构和应用程序架构。 如果您希望应用程序扩展,您必须独立于您使用的缓存产品来整合它,我的意思是,您应该拥有它。 目前对于 .NET 人来说,市场上的选择是 NCache 这是一个开源的,也是商业的。 有 Redis 微软至少在 Azure 上提供了这一点。 在 Azure 上,它是一个托管缓存服务,在它之外你必须安装它,它主要安装在 Linux 上,除非你使用不受支持的开源版本。 在 Java 方面,缓存有更多选择。 所以,这是第一个。

第二个目标你应该明白,它不是一个简单的键值。 您希望确保您可以缓存各种数据并处理各种情况,这才是您真正受益的地方。 而且,我什至还没有进入另一部分,因为我实际上已经没有时间了,例如,你如何进行运行时数据共享以及你想要确保的一些架构事情是什么缓存始终是动态的,因此您可以进行配置。 它是您的数据中心的一部分,是您的生产环境的一部分。 因此,任何不允许您在运行时进行更改的缓存都不是一个很好的选择,因为。 然后你会遇到很多停机时间,我们有客户每年安排一次停机时间,你知道的。 所以,我们的一些客户甚至没有这个,因为他们有如此高的可用性。

高可用性

他们甚至想在不停机的情况下将缓存本身升级为新版本。 所以,我的意思是,这取决于您的业务需求。 但是,所有这些都必须考虑在内,现在很多人都有多个数据中心。 至少出于 DR 目的,然后还用于地理负载平衡,如果有,您希望您的数据库能够复制,对吗?

万复制

那么,为什么缓存不能支持多个数据中心呢? 因为,缓存可以做的越少,您必须做的事情就越多。 这是底线。 因为,您的应用程序需求不会改变,缓存必须适应。 所以,请记住所有这些。

所以,有一个比较 NCache 和 Redis.

redis航班吗ncache

它们都是开源的。 NCache 还有企业版。 所以,基本上如果你的.NET, NCache 非常适合。 在里面 NCache, N 代表 .NET,底线,我的意思是这就是我们对 .NET 的承诺。

接下来做什么?

 

注册每月电子邮件通讯以获取最新更新。

联系我们

联系电话
©版权所有 Alachisoft 2002 - 版权所有。 NCache 是 Diyatech Corp. 的注册商标。