标准差 2017 伦敦

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

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

如果您正在增加数据交易量、会话量或对象大小,那么本次演讲适合您。 了解如何使用应用程序和数据库之间的分布式缓存来提高应用程序性能。 本次演讲涵盖:

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

概述

大家好,我是伊克巴尔汗。 我是技术布道者 Alachisoft. 我们是制造商 NCache. 有多少人听说过 NCache 前? 好,好数字。 今天的主题是使用分布式缓存扩展 .NET 应用程序。 这不是关于 NCache,它是关于 .NET 应用程序面临的整体可伸缩性问题以及如何解决这个问题。

我更喜欢互动性更强的讨论。 所以,不要等到最后才提问,如果你在我说话的时候有问题,请举手。 我将通过架构和实际代码的组合,我也会向你展示 NCache 作为缓存外观的示例。

什么是可扩展性?

因此,让我们先了解一些定义。 我相信你们中的大多数人已经知道这一点,但什么是可扩展性? 可扩展性不是应用程序性能。 它是峰值负载下的应用程序性能。因此,如果您的应用程序在 5 个用户的情况下执行超快,那么它不一定具有可扩展性,除非它在 ​​5,000 或 50,000 或 500,000 个用户下执行超快。 当然,如果您的应用程序在 5 个用户时不能快速执行,那么除了可伸缩性之外,您还有其他问题。

线性可扩展性与非线性可扩展性

线性可扩展性更多的是一种部署架构。 您的应用程序是否以这样一种方式构建,即您可以在负载平衡的环境中不断添加更多服务器,然后随着您添加更多服务器,您会增加事务容量。 顺便说一下,当我使用可伸缩性这个词时,我指的是事务可伸缩性,而不是可伸缩性的数据。 我们不是在谈论海量数据。 我们不是在谈论 TB 或 PB 的数据。 我们正在谈论很多活动。 因此,如果您的应用程序以一种可以添加更多服务器的方式构建,并且随着您添加更多服务器,您的容量会以线性方式增加,那么您就是线性可扩展的。

如果没有,那么你有更多的对数曲线,对于那些还记得他们大学微积分的人来说,这条曲线的问题是你会看到增加,但在某个点之后添加更多服务器实际上没有任何好处,实际上会降低性能,因为您的应用程序中存在一些不会消失的瓶颈。 所以,你绝对不希望是非线性的。

哪些应用程序需要可扩展性?

那么,哪些应用程序需要可扩展性? 当然,这些通常是服务器应用程序。 Web 应用程序,ASP.NET,现在是 ASP.NET Core 还。 网页服务。 同样,您可以通过 WCF 来完成。 您可以使用 ASP.NET Web API 或 ASP.NET Core 网络 API。 也就是说,Web 服务通常是物联网的后端,这在当今是一个非常快速的新兴领域。

这些也是大数据处理应用程序。 所以,如果你有很多数据,那么这就是可扩展性的数据部分的来源,但即使在那里,它也不是关于数据,而是关于你能以多快的速度处理它。 因此,如果您有一个大数据处理应用程序,它需要扩展。 大多数大数据处理应用程序通常不在 .NET 中。 它们更多地在 Java 方面,而我的重点更多地放在 .NET 应用程序上。 但是,从概念上讲,大数据处理应用程序也是需要可扩展性的。

最后,任何其他服务器应用程序。 您可能是一家金融机构,您可能是一家大型银行,您有数百万客户,他们打电话、更改地址、发行新卡或您需要处理的任何事情,也许他们想要转移资金而您需要出于合规目的,在特定时间范围内处理所有这些请求。 因此,您有很多这样的后端批处理流程正在进行,它们需要在非常短的时间内处理越来越多的事务,就您每晚只有几个小时而言。 所以,任何服务器应用程序。 因此,如果您拥有这些应用程序中的任何一个并且它们需要可扩展性,那么您今天就来对地方了。

可扩展性问题

那么,什么是可扩展性问题? 好吧,应用层不是问题。 在我提到的大多数应用程序中,应用程序层似乎工作得非常好。 您可以添加更多服务器。 您通常有一个负载平衡的环境。 如果您有一个 ASP.NET 应用程序,您将在顶部有一个负载均衡器,并且您将拥有一组服务器,负载均衡器将流量发送到您需要更多流量,因为您需要处理更多用户,您只需添加更多服务器。 所以,这很简单。

但问题是您的数据库是关系型数据库还是大型机数据,它们都成为了瓶颈。 而且,关系并不意味着任何一个特定的数据库。 它可以是 SQL 服务器,也可以是 Oracle、MySQL、Db2 等等。 所有关系数据库都具有无法扩展的固有弱点。 所以,这就是为什么 NoSQL 运动开始了,事实上我们甚至在 .NET 空间上也有一个产品,叫做 NosDB 这是一个开源 NoSQL database 但是, NoSQL databases 并不总是答案。 我的意思是他们肯定解决了可扩展性问题。 从技术上讲,如果您使用 NoSQL database 您不会遇到可扩展性瓶颈。 但是,问题是由于技术和业务原因的结合,您无法将所有数据移到关系或遗留大型机之外 NoSQL.

所以, NoSQL 更多的是我们所说的新数据,你知道的。 由于各种原因,传统的业务数据仍然驻留在关系数据库中。 所以,这意味着你必须在使用关系数据库的同时解决这个问题。 你不能说我只是要从我的图片中删除关系数据库。 事实上,甚至我们的客户都没有完全进入 NoSQL. 他们将一些数据移入 NoSQL. 甚至像 MongoDB 这样的大玩家,他们的故事与迁移到的人一样 NoSQL database 将一些数据移动到 NoSQL 他们仍然将传统数据保留在关系数据库中。

分布式缓存部署 (NCache)

因此,您需要解决图中关系数据库的问题,这就是 分布式缓存 进来。它实际上经常给你同样的好处 NoSQL database. 事实上,如果你仔细想想,它是一个 NoSQL 内存中的键值存储。 所以,你知道,如果你调查过 NoSQL databases,有 JSON 文档数据库,有键值存储,有图形数据库,还有其他类型。 所以,键值存储,如果它是一个......分布式缓存唯一的事情是它不做持久性,它都在内存中。 它是键值存储。 而且,它分布在多台服务器上,因此它可以为您带来同样的好处,它可以扩展,因为您可以添加更多服务器。 因此,将其视为此处的应用程序层。 这里是应用层,然后通常是这里某个地方的负载均衡器。 而且,当您在该层中添加更多服务器时,数据库将变得越来越承受压力,除非您在两者之间放置一个缓存层。

图1 - NCache 建筑

缓存层的扩展就像应用层一样。 它没有瓶颈,因为你只是不断地添加越来越多的盒子。 数据分布在多个服务器上。 顺便说一下,这些都是低成本服务器。 这些不是高端数据库类型的服务器。 事实上,我们的客户……典型的配置是大约 16 GB 的 RAM,大约 8 个核心盒,就像一个典型的 Web 服务器盒,但只是更多的内存。 16 gig,16 到 32 gig,我们甚至不建议超过 32。事实上,64 gig 几乎是我们向客户推荐的最大值。 我们会说,添加更多服务器。 这是为什么? 因为,如果你将内存增加太多,.NET 就会有这个东西叫做垃圾收集。 而且,垃圾收集需要大量的处理能力。 所以,你拥有的内存越多,它需要做的垃圾收集就越多,你的 CPU 必须变得越快,然后你的缓存就不会变得越来越像数据库,而且它变得越来越昂贵。 因此,最好拥有更多的服务器而不是拥有一些高端服务器。

因此,分布式缓存本质上形成了一个服务器集群。 这通常是一个基于 TCP 的集群,该集群意味着集群中的每台服务器都相互了解,并将资源集中到一个逻辑容量中。 拥有集群意味着当您需要增加容量时,您只需将另一台服务器添加到集群中。 或者,当您需要减少容量时,您删除了一台服务器。 而且,当您拥有这个缓存层时,它就是一个内存存储,因为您不需要持久化数据。 这不是一个永久的商店。 永久存储仍然是数据库,因为它是内存存储,它还需要提供数据复制。

整幅图的目标是在大约 80% 的时间里访问缓存。 因此,如果您可以想象,如果您在 80% 的时间里访问缓存,您的数据库将完全没有压力,您知道的。 您确实可以大大提高可伸缩性。

问题:应用程序是否仍然不必与数据库谈太多?

实际上并没有。 因此,这取决于数据。 但是,大多数应用程序数据属于参考数据或不每隔几秒更改一次的事务数据的类别。 它可能每隔几分钟就会改变一次。 因此,对于所有这些数据,您执行的读取操作要比写入操作多得多。 因此,第一次读取进入数据库,甚至还有一些功能,例如 NCache 有一个功能,您可以使用数据预加载缓存。 因此,您可以使用您认为将拥有的所有数据来预热缓存,然后即使没有命中流量,也没有命中数据库。 但是,这取决于数据。 例如,如果您有其他类型的数据,比方说,如果您要在其中存储会话,那么每次读取都会有一次写入。 所以,这取决于我会详细介绍这些细节,但这是一个很好的问题。

嗯,你不会的原因,因为缓存加载数据并将其保存在缓存中。 因此,缓存和数据库之间的流量非常少。 正如我所说的那样,80% 的时间读取完成并且缓存有数据。 因此,当您缓存它时,您会将其缓存一段时间,并且在此期间,缓存不会每次都进入数据库。 但是,应用程序每次都会进入缓存。 所以,即使你有很多流量,它也会全部进入缓存,突然间数据库变得很轻。

实际上,每个盒子都有分区存储不同的数据,并且还内置了一些冗余以提高可靠性,但我会更详细地介绍。

因此,这张图片(图 1)旨在让您相信,在当今的高可扩展性环境中,分布式缓存有点像事实上的最佳实践。 因此,如果您设计应用程序,请记住缓存。 哪个缓存都没有关系。 那是一个单独的讨论。 第一个讨论是您需要以一种将要使用分布式缓存的方式设计应用程序。 如果您这样做,并且您可以确信当业务需要您的应用程序执行时,应用程序不会阻塞。

而且,如果您不提前计划,那么无法扩展的真正不利之处在于,当业务确实做得很好时,就会出现这个问题。 想象一下,如果您是一家航空公司,并且您刚刚在某个度假胜地进行了这个周末的促销活动,并且数百万新用户正在访问网站进行航班搜索并可能购买机票。 如果您的网站性能在每点击一分钟后开始变慢,您就会失去客户。 如果情况变得更糟,您的应用程序开始崩溃,因为数据库刚刚阻塞,您就会失去很多业务。 所以,你需要提前计划。 即使您今天没有遇到这个问题,而且这与性能无关。

许多人认为,使用缓存是因为它会提高性能。 它确实提高了性能,但这些天数据库非常快。 如果您只有这五个用户。 我还没有听到有人抱怨数据库运行缓慢。 所以,问题不在于性能。 问题在于可伸缩性,因为只有一台数据库服务器,而您可以在应用层添加更多服务器,然后突然数据库成为瓶颈。

问题:我们应该为缓存集群使用虚拟机还是物理机?

非常好的问题。 我正要谈这个,我忘了,你问很好。 所以,这些可能是物理盒子。 我们仍然有拥有物理盒子的客户,但越来越多的客户正在转向虚拟机,现在新趋势是容器。 因此,至少您将拥有虚拟机。 因此,每个缓存服务器都是一个 VM。 因此,您至少有两个缓存服务器 VM。 正如我所说的,每个演出 16 到 32 个演出。 当然,您不希望将两个 VMS 都放在同一个物理盒子上。 因为,那么您将失去高可用性优势。 因为,如果该框崩溃,则两个 VMS 都消失了。

还有一个问题。 那么,物理数据是存储在内存中的吗?

在记忆中。 正是,正是。 都是内存存储。 而且,因为它是一个临时存储,你可以将它存储几分钟、几个小时、几天、几周,你知道,你不会永久存储它。 永久存储仍然是数据库。 不管那是什么。 正如我所说,它可能是一个遗留的大型机,它可能是关系型的,它可能是 NoSQL.

即使 NoSQL database,您应该使用分布式缓存。 因为 NoSQL 不像分布式缓存那么快,因为我们拥有我们所知道的两种产品。 我们做基准测试。 它仍然快 10 倍。

我不熟悉 NoSQL database,所以我只是想知道,为什么它的性能比关系数据库好?

它可以扩展更多,因为它还分布在多个服务器上。 因此,就像分布式缓存可以有 5、10、15、20 个服务器一样,您可以使用 NoSQL database. SQL 不能有 20 个服务器。 对于主动-被动或主动-主动,您可能有 2 个,但仅此而已。 你知道,你不能真正扩展。 因此,这是出于可扩展性的原因。

因此,无论是虚拟机还是现在容器在管理方面变得越来越流行,这可能是本地的,也可能是云中的任何环境。

分布式缓存的常见用途

所以,我希望这张图片(图 1)能让你相信你们需要使用缓存。 所以,现在你确信了,让我们说。 接下来的问题是,我该如何使用它? 我在哪里使用它,你知道吗? 因此,您可以在三个常见的地方使用缓存。

应用数据缓存

第一个是我到现在为止一直在谈论的,它是应用程序数据,也就是这张精确的图片。 你在这里缓存数据,这样你就不必去数据库了。 唯一要记住的是 缓存应用程序数据 是现在数据存在于两个地方。 一个是缓存,一个是数据库。 当数据存在于两个地方时,会出现什么问题? 同步。 所以,这是一个很大的问题,以至于大多数人都害怕使用缓存,而不是只读数据。 如果您问一个普通人,您是否考虑过使用缓存或者您是否正在做任何缓存? 人们有时会在内存存储中构建这些哈希表或一些,他们只会放置只读数据。 在整个应用程序中或在非常舒适的时间范围内永远不会改变的数据。 那么,只读数据或参考数据仅占总数据的 10-15 %。 因此,它肯定会给您带来很多好处,但真正的好处是您是否可以缓存所有数据。 这意味着你真的需要能够处理......

一个好的分布式缓存必须处理同步。 因此,它必须确保缓存始终是新鲜的。 因此,您对缓存有信心,无论您从缓存中读取什么都是该数据的最新副本。

而且,如果您没有信心,您将被限制为只读数据,这实际上会最大限度地减少或降低缓存的价值。

ASP.NET 特定缓存

所以,第二个好处是 ASP.NET 特定缓存. 我不会进入 ASP.NET Core 在这个时候,但我会简单地谈一谈。 但是,对于 ASP.NET 缓存,您可以在三个地方执行此操作,现在至少有两个。 如果你有 MVC 框架,那么你就没有 View State,但是,每个 ASP.NET 应用程序都有会话,并且会话必须存储在某个地方。 默认情况下,它们要么存储在内存中,即 In-Proc,它位于 ASP.NET 应用程序或 SQL 服务器的工作进程中。 状态服务器在云中不可用,它只是在本地,所有这些都有问题。 有些存在可扩展性问题。 实际上,所有这些都存在可扩展性问题。 有些还存在性能问题。 像 SQL 数据库也有性能问题。

因此,分布式缓存的一个非常好的用例是将这些会话放入缓存中。 您知道,这些会话是存储的……如果您将它们存储在 SQL 中,它们将存储为 blob。 而且,关系数据库不是为 blob 存储而设计的。 但, NoSQL 或键值存储,值是 blob。 因此,它非常适合分布式缓存。 当然,您还必须解决……越来越多的人将使用多数据库或多个数据中心进行灾难恢复或负载平衡,地理负载平衡。 因此,您还需要解决该问题。

视图状态是 ASP.NET 中不再存在的东西,但如果您是以前的 - 我认为是 ASP.NET 5。如果您使用 ASP.NET 4 然后查看状态或前 MVC,则存在视图状态。 它仍然存在于当时开发的大多数 ASP.NET 应用程序中。

对于那些不知道视图状态是什么的人来说,视图状态是由 Web 服务器发送到浏览器的加密字符串,只有在回发发生时才会返回。 所以,这个字符串可能有数百千字节,它到达浏览器并存储在浏览器中,然后返回。 将其乘以您的应用程序必须处理的数百万笔交易,它有两个问题,一是它消耗了大量带宽,而带宽并不便宜,您必须为带宽付费。 其次,它会减慢响应时间,因为它是一个沉重的有效载荷。 因此,这是在服务器上缓存它并发送一个小密钥的理想情况,当它下次返回时,从缓存中获取视图状态并提供给页面。 同样,视图状态只是您不使用 MVC 框架的问题,而且在 ASP 中肯定不存在.NET Core 因为 ASP.NET Core 是MVC。

ASP.NET 输出缓存也是 ASP 的一部分.NET framework,不在 ASP 中.NET Core 它几乎缓存了页面输出。 那么,如果您的页面在下一个请求时没有更改,为什么要再次执行它呢? 因此,ASP.NET 缓存页面,因此下次请求带有相同的参数、相同的所有内容时,最后一次执行的输出将提供给页面。

因此,该框架已经存在,并且为它使用分布式缓存确实是一件好事,这样,在多服务器环境中,一旦它被缓存,它就可以立即用于所有服务器。 ASP.NET Core 只有用于缓存的会话,没有视图状态,也没有输出缓存。 但是,还有一种叫做响应缓存的东西。 所以,ASP.NET Core 现在已经对内容缓存发生在服务器之外的整个 Web 应用程序进行了标准化。 所以,这也是一个很好的缓存候选者。 所以,ASP.NET Core 有这个响应缓存中间件的概念。 因此,您可以使用内置的中间件,然后您可以制作第三方中间件。 像 NCache 很快就会提供一个。

所以,无论如何,对于 ASP.NET 缓存,现在要记住的重要一点是,您不再将这些数据存储在缓存中。 因此,与数据存在于两个地方的应用程序数据不同,现在数据只存在于一个地方,那就是缓存,它是内存中的缓存。 那么,当内存存储是您唯一的存储时,会出现什么问题呢? 是的。 我的意思是,如果那个盒子掉了,你就会被冲洗掉。 因为,内存是易失的。 它没有坚持下去。 因此,处理该问题的方法当然是进行复制。 在不止一台服务器上拥有该数据。 但是,又要解决两个非常不同的问题。 一个好的分布式缓存必须做智能复制。 例如,如果您要自信地存储 ASP.NET 会话。 否则,会发生什么? 让我们回到那个,你知道的,航空公司。 我刚刚去了那个网站。 我要买一张价值5,000美元的票。 我做了所有的航班搜索,各种组合,我即将……我输入了我的付款信息并准备提交,突然间我发回了,你知道的,启动页面,无论如何,因为我的会话是丢失。 因为当我点击提交时,它去了网络服务器,那个网络服务器不在那里,它崩溃了,会话消失了。 所以,绝对不是一张好照片。

通过事件共享运行时数据

第三个用例是 运行时数据共享 通过事件。 这是很多人不知道的,它现在变得越来越流行,一旦你在你的环境中拥有分布式缓存,它是一个非常强大的平台,用于在多个应用程序之间共享数据,例如 发布/订阅 模型或其他事件驱动的数据共享。

例如,您可能有多个需要共享数据的应用程序。 一个应用程序产生一些东西,将其放入缓存中,触发一些事件,该事件有订阅者。 因此,还有其他应用程序实例或其他应用程序,很多时候您会在应用程序中发生某种工作流。 先完成某件事,然后在此基础上完成另一件事。 而且,在这种情况下,这些事件有这些订阅者。 这些申请将被通知。

现在想想这张照片(图1) 这里。 不要将其视为应用程序和数据库之间的缓存。 把它想象成一个消息总线,这些应用程序都连接到消息总线。 来自该服务器的一个应用程序将数据放入缓存中,触发一个事件。 可能在其中一些服务器上的其他应用程序会收到通知,它们将立即开始使用数据。 很强大的方法。

有些人使用消息队列。 对于很多这样的消息队列有明确的目的。 分布式缓存在这里并不是要完全取代它们,而是部分案例。 当所有数据共享都在同一个数据中心内时,不是一个非常分布式的环境,而是一个高流量的环境。 与分布式缓存不同,消息队列不可扩展。 因为,消息队列没有这样的集群。 你真的不能添加更多。 因此,如果您有数百万个事务正在发生并且其中一部分也是消息信息,那么消息队列无法处理该负载,但缓存可以。

所以,运行时数据共享是一种非常强大的方式,我会谈到它。 同样,在运行时数据共享中,数据通常只存在于缓存中。 虽然,数据库中可能存在不同形式的它。 因为,它是从数据库中读取出来的,经过某种形式的转换,然后放到缓存中共享。

因此,某些特性在所有缓存中都是通用的。 有些只是 NCache 在 .NET 方面,但一切都是 NCache 在 .NET 方面不是 .NET 专有功能。 因为,您会在 Java 端和所有 Java 缓存中看到相同的功能。 因此,Java 是一个更先进或更成熟的市场,因为 Java 作为服务器端技术的时间比 .NET 更长。 所以,你看到了......在Java方面。 在 .NET 方面,您会在一些缓存中看到它,而不是全部。 例如, AppFabric,我认为没有。 Redis 有一些不是全部。 NCache 像 Java 缓存一样成熟。

因此,这是三个用例。 在我深入研究每个问题之前,对此有任何疑问吗?

动手演示

在讨论这些之前,让我先向您展示一下缓存是什么样的? 我当然要使用 NCache 作为示例,但目的是让您了解缓存的真实外观。 例如,我在 Azure 中有三个 VM。 它们正在运行。 Demo1 和 demo2 是我的缓存服务器虚拟机。 所以,我将有一个 2 节点缓存集群。

演示客户

演示客户端是我的应用服务器。 所以它是一个缓存客户端虚拟机。

创建集群缓存

我在这里登录了演示客户端 VM。 我将继续创建一个集群缓存。 的情况下 NCache, 我会用这个工具叫 NCache 经理,这是一个图形工具。 我会来这里说,让我首先确保缓存不存在。 好的,它没有,好的,我要来这里说创建一个新的集群缓存。

的情况下 NCache 所有缓存都被命名。 所以,我的缓存被称为 演示缓存. 我将保留所有默认设置。 我不打算详细介绍这个。 我会继续……我只会谈论那些重要的部分。

你会选择的第一件事就是我们所说的 缓存拓扑 NCache 这就是你们中的一个问关于分区的问题的地方。 数据是真正分布的还是每个服务器中都存在相同的数据。 因此,分区副本是一种拓扑, NCache 给你。

例如,我将快速跳过这个,我将快速讨论那个拓扑是什么? 所以,一个分区副本拓扑......所以,这是一个分区拓扑,这是一个分区副本。

在分区中,每台服务器都有 1 分之一的数据。 所以,如果你有,让我们说,以防万一 NCache,当你建立一个集群缓存时,它会创建一千个桶。 所以,如果你有一个两台服务器集群,每台服务器 500 台。如果你有三台,那么每台服务器就是千分之一。

所以,这些桶本质上就像一个哈希表桶。 每个存储桶都分配有一个键值范围。 因此,有一个哈希映射函数可以将您的键转换为哈希值,并且它们将根据键落入它们应该落入的任何存储桶中。 因此,分区副本在每台服务器上都有一个分区。 比方说,如果你来这里。 假设这是一个三服务器集群,因此,三个分区和每个分区在不同的服务器上都有一个备份或副本。

的情况下 NCache 副本未激活。 它是被动的。 因此,只有分区与副本对话。 应用程序与分区对话。 因此,假设每个缓存客户端,每个应用程序服务器都连接到所有缓存服务器。 它连接并获取所有集群成员信息。 分布图就是那个桶图。 那么,它得到桶图,告诉它每个桶在哪里? 基于此,它知道,好吧,如果我需要添加第 2 项,我需要转到服务器 2。因为,那是分区 3 所在的地方,它应该有第 XNUMX 项的密钥。所以,它直接进入那台服务器,它可以做到这一点。

然后,如果一个服务器宕机,那么,比如说,分区 3 宕机,所以副本 3 将立即变为活动状态。 所以,它现在将成为一个分区。 它将从副本转换为分区。 因为,你不知道,你想继续。 缓存必须运行,应用程序必须继续。 这是高可用性,对。 所以,然后这个分区 XNUMX 意识到只有两个服务器,所以,它需要将自己合并到这两个分区中,然后消失,消失。 因此,它将自身合并到其他两个分区中,然后一旦完成,就会在此处创建分区 XNUMX 的副本。

因此,再次为您概述该拓扑的含义,这就是分配发生的方式,以确保当您添加更多服务器时,您拥有越来越多的存储空间,这也是复制发生的方式,以便每个数据都存在于两台服务器中. 因此,如果任何服务器出现故障,数据不会丢失。

同样,高可用性理论表明两台服务器不会同时停机。 与任何一台服务器宕机相比,两台服务器同时宕机的可能性是天文数字的低。 当然,正如我所说,如果两台服务器使用同一个电源,那么该电源就会出现故障,那么我假设一切都是冗余的。 那么两件事就不会同时失败。 所以,这就是为什么只有两个副本就足够了。

我们回去吧。 所以,这就是分区副本。 然后我会选择一个异步复制。

所以,有两种模式。 大多数分布式缓存都会做这种称为最终一致性的事情。 这意味着由于分布,如果您必须立即进行同步,那么一切都会变慢。 但是你能负担得起的大多数数据,都会排队并进行异步更新。 因此,异步是这里的默认设置。

我将选择演示客户端或演示 1 是第一个服务器。 我将选择演示 2 作为第二台服务器。

我会来这里,我会采用默认值。

我将指定每个服务器应该使用多少内存。

当然在你的情况下会更多。 因此,假设您在每个盒子中有 16 gig 内存,您需要分配一些用于分区和一些用于副本。 所以,比方说,应该为操作系统和其他进程留下 2 到 3 gig,剩下大约 13 gig。 因此,按 7.5 或 6.5 gigs,一个用于分区,一个用于副本。 而且,因为您指定该大小以确保缓存不会消耗更多。 因为,它是一个内存存储,内存总是有限的,并且在那个盒子上可能有其他应用程序正在运行。 因此,您想限制缓存应该使用多少内存,并且一旦缓存使用了该内存……

那么,下一页将是。 假设你已经用完了所有的内存。 所以,现在缓存已满。 所以,只有两件事会发生。 第一,它要么驱逐一些旧数据或其他数据,要么拒绝新插入。 所以,你必须选择这两个。 当然你要做你的容量规划,数据在哪里,如果是应用程序数据,就可以逐出,因为你总是可以从数据库中重新加载它。 驱逐会话是不行的。 因此,您希望以永远不会驱逐这些会话的方式进行容量规划。 现在您有足够的内存、足够的 RAM 和足够的服务器,您将始终拥有用于会话的内存。 而且,您要使会话过期,而不是驱逐主题。 驱逐意味着会话仍然没有过期,但没有留下任何记忆,所以,你有点强行驱逐。 到期的情况下 NCache 表示您指定会话仅适用于 20 分钟不活动。 之后,会话将被清理。 所以,这就是到期。 所以,过期没问题,没有问题,但驱逐是你不应该对会话做的事情,对应用程序数据做这些是可以的。

所以,你怎么办,以防万一 NCache,您为会话创建缓存并为应用程序数据创建缓存。 所以,这就是你将两者分开的方式。 所以,假设我刚刚创建了这个缓存。 所以,它是一个两节点缓存。 我将继续添加一个客户端节点,它是我的演示客户端盒子,现在我将启动缓存。

添加客户端节点

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

因此,如您所见,它非常简单。 这是一种资源管理器风格的界面。 从一个地方你可以继续创建多服务器缓存,管理它,监控它,然后一旦你完成了,比方说,现在它完成了,我将看到一些 PerfMon 计数器,我将运行这个工具叫做压力测试工具 自带的 NCache,这让您可以非常快速地模拟应用程序的使用。

压力测试工具

所以,假设我刚刚这样做了,现在它开始……所以,它在每台服务器上执行大约 500 到 800 个事务。 所以,大约是 2 倍,这就是负载。 我想增加负载。 所以,我想再添加一个压力测试工具。 我们的客户经常使用它,因为几乎每个人都想看看缓存在他们的环境中的表现。 您知道,我们确实发布了所有基准测试和所有内容,但他们希望在他们的环境中看到它。 所以,他们不用编程和应用程序来做,这可以非常快速地模拟。 所以,假设我跑了其中两个,现在负载增加了。 所以,我可以继续添加越来越多的这些,直到我最大化这两个服务器。 所以,这就是可扩展性的来源。

缓存统计

这两台服务器现在的运行速度非常快。 但是,当我增加负载时,在某个点之后它们会达到最大值,这就是数据库所发生的情况。 唯一不同的是,您可以来这里添加另一个节点。 所以,如果你有第三个虚拟机,你只需到这里添加它,一旦你这样做,负载就会突然分散,我们有这张图片,你知道,我向你展示了你从哪里开始的地方两台服务器,现在这两个已经被刷爆了,你想添加第三台。 因此,您只需获取另一个 VM 并添加它,现在它就变成了三台服务器,并且 NCache 将自动重新调整所有内容,我们将重新分区或 redis致敬桶图。 因此,在运行时添加了第三台服务器。 所以,突然之间你就没有那个容量问题了。

缓存统计

是的,所以,你要做的就是安装 NCache 服务器软件, 在所有这些虚拟机上。 在云的情况下,您通常有一个预先配置的 VM 映像,您可以在其中创建实例,因此您只需启动一个新 VM,它具有 NCache 软件正在运行,您只需将其添加到此集群即可。

但是,主要的一点是,与数据库不同,一旦您达到最大输出状态,您就会被淹没,您知道。 你做什么工作? 你知道,好吧,我想买更贵的。 那么你必须去买另一个盒子然后把这个盒子拿下来,这是一场噩梦。 在这里,您只需添加另一个框。

运用 NCache 使用 ASP.NET 会话

所以,我现在要去下一个。 所以,现在我们知道缓存是什么样的了。 所以,现在我们看到了……万一 NCache,所有缓存都被命名。 因此,只要您知道缓存的名称,您就可以连接到缓存。 那么,如何连接到会话缓存呢? 这是最简单的。 同样,我们的大多数客户,他们做的第一件事 NCache 他们将其用于会话。 为什么? 因为不需要编程。 在会话的情况下,您唯一需要确保的是,您放入会话中的任何对象都是可序列化的。 如果您已经在 SQL 中存储会话,那么您已经确保了这一点。 如果您在 In-Proc 模式下存储会话,那么您可能无法确保它。 所以,你知道,这是你唯一要做的测试。 但是,之后就很简单了。

我只是在这里给你看一个小样本。 因此,例如,这里有一个示例,称为会话存储提供程序示例。 所以,我有一个 ASP.NET 应用程序。 我将转到 web.config。 假设我在这个应用服务器上,你知道的。 如果你在这里看到那张照片。 其实,让我,回到这里。 所以,这里是缓存服务器,但我的应用程序正在这个盒子上运行。 所以,在这个盒子上,我创建了两个服务器集群,并在其中添加了一个客户端,对吧。 所以,现在那个客户端发生的事情是,如果 NCache,哎呀,不在这里。 好的,万一 NCache 它实际上在配置文件夹中创建了一个client.ncconf,因此它创建了一个条目。 所以,这就是应用程序知道要连接到哪个服务器的方式。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <ncache-server connection-retries="3" retry-connection-delay="0" retry-interval="1" command-retries="3" command-retry-interval="0.1" client-request-timeout="90" connection-timeout="5" port="9800" local-server-ip="10.2.0.5" enable-keep-alive="False" keep-alive-interval="0"/>
    <cache id="demoCache" client-cache-id="clientCache" client-cache-syncmode="optimistic" skip-client-cache-if-unavailable="True" reconnect-client-cache-interval="10" default-readthru-provider="" default-writethru-provider="" load-balance="False" enable-client-logs="False" log-level="error">
      <server name="10.2.0.5"/>
      <server name="10.2.0.6"/>
    </cache>
  </configuration>

同样,这些只是初始服务器列表。 这不是最终名单。 为什么? 因为,对于高可用性环境,如果您在运行时添加第三台服务器会怎样? 那不在此列表中,对吗? 所以,比方说,那是点八(.0.8),一些东西。 所以,这只是最初的列表。 一旦应用程序知道其中任何一个,它就会连接到那个。 应用程序发生的第一件事是,一旦连接,它就会接收集群成员信息,并且每当集群成员更改并且您添加另一台服务器并将更新的集群成员发送到客户端时,它都会被保存在内存中。 这一切都隐藏在您的应用程序中。 这一切都由 NCache 客户端部分,但这就是应用程序知道如何连接到您的缓存的方式。

所以,在会议的情况下,你就来这里。 因此,在会话中,您必须首先添加程序集。

...
<compilation defaultLanguage="c#" debug="true" targetFramework="4.0">
    <compilers>
		<compiler language="c#" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" extension=".cs" compilerOptions="/d:DEBUG;TRACE" />
	</compilers>
	<assemblies>
	<add assembly="Alachisoft.NCache.SessionStoreProvider, Version=4.6.0.0, Culture=neutral, PublicKeyToken=CFF5926ED6A53769" /></assemblies>
</compilation>
...

的情况下 NCache 你只是……这个程序集实现了 会话状态提供者接口 这是 ASP 的一部分.NET framework 并通过这样做 NCache 成为第三方,自定义存储。 因此,这只是复制粘贴,然后是会话状态标记的实际更改。 所以,你在这里做什么,你确保模式是自定义的。

...
<sessionState cookieless="false" regenerateExpiredSessionId="true" mode="Custom" customProvider="NCacheSessionProvider" timeout="20">
    <providers>
        <add name="NCacheSessionProvider" type="Alachisoft.NCache.Web.SessionState.NSessionStoreProvider" sessionAppId="WebF1" cacheName="democache" writeExceptionsToEventLog="false" enableLogs="false" />
    </providers>
</sessionState>
...

因此,模式有 In-Proc、状态服务器、SQL 和自定义。 所以你有四种模式。 因此,如果模式是自定义的,那么您还需要确保超时是您希望会话超时的任何值,然后复制提供程序详细信息。 也就是说,如果 NCache 就是这一行,他们唯一需要改变的是缓存名称。 因此,例如,这里的缓存名称已经更改。 你做出改变,仅此而已。 而且,一旦您进行了更改,ASP.NET 无论如何都会重新启动您的工作进程,您将看到每个会话都将作为一个对象保存在缓存中,您将立即看到性能的巨大提升。 因为,现在您没有将它们保存在 SQL 中。

因此,从分布式缓存中受益的最快方法 NCache 只是,把它放在会议上。 因为,对于应用程序数据缓存的对象,还有更多工作。 当然,您知道,您想这样做,这就是我要介绍的内容,但第一个用例是 ASP.NET 规范。

对此有任何疑问吗? 因此,我们所看到的,例如,我们的一些高端客户在应用层拥有大约 50 到 100 台服务器。 为此,假设保持 1 比 5 的比例是通常发生的情况。 因此,对于 100 台服务器配置,他们将拥有 20 台缓存服务器。 超过 50 台,它们很少,你知道,在负载平衡的环境中,你真的必须有很多流量才能拥有超过 50 台服务器。 大多数客户都在 4 到 12 台服务器之间。 而且,正如我所说,我们建议根据应用程序的性质,采用 4 比 1 或 5 比 1 的比例。 有时,它甚至可以超过 5 比 1,但我的意思是这就像平均用例一样。 因此,如果您有 5 比 1 并且您在应用程序层中有 12 台服务器,那么您就有了 XNUMX 台服务器缓存层。 所以,没有那么多联系,是的。

理论上,是的。 如果您继续添加越来越多的服务器,您将有很多冗余。 但是,我们正在谈论的用例并没有落下。 大数据处理可能有 50 或 100 台服务器,但在这种情况下没有客户端,大数据处理只是服务器的。 因为,一切都在服务器本身上运行。 但是,对于 Web 应用程序或 Web 服务应用程序,我们称之为电子商务,即在线业务模型。 我的意思是差不多了。 我认为您可以假设在大多数情况下您将拥有少于 20 台服务器,并且极少数客户将拥有超过 20 台服务器,而超过 50 台的客户非常小。

是的,绝对的。 因此,例如,如果我要来这里,我只是要去……如果我要来这里。 我没有使用 NuGet软件包 在这里,但我可以来这里去 NuGet,我可以在这里说 NCache,例如,你会得到一个 NCache SDK, NCache 面向企业和专业人士的会话服务,还有一个开源的,还有 NHibernate。 所以,有一堆 NuGet。 因此,一个典型的……对于会话,您只需包含此会话 NuGet 包。 对于应用程序数据缓存,您只需包含 SDK,这将包含您需要的所有内容。

缓存统计

应用数据缓存概述 (API)

所以, 应用数据缓存 是你必须编程的东西。 因此,您将缓存视为数据库。 您连接到缓存。 的情况下 NCache 我们有这个方法叫做 初始化缓存.

缓存连接
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");

您可能对其他缓存有一些其他方法,并且有一个缓存名称以防万一 NCache 正如我们所讨论的,这为您提供了一个缓存句柄。

那么,让我们进入一个应用程序。 同样,我们将进入…… 这是一个简单的控制台应用程序。 您所做的是,如果您包含 NuGet 包,那么所有这些都将为您完成。 你会参考一些 NCache 组件。 因此,您只需要引用两个程序集, NCache。运行NCache.Web. NCache.Web 是实际的公共 API NCache. 然后在您的应用程序中,包含命名空间。 所以,你有 NCache。运行NCache.Web.缓存 作为命名空间。

然后在应用程序开始时,您从 App.config 中获取缓存名称,然后初始化缓存并获得缓存句柄。 因此,这里是您需要在应用程序中随处使用的缓存句柄。

现在,让我们进入那个缓存句柄。 所以,你可以做 缓存。添加, 指定键。 正如我所说,密钥通常是一个字符串。 无论是什么,对象都是您的实际对象。 它是任何 .NET 对象, NCache 实际上会将其序列化并将其发送到集群。 所以,所有这些都发生在客户端,在应用程序服务器上。

// Alachisoft (R) NCache Sample Code.
using Alachisoft.NCache.Runtime;
using Alachisoft.NCache.Sample.Data;
using Alachisoft.NCache.Web.Caching;
using System;
using System.Configuration;

namespace Alachisoft.NCache.Samples
{
    /// <summary>
    /// Class that provides the functionality of the sample
    /// </summary>
    public class BasicOperations
    {
        private static ICache _cache;

        /// <summary>
        /// Executing this method will perform all the operations of the sample
        /// </summary>
        public static void Run()
        {
            // Initialize cache
            InitializeCache();

            // Create a simple customer object
            Customer customer = CreateNewCustomer();
            string key = GetKey(customer);

            // Adding item synchronously
            AddObjectToCache(key, customer);

            // Get the object from cache
            customer = GetObjectFromCache(key);

            // Modify the object and update in cache
            UpdateObjectInCache(key, customer);

            // Remove the existing object from cache
            RemoveObjectFromCache(key);

            // Dispose the cache once done
            _cache.Dispose();
        }

        /// <summary>
        /// This method initializes the cache
        /// </summary>
        private static void InitializeCache()
        {
            string cache = ConfigurationManager.AppSettings["CacheID"];

            if (String.IsNullOrEmpty(cache))
            {
                Console.WriteLine("The CacheID cannot be null or empty.");
                return;
            }

            // Initialize an instance of the cache to begin performing operations:
            _cache = NCache.Web.Caching.NCache.InitializeCache(cache);

            // Print output on console
            Console.WriteLine(string.Format("\nCache '{0}' is initialized.", cache));
        }

        /// <summary>
        /// This method adds object in the cache using synchronous api
        /// </summary>
        /// <param name="key"> String key to be added in cache </param>
        /// <param name="customer"> Instance of Customer that will be added to cache </param>
        private static void AddObjectToCache(string key, Customer customer)
        {
            TimeSpan expirationInterval = new TimeSpan(0, 1, 0);

            Expiration expiration = new Expiration(ExpirationType.Absolute);
            expiration.ExpireAfter = expirationInterval;

            //Populating cache item
            CacheItem item = new CacheItem(customer);
            item.Expiration = expiration;

            // Adding cacheitem to cache with an absolute expiration of 1 minute
            _cache.Add(key, item);

            // Print output on console
            Console.WriteLine("\nObject is added to cache.");
        }

而且,一旦你这样做了,你也可以这样做 _cache.Get 并取回相同的对象。 所以,如果你从 API 的角度来看,这里是 cache.Get、获取、包含、添加、插入、删除 并且这三个都有一个异步版本,这基本上意味着应用程序不等待缓存更新,控制权立即返回。 但是,密钥通常是一个字符串。 它通常是这样的。 您有类型名称。 的情况下 NCache 那要看。 如果您使用过此功能称为 客户端缓存. 所以,我只想跳进去。

客户端缓存(靠近缓存)

因此,默认情况下,您会假设每当您执行 缓存.获取,您实际上将进入缓存层。 但是,有一件大多数人没有意识到的有趣的事情,那就是,如果您一直在使用 In-Proc 缓存,例如 ASP.NET 缓存对象,并且您决定使用类似的东西 NCache 因为我们说过它将提高您的性能和可扩展性。 嗯,这是一种提高可扩展性的方式,但是突然之间你的性能实际上会下降,我们有很多客户打电话给我们说,你知道,自从我插入后,我的应用程序实际上已经变慢了 NCache. 所以,为什么我真的需要它,你知道的。 这真的不好,这是一个你知道的。 所以,然后我们必须向他们解释,当你做一个 In-Proc 缓存时,没有序列化,应用程序和缓存之间没有进程间通信,无论是在同一个盒子上还是在单独的盒子里,通常它是一个单独的盒子,对。 因此,如果对象以对象形式保存在您的堆中,它会非常快,对。 你去拿一个参考。 没有什么能比得上这种表现。 但是,您迁移到分布式缓存的原因是因为 In-Proc 模型有很多限制。 它无法扩展。 您不能添加越来越多的数据,它只是一个进程,如果您有多个进程,则复制不会同步。 因此,还有很多其他问题导致您迁移到分布式缓存,但您会失去这种好处,对吧。 所以,我们所做的是我们提出了一个叫做客户端缓存的东西,它在 Java 端被称为近缓存,而在 .NET 端到那时,缓存是唯一拥有它的缓存。

缓存统计

所以,这实际上做了什么,它实际上在应用程序中创建了一个 In-Proc 本地缓存。 因此,它将该对象以对象形式保存在您的堆中。 因此,您可以获得与在独立进程内缓存中习惯的相同的性能。 唯一的区别是这个缓存知道它是集群缓存的一部分。 所以,无论它保存在本地副本中,它都有一个到缓存层的链接。 它告诉缓存层,你知道,我有这个对象,如果有人更改了那个对象,请通知我。 所以,如果有的话,假设这个客户端有另一个客户端的第一个项目,当然那个第一个项目也在这个缓存层中。 另一个客户进来并更新第一个项目。 缓存层知道这些客户端缓存具有第一个项目,因此,它们通过事件通知你知道的。 的情况下 NCache 这是相当快的事件。 这些不是 .NET 事件,它们是套接字级别的通信。 因此,客户端缓存会立即自我更新。 所以,我们说的可能是毫秒延迟。

所以,这样你就有信心,无论你得到什么,所有或大部分时间都是准确的。 从技术上讲,可能是旧版本的可能性很小。 的情况下 NCache,如果你太在意,那么你可以使用我们所说的悲观同步模式,每次你获取任何东西时,你知道, NCache 内部检查缓存层是否有最新副本。 如果没有,它会从客户端缓存中的数据中提供它,否则它会从缓存层中获取它。 但是,在大多数情况下,您不需要它。 大多数情况下,你可以接受这么多的机会。 因此,这可以提高 In-Proc 缓存的性能。 但是,您的应用程序也不知道这一切正在发生。

的情况下 NCache 您的应用程序确实知道。 应用程序认为它只是在与缓存层对话。 只有一个缓存与之通信。 它被称为我的缓存或其他任何东西。 这是演示缓存,演示缓存可以通过配置插入客户端缓存,以防万一 NCache. 对此有任何疑问吗?

JCache (JSR 107) API

所以,我的意思是这就是典型的缓存的样子。 做这个编程很容易。 Java 方面现在正在发生什么,我再次称赞他们,因为他们在这方面更先进。 他们有一个完整的标准 API,称为 JCache。 因此,JCache API 是一个非常有特色的功能……它具有我刚才谈到或正在谈论的所有功能。 因此,JCache 是每个 Java 缓存都必须实现的标准,如果它们想要与行业兼容。

IDistributedCache API

在.NET 方面还没有这样的东西。 有一个 ASP.NET 缓存对象,直到最近才可插入。 因此,如果您对 ASP.NET 缓存进行编程,则无法插入 NCache 代替它。 因此,您不能插入第三方缓存。 它只是一个独立的缓存。 在 .NET 4.0 中,他们启动了一个从未真正使用过的 .NET 缓存。 现在在 ASP.NET core 他们有一个 i分布式缓存 界面。 这又是一个非常基本的 get 输入法。

因此,标准 API 的问题在于您将无法利用良好缓存应提供的所有功能。 你真的仅限于真正的基本获取输入。 但同样,我们的大多数客户无论如何都封装了缓存层。 所以,即使他们正在制作所有 NCache 调用时,整个应用程序不会暴露给它。 所以,无论如何,这就是 API 的样子。

应用数据缓存功能

现在,让我们介绍一些重要的功能。 所以,他们中的大多数……继续吧。 只是一个简单的问题。 插入和添加有区别吗? 是的,插入意味着添加或更新。 如果数据已经存在,则更新它,如果不存在,则添加它。 如果数据已经存在,添加将失败。 而且,这也是我们坚持使用的 ASP.NET 缓存 API,因为我们希望尽可能接近当时的标准。 不,不,不是。 我的意思是,我们保留了它。 ASP.NET 缓存对象现在消失了,因为现在,正如我所说,在 ASP.NET Core 不存在了,ASP.NET 仍然有它,但 ASP.NET Core 没有。

绝对到期

所以,你必须记住的第一件事就是保持我们谈到的缓存新鲜,对吧。 你是如何做到这一点的第一技术是过期。 过期看起来像这样,让我们​​回到这个。 所以,让我们这么说,我有......你们能看到这个吗? 你能看到这个吗? 好的。 假设我有一个键和一个值或某个对象。 我想将它添加到缓存中,我将指定 1 分钟的过期时间。 所以,这被称为 绝对到期.

public static void AddObjectToCache(string key, Customer customer)
    {
        DateTime expirationInterval = new DateTime();
        expirationInterval.AddMinutes(1);
        //Adding item with an absolute expiration of 1 minute
        _cache.Add(key, customer, expirationInterval, Cache.NoSlidingExpiration, CacheItemPriority.Normal);
        Console.WriteLine("\nObject is added to cache");
    }

绝对过期意味着在 1 分钟过去后,无论如何都会过期。 这意味着我是在对缓存说,我真的不愿意缓存超过一分钟。 因为,我做出有根据的猜测,将其保存在缓存中一分钟是安全的。

滑动到期

另一方面,滑动到期具有完全不同的目的。 它用于清理诸如会话之类的东西。 它与同步或保持缓存新鲜无关。 因此,绝对表达式几乎是所有缓存都有的。 事实上,即使是 ASP.NET Core IDistributed Cache Interface 具有绝对的表达方式。

将缓存与数据库同步

但是,表达是制作缓存或保持缓存新鲜的唯一方法有什么问题? 这是你在猜测这个数据不会改变。 如果有怎么办? 如果有其他应用程序,还有其他脚本正在修改数据,在任何企业中,通常会有不止一个地方更新数据。 因此,如果您无法预测数据的更新频率,那么表达式只是一个起点。 您必须进入下一个阶段,即将缓存与数据库同步。 所以,你基本上,在将缓存与数据库同步的情况下 NCache 我们使用这个特性,它是 ADO.NET .NET 的一部分,称为 SQL 依赖项。

本质上是 SQL 依赖,让我向您展示它的样子。 所以,在 SQL 依赖的情况下,我正在做同样的缓存。添加,对。 我将拥有键,而不是值,我将拥有一个缓存项,它是我们自己的结构,我们将实际对象放入其中,现在我们有了它,然后我们指定这个称为 SQL 依赖项、SQL 服务器依赖项的东西这个变量本质上是创建 SQL 语句。


private static void AddProductToCacheWithDependency(Product product)
    {
        // Any change to the resultset of the query will cause cache to invalidate the dependent data
        string queryText = String.Format("SELECT ProductID, ProductName, QuantityPerUnit, UnitPrice FROM dbo.PRODUCTS WHERE PRODUCTID = {0}", product.Id);

        // Let's create SQL depdenency
        CacheDependency sqlServerDependency = new SqlCacheDependency(_connectionString, queryText);

        CacheItem cacheItem = new CacheItem(product);
        cacheItem.Dependency = sqlServerDependency;

        // Inserting Loaded product into cache with key: [item:1]
        string cacheKey = GenerateCacheKey(product);
        _cache.Add(cacheKey, cacheItem);
    }

这段代码在客户端机器上运行,就在这里。

缓存统计

它与缓存服务器对话。 它告诉缓存服务器使用 ADO.NET SQL 依赖功能连接到我的数据库。 所以,它实际上给了我一个到数据库的连接字符串。 所以,现在应用程序告诉缓存,这是我的数据库,用于这个缓存的项目,这是代表数据库中相应数据的 SQL 语句。

实体框架/实体框架核心集成

好问题。 在实体框架的情况下,我们已经在内部实现了实体框架的实现。 我们甚至使用 Entity Framework 也有两种方法可以使用缓存。 无论是您,如果是 EF Core,现在新架构允许插入第三方缓存,但在 EF6 之前,无法插入缓存。 因此,无论如何,您都必须进行这些 API 调用。 所以,假设你得到了一个实体集合,当你缓存它们时,你可以指定 SQL 依赖项。 你明白我的意思吗?

的情况下 NCache 你在说 NCache 这是我的 SQL 语句。 NCache 我们将使用 ADO .NET 连接到您的数据库并使用 ADO.NET SQL 依赖项功能来监控该数据集。 所以, NCache 正在告诉 SQL 服务器,如果此数据集发生更改,请通知我。 然后 SQL server 发送一个数据库通知到 NCache 因为 NCache 不是数据库的客户端,然后 NCache 现在知道这个数据在数据库中发生了变化。 所以,即使你有 EF,它也有点绕过它,现在 NCache 知道此数据已更改 NCache 有两个选择。 它可以从缓存中删除该项目,当您删除它时,您知道,下次有人需要它时,他们不会在缓存中找到它,因此,他们必须从数据库中获取它。 所以,在某种程度上,你让它变得新鲜或 NCache 可以为您从数据库本身重新加载该数据,除非您使用另一个称为通读的功能,否则这是不可能的,我会谈到这一点。

因此,SQL 依赖项基本上确保如果您无法预测数据何时可能更改,您只需告诉 NCache 或您的缓存请为我监控数据库。

SQL 依赖项有一个限制,您不能在其中加入连接。 所以,这是一个单表的事情。 您还可以通过其他方式进行监控。 例如,如果 NCache 有一个功能叫 自定义依赖,这是你的代码。 NCache 调用您的代码并说请去监控您的数据源并查看数据是否已更改。 所以,这有点像投票。 所以, NCache 将轮询您的自定义依赖项,然后它可能是一个复杂的结构。

是的,正是。 实际上,当您执行 SQL 依赖时,缓存不会频繁地与数据库通信,因为它只是……所以,数据库是发起通信的那个,因为有一个事件。 这是一个事件驱动的架构。 因此,只要数据发生变化,数据库就会发送一个事件。

实际上,SQL 服务器具有此功能,它监视数据集,然后向客户端发出数据库通知。 所以, NCache 成为数据库客户端。

因此,一种选择是从缓存中删除该项目。 另一种是重新加载它。 好吧,重新加载意味着 NCache 必须有一种方法知道如何去获取数据,这意味着有一个称为读取的功能,这是您编写的代码并在缓存服务器、缓存集群中注册。 我将快速向您展示该代码的外观。

直读缓存

不,实际上它只是您的自定义代码。 因此,即使您也可以在该代码中进行 ORM 调用。 所以,所有的代码看起来都是这样的。 所以,这里有一个 IReadThruProvider 接口。

...
// Perform tasks like allocating resources or acquiring connections
public void Init(IDictionary parameters, string cacheId)
{
    object connString = parameters["connstring"];
    sqlDatasource = new SqlDatasource();
    sqlDatasource.Connect(connString == null ? "" : connString.ToString());
}

// Perform tasks associated with freeing, releasing, or resetting resources.
public void Dispose()
{
    sqlDatasource.DisConnect();
}

// Responsible for loading an object from the external data source.
public ProviderCacheItem LoadFromSource (string key)
{
    ProviderCacheItem cacheItem = new ProviderCacheItem(sqlDatasource.LoadCustomer(key));
    cacheItem.ResyncOptions.ResyncOnExpiration = true;
    // Resync provider name will be picked from default provider.
    return cacheItem;
}
...

所以,有 IReadThruProvider 接口。 它有三种方法。 有一个 Init 仅在缓存启动时调用。 因此,它应该连接到您的数据源。 最后有一个处置,并且有一个负载。 因此, load 为您提供了一个密钥,您应该返回一个缓存项。

因此,基于该键,您的代码需要知道去哪里,因为它已经连接到您的数据源。 因此,无论您使用 ORM,是否进行 EF 调用 NHibernate 调用、ADO.NET 调用,这都是您的所有代码,然后您将去加载它,比方说,您将从数据库中加载该对象,然后您把它放进去,你把过期时间或者你想要的任何其他元数据放在里面,然后你把它传回去 NCache. NCache 然后将其缓存,然后将其返回给应用程序。

所以,通读的全部目的……让我来谈谈通读本身。 通读是缓存能够从数据库加载数据的一种方式。 因此,您实际上是在将一些持久性代码移动到缓存层。 而且,如果您有多个应用程序想要共享一个缓存,那么拥有通读、通写机制是完美的选择。 因为你在整合,你在制作应用程序,代码更少,你知道的。 因此,他们将拥有更少的代码,因为越来越多的持久性代码将进入缓存层。 这是一个好处。 你知道,封装和合并。

通读的第二个好处是我们刚刚谈到的重载。 因此,重新加载发生在两种情况下。 一个在数据库同步,另一个在过期。 如果您有一个非常高流量的应用程序,例如,您有某种查找表或定价表会发生变化,并且您有成千上万的请求进入,如果您没有重新加载功能,然后当数据过期时,成千上万的请求将进入数据库。 而且,它们都会将同一个对象加载到缓存中。 这最终只是对数据库的大量流量。 您将其乘以您可能拥有的数据库的数千个项目将看到大量不必要的流量。

事实上,我们的一位客户是美国花卉业务的真正高端电子商务客户,曾遇到过这个问题。 因此,当他们突然实现重新加载功能时,整个问题就消失了,因为现在该项目永远不会从缓存中删除。 因此,旧副本会保留到某个点,而新副本会在此基础上更新。 因此,应用程序永远不必访问数据库。 所以,因为即使在探索时它也只会更新新副本。 所以,它有很多……所以,这两个好处将通读,您可以与此同步相结合。

直写缓存

另一个方面是直写,它的工作原理与直读一样,只是用于写入,写入可以是添加、插入、删除或删除。 同样,你有 Init,你有 Dispose,现在你有 写入数据源. 它说明了操作是什么,也有数据,你去更新数据库。 所以,直写意味着你更新缓存,缓存更新数据库。

那么,直写有什么好处呢? 好吧,一个好处与通读相同。 你巩固了所有的坚持。 其次,效益是后记。 因为,数据库更新没有那么快,你知道的,如果你相信数据库更新会成功,就更新缓存,让缓存异步更新数据库。 当然,如果出现故障,您可以收到通知,但您可以继续做其他事情,这也提高了应用程序的更新性能。 因此,现在您不必等待数据库更新完成,因为它们都已排队。 所以,这就是后面的部分。 并且,后写队列再次被复制到多个服务器。 因此,如果任何一台服务器出现故障,您的任何操作都不会丢失,以防万一 NCache.

但那是你的代码。 我是说 NCache 打电话给你。 所以,所有这些都是你的代码。 所以, NCache 打电话给你,你弄清楚写是什么意思或读是什么意思。

所以,read-through、write-through 是另一个非常强大的功能,可以与过期和同步结合使用。 因此,您需要确保缓存保持新鲜,然后您需要确保使用通读、通写。 现在您开始这样做,您可以缓存大量数据。 而且,现在缓存开始看起来像数据库。 这意味着你不能真正得到,你知道,现在 key 是不够的。 您需要能够进行搜索。 您需要能够以更智能的方式获取东西。 因此,这就是您应该能够对缓存执行 SQL 类型的查询的地方。 例如,选择客户之类的东西,其中客户点城市等于伦敦。 它为您提供了与该条件匹配的所有客户对象的集合。 而且,缓存会根据城市属性对这些对象进行索引。 所以,这就是它允许您搜索的方式。

所以,如果你不能做到这一点,那么你的应用程序就会变得更加复杂,因为你只能在键上搜索东西,而且你知道,你已经习惯于用数据库做很多其他你不能做的事情做缓存。

缓存中没有连接,但您可以进行分组。 而且,这种服务的目的是您可以获得数据,然后对它进行分组,然后基于这些组,您可以说给我属于这些组、子组、标签、名称标签的所有内容。 因此,您可以执行其他一些操作来对事物进行逻辑分组,并且您正在缓存的数据本身可以通过连接来实现。 只是缓存不能……缓存不是搜索引擎。 因此,如果您有连接数据,您只需将其分组。

缓存依赖

所以,这里有一个功能,因为有太多的内容,我这次无法真正涵盖。 所以,有一个功能叫做 缓存依赖 顺便说一下,它来自 ASP.NET 缓存对象, NCache 还实现了允许……你告诉缓存这个项目依赖于这个项目。 如果此项目被更新或删除,则此项目将自动删除。 因此,通过创建这些关系,您可以拥有一对多,比方说,如果您有一个一对多的关系,如果没有一方,多方就无法存在。 假设这是一个客户和一个订单。 因此,如果您删除客户,您也想删除订单。 因此,您可以让缓存为您处理。 同样,当您缓存时,假设您有一组对象,您可以将整个集合缓存为一个对象,也可以将它们分解为一个单独的对象。 如果你分解它们,那么你想要做缓存依赖。 因此,如果删除任何一个对象,则该集合不再有效。

是的,所以,这是我要讨论的整个主题,您可以访问我们的网站。 让我快速向您展示。 所以,有一个完整的讨论。 我想这是 处理缓存中的关系数据. 所以,这涵盖了所有的一对多、一对一、多对多,涵盖了你刚才谈到的所有内容的集合。 去看看吧。 我只是要快速完成,因为我们没有时间了。

因此,我试图说明为什么应该使用缓存以及应该如何使用它并通过它最大化收益。 我要跳过 运行时数据共享 部分,我想我已经讲得够多了。 您可以访问我们的网站并了解更多信息。 我已经谈到了客户端缓存,我已经谈到了通过分区实现的高可用性等等。

分布式缓存的广域网复制

还有多个数据中心。 你知道,你希望你的数据库能够处理多个数据中心,所以,为什么不缓存,你知道的。 所以,再一次, NCache 为您提供此功能。 在 Java 方面,您有执行此操作的缓存。 在 .NET 方面 NCache 是唯一的一个。 因此,您可以拥有一个主动-被动或主动-主动数据中心,并且缓存是同步的。 同样,您不能有一个跨越 WAN 的集群,因为性能只会下降。 您必须跨 WAN 进行异步复制或同步,因为当您有两个数据中心时,它们可能不在同一个位置。

广域网复制

我们之一 客户 瑞安航空是这里的一家大型航空公司,他们在都柏林伦敦和法兰克福设有数据中心。 所以,他们必须确保他们可以同步。 的情况下 NCache 我们还有 广域网复制. 还有一个多数据中心会话概念,会话可以从一个数据中心移动到另一个数据中心。 但是,无论如何,您的缓存必须能够支持多个数据中心。 因此,请确保您对此进行了调查。

NCache vs Redis

大多数 .NET 人员都知道 Redis. NCache, 很抱歉,Microsoft 已选择它们作为 Azure 的选择,尽管 Redis 来自Linux背景。 我认为微软选择它们的主要原因是因为他们想要拥有多种语言。 所以, Redis 涵盖了很多语言。 NCache 非常关注.NET。 我们也有 Java API 但是 NCache 本身是.NET 的重点。 我想对这两者做一个非常快速的概述,以便您了解这意味着什么,然后您可以访问我们的网站,实际上有一个完整的 对照. 您可以在此处进行功能比较。 然后你也可以下载这个。 所以,一定要看看这个。 它基于他们的文档和我们的文档。 所以,这不过是……这没有任何旋转。

NCache 也是开源的,所以是 Redis。 的情况下 NCache 你有……你可以访问我们的网站,你可以 下载 企业版或者开源或者你也可以去 GitHub,在哪里 NCache? 就在这里 GitHub上 然后你可以看到 NCache 这里也是。

因此,完全支持此企业版。 的情况下 Redis 微软移植 Redis 从 Linux 到 Windows。 因此,有人会认为微软会在 Azure 中使用该端口,但事实并非如此。 所以,他们拥有的港口有很多问题。 很多客户都向我们投诉过。

所以,如果您使用 Redis 在 Azure 中,他们使用 Linux 版本,它是稳定的,没有问题,但是你失去了我们刚才谈到的所有功能。 如果您想做本地支持, NCache 将为您提供任何开源都是免费的,企业是您获得的功能比您为支持支付的费用还多的东西。 如果你想在本地使用 Redis,您唯一的选择是使用 Linux 版本 Redis 实验室。 他们现在在 docker 中也有这个。 因此,您可以在 Windows 上技术上运行它,但仍然是它们的 Linux 环境。 Windows 的本地部署来自 Microsoft,正如我所说,它不稳定且没有支持。

在天蓝色 Redis 为您提供缓存服务模型, NCache 给你一个VM模型。 VM 模型为您提供了更多的控制权。 我们刚刚谈到的所有这些内容,包括通读、通写、缓存加载器、数据库同步,您可以获得所有的控制权,并且只需要一个客户端 API。

这只是对两者的简要概述。 我想提一下。 基本上, NCache 是 .NET 空间中最古老的缓存。 我们有大量的客户在使用 NCache. 他们中的许多人也在英国。 你知道,英国是我们的第二大市场,如果你有一个 .NET 应用程序,我希望你更喜欢整个堆栈都是 .NET。 NCache 为您提供 .NET 堆栈, Redis 没有。

在我结束这次演讲之前有什么问题吗? 但是你自己暴露了分区。 因为,在关系数据库中,您必须以数据驻留在其中一个或另一个中的方式对应用程序进行编程。 我的意思是 No SQL 的整个概念是他们为你做分片,因为一切都基于密钥。 在关系中,您有更多的复杂性,到目前为止,没有一个关系数据库能够解决可伸缩性问题。 他们一直在努力,他们的表现有了很大的提高。 有很多内存选项,所以,他们也有内存数据库,他们做了很多内存表和东西。 因此,性能已经提高了很多,但性能不是这里的问题。 你知道,问题在于可扩展性。 你能处理这个负载,到目前为止他们还不能。

因此,我们拥有索引的原因是您可以搜索这些属性。 因此,您可以执行 SQL 语句并搜索您被索引的对象的那些属性。

因此,我们所做的是除非您创建了索引,否则我们不允许您进行搜索。 所以,如果你搜索 NCache 会抛出异常说,这个属性没有被索引。 所以,以一种更痛苦的方式,是的。 但是,我们告诉客户的是,无论您要搜索什么,都必须创建一个索引。 而且,与一切都是 SQL 的数据库不同,这里的一切都不是通过 SQL 进行的。 同样,您只通过 API 做很多事情,然后一些事情是通过 SQL。

你的意思是缓存名称? 有一个约定,键应该有类型信息,然后基于某些,比如说,如果它是一个单独的对象,类型和主键值或主键属性名称,然后是值,那就是常见的事情,然后如果您要保存整个集合,例如,您要为客户保存所有其他订单,然后您可能希望根据客户获取它,那么键可以是客户、客户 ID、我的订单或其他内容像那样,你知道的。 因此,根据您想要获取数据的方式,密钥必须是有意义的。

是的,所有这些都是您可以选择的选项。 如果您观看我处理关系数据的视频,我会浏览所有这些选项。 而且,再次使用缓存,假设您在数据库中有一个多对多的关系。 在应用程序级别没有多对多。 在应用程序中,您可以从这一侧或从这一侧接近。 它始终是一对多的。 所以,像那样的事情突然改变了视角。

您不是要在内存中重新创建整个数据库。 你能回顾一下使用分布式缓存的好处吗? 你说这是可扩展性。 还有其他吗? 我认为,最重要的好处是可扩展性。 第二个好处是性能,同样对于用例,对于 ASP.NET 特定用例,会话,有一个巨大的好处。 因为,分布式缓存的替代方案都非常慢或不可扩展。 所以,如果你做一个 In-Proc,它是不可扩展的。 因为,您每次都必须执行相同的过程。

我也在录制这个,我认为 SDD Conf 也是如此。 我们将在 YouTube 上进行此演讲,如果您来到我们的展位并让我们扫描您,那么我们可以通过电子邮件将演讲的链接发送给您,然后您可以与您的同事分享。 非常感谢你们的耐心。

接下来做什么?

 

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

联系我们

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