在 360 年奥兰多 2016 度直播中谈话

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

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

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

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

什么是可扩展性

所以,让我们从一些定义开始。 我相信你们中的大多数人已经知道这一点,但为了完整起见,我们将对其进行讨论。 第一个定义是可扩展性。 那么,什么是可扩展性? 人们经常将可伸缩性与性能混淆。 性能实际上是应用程序的快速响应时间,但这可能仅适用于五个用户,如果您将其从五个用户增加到五千或 50,000 个用户并且性能保持良好,那么您的应用程序是可扩展的。 这就是我们想要实现的目标的概括。

在您拥有的任何应用程序中,如果您可以实现与五个用户或非常低的事务负载相同的性能,如果您可以在高事务负载下实现相同的性能,那么您是可扩展的。 如果五个用户的性能不佳,那么您还有其他问题。

线性可伸缩性

线性可扩展性更像是一种基础架构定义,即如果您的应用程序的架构方式是向部署中添加更多服务器,无论是添加更多应用程序服务器还是数据库服务器或其他任何东西,如果这可以线性增加事务容量时尚,那么你就有了一个线性可扩展的应用程序架构。

线性可扩展性

但是,如果您无法做到这一点,如果添加更多服务器并没有增加任何价值,那么就会出现根本性错误,并且您无法以线性方式扩展应用程序。 当然,这里的目标是能够以线性方式扩展。

非线性可扩展性

非线性将是,当您添加更多服务器时,您会看到增加,但在此之后的某个点不再增加,事实上,即使添加更多服务器,性能也会下降,因为应用程序的架构和部署存在一些瓶颈这是你无法克服的。

非线性可扩展性

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

这些通常是 Web 应用程序。

应用程序需要可扩展性

因此,这些是 ASP.NET for.NET 人员、Web 服务、物联网后端,这是一个非常强大的新兴空间和大数据处理。 大数据处理在 Java 端更为常见。 在 .NET 方面做这件事的人并不多,但大数据处理也是另一个领域。 而且,任何其他服务器应用程序,这可能是您的批处理应用程序。 您可能是一家金融服务公司,您有数百万客户,他们打电话和更改地址,或者他们正在将资金从一个帐户转移到另一个帐户,并且您有一定的合规要求,在半夜或您有什么完成这些处理,并且在后端,在工作流中,以某种方式发生了一些批处理。 因此,在时间限制下完成一定数量的事务的任何其他服务器应用程序都需要可扩展性。

可扩展性问题

那么,可扩展性问题在哪里? 我们讨论了线性和非线性可扩展性。 所以,可扩展性问题是应用层以非常好的线性方式扩展。 如果您有一个 Web 应用程序或 Web 服务,您的应用程序层,您只需添加更多服务器,没问题。 数据存储是瓶颈。 而且,当我说数据存储这个词时,我指的是关系数据库和大型机遗留数据。 我不是说 NoSQL database. NoSQL databases很棒。 我们还有一个 NoSQL 产品称为 NosDB 但没有 SQL 数据库并不总是答案。 如果您可以移动更多的数据,它们就是一个答案 NoSQL database 更多的是您获得的可扩展性解决方案。 但是,问题是您无法将所有数据移动到 NoSQL. 出于技术和业务原因,有很多数据必须保持相关性。

因此,关系数据库将继续存在。 就这个问题而言,他们不会去任何地方。 所以,你必须解决这个现实,或者处理这个你将要使用关系数据库的现实,但你仍然必须解决这个问题。 而且,您必须解决此问题的原因是您拥有我提到的所有需要​​可伸缩性的应用程序。

分布式缓存部署

而且,答案当然是在应用层和数据库层之间插入一个分布式缓存。

分布式缓存部署

因此,分布式缓存本质上是一个非常强大但又非常简单的概念。 您有两台或多台低成本服务器,它们聚集在一起,并且该集群将所有服务器的内存和 CPU 资源集中到一个逻辑容量中。 瓶颈和可扩展性来自三个方面。 一是内存,二是CPU,三是网卡。

所以,如果你有,比如说,这里有一台数据库服务器,你有 20 个应用层盒子,就硬件强度而言,一台数据库服务器可以占用它,你可以添加更多内存,更多 CPU,但是这是有限制的。 所以,答案是,能够拥有越来越多的不是很高端的服务器,事实上,它们不应该是高端的。 而且,在过去 10 年或更长时间中,我们看到最常见的配置是双 CPU 四核类型的等效配置。 所以说,一个8核的盒子和一个16核的盒子对于缓存服务器来说实际上是一个相当高端的配置。 8核几乎是常见的。

内存,当然,你需要很多内存,因为内存很便宜,所以这不是一个大因素。 您需要大量内存,为什么因为缓存是内存中存储,所以它将所有内容都存储在内存中,典型配置是每个缓存服务器中大约 16 到 32 gig 的内存,而 2 个缓存服务器是您应该拥有的最低限度出于冗余目的。 因此,通过拥有这种架构,您现在处于在应用程序层中添加更多服务器的情况。 您在缓存层中按比例添加更多服务器。 所以,通常情况下,4 比 1 或 5 比 1 的比例是我们认为最实用的比例。 在某些情况下,您可以超过 5 比 1。意味着 5 个应用程序服务器到 1 个缓存服务器,但您可以拥有的服务器数量没有限制。 你可以有 2 个,你可以有 4、10、20、30 台服务器,但是如果你在这里有 20 台服务器,你可能需要在负载均衡器环境中使用 XNUMX 台服务器。

因此,在某个阶段,这成为我们在网络或电子商务在线业务场景中看到的任何应用程序的高端。 因此,通过在此处添加更多服务器,这不再是瓶颈。 因此,分布式缓存实际上正在成为一种最佳实践。 如果您需要可扩展性。 因为现在,您不仅拥有一个用于其自身目的的数据库,您还需要对所有应用程序数据进行永久数据存储持久性,而且您还拥有这个非常快速且可扩展的基础架构,它现在是您的应用程序架构的一部分。 因此,当您编程时,您不再只是为数据库编程。 您一直在考虑缓存,因为缓存现在将确保您的应用程序即使在峰值负载下也不会变慢。 即使数据库的设计目的不是以同样的方式扩展。 所以,这是一张典型的照片。

大约 80% 的流量会被困住,或者 80% 的时间会访问缓存,20% 的时间会访问数据库,而这 20% 主要是更新,当然,有些读取是因为你需要将数据放入缓存,但您也可以预先填充缓存,还有很多其他方法可以做到这一点。 但是,通过如此显着地减少数据库层的流量,这就是您实现性能和可伸缩性的方式。

所以,这就是使用分布式缓存的情况。 为什么必须将其作为应用程序架构的一部分。

常见用例

所以,既然我们已经证明了使用分布式缓存,那么下一个问题是你如何使用它? 你在哪里使用它? 你应该对分布式缓存有什么类型的使用?

用例

应用程序数据缓存

嗯,最常见的用途是应用程序数据缓存。 这就是我刚才所说的,无论你在数据库中有什么数据,你都可以缓存它。 这样你就不必去数据库了。 需要记住的一点是,我将在后续幻灯片中更详细地讨论这一点,即在应用程序数据缓存用例中,数据存在于两个位置。 一是在数据库中,它总是必须在的地方,二是缓存。 那么,当数据存在于两个地方时,首先想到的问题是什么? 同步! 是的。

因此,任何无法处理这种情况的缓存都会迫使您缓存只读数据,即您知道永远不会更改的数据。 事实上,大多数人在谈到缓存时,会下意识地想到为什么它是用于只读数据的? 我真的不想缓存我的客户和帐户,以及每 30 秒更改一次的数据。 但是,研究表明,缓存的最大用途是在事务数据中,一旦你缓存了它,你可能会在接下来的一两分钟内需要它,无论是什么活动,无论你使用的移动窗口是什么。 那时您再次需要相同的数据,如果您可以从缓存中获取它,您就可以减少访问数据库的次数,并将其乘以应用程序中发生的数百万个事务,这将成为一个非常显着的提升。 因此,在我们继续前进时请记住这个问题,任何好的缓存都必须非常有效地处理它。

ASP.NET 特定缓存

第二个用例是,如果您有一个 ASP.NET 应用程序,那么会有很多临时数据。 瞬态意味着暂时的,您可以将其放入缓存中,并且这些数据并不真正属于数据库。 例如,数据库是永久存在的。 这是一个永久的商店。 那是你的主记录。 所以,一个 会话状态,你可能只需要保留它,只要用户在 20 分钟后登录,你知道的。 那么,为什么要把它保存在数据库中呢? 数据库没有那么快。 关系数据库不是为存储 blob 而设计的,会话通常存储为 blob。 因此,当您将会话存储在数据库中时,性能会受到很大影响。 因此,会话状态是 ASP.NET 将其放入分布式缓存的一个很好的用例。

而且,如果您不使用 MVC 框架,那么视图状态也在那里,它是一个相当重的数据,从 Web 服务器流向浏览器仅用于一个目的,即在回发时返回浏览器。 所以,这是一个相当长的旅程,正如他们所说的那样。 所以,如果你把它保存在服务器端并发送一个小密钥会更好。 所以,这是一个非常非常好的缓存用例。

第三个用例是页面输出,很多页面的输出不会每次都改变。 所以,如果它没有改变,为什么要执行页面,因为当你执行页面时,你正在消耗 CPU 和内存以及所有其他资源。 为什么不直接获取上次执行的输出并显示它。 因此,Microsoft 或 ASP.NET 有一个输出缓存框架,您可以在其中插入分布式缓存。 所以,现在在这个用例中,在ASP.NET下的这三个用例中,问题的本质已经完全改变了。 它不再是缓存和数据库之间的同步。 为什么? 因为没有数据库。 缓存是数据库。

现在问题的本质是......所以缓存在内存中,好吗? 这就是您获得所有性能的方式。 那么,当您将数据保存在内存中并且这是唯一的存储时,您最关心的是什么? 你可能会失去它! 如果那个盒子重新启动怎么办? 众所周知,Windows 会重新启动或回收工作进程。 如果我的意思是,即使 Linux 机器必须重新启动,但是,如果你的机器重新启动怎么办? 您准备好丢失这些数据了吗? 如果您是一家航空公司,并且该客户在点击提交价值 5,000 美元的最后一页时,有一张他们打算为夏威夷购买的家庭度假机票,突然它说,对不起,您必须重新开始! 你知道,他们经历了各种各样的飞行研究和检查时间,也做了谷歌航班,看看哪些匹配和所有其他的东西,这不是一个好的体验。

作为一家企业,您不想失去客户、购物车,也不想失去它。 因此,答案是分布式缓存。 如果它可以确保可靠性,您应该只保留会话或所有临时数据,如果它确保您永远不会丢失该数据,它确保它可以复制。 因此,一个好的分布式缓存可以跨多个服务器复制数据。 现在复制实际上是在浪费时间,只是为了我们刚刚谈论的那种意外情况而做额外的事情。 因此,复制的不利方面是它会影响性能。 因此,如果缓存不能智能地执行此操作并且其中很多都没有,那么当您打开复制时,您将看到性能下降。

通过事件共享运行时数据

因此,请记住这两点,第三个用例实际上是大多数人不知道的分布式缓存,一旦您在环境中拥有该基础架构,它就是一个非常强大的事件驱动数据共享平台。 因此,您可能有多个应用程序需要在工作流中共享数据。 您可能有一种发布/订阅类型的情况,您可能会为此使用消息总线、企业服务总线或消息队列。 分布式缓存是一个非常强大的平台。 由于您已经在内部拥有它,因此它实际上比其他选项更快且更具可扩展性,因为它是为性能而设计的,而其他应用程序则更多地是为共享而设计的。

因此,多个应用程序之间共享的事件驱动发布/订阅类型。 一个应用程序产生一些数据,将其放入缓存中,触发一个事件。 还有其他应用程序对该事件感兴趣,我想在可用时使用这些数据。 因此,他们接收到事件,并且一个应用程序可能在这里,一个应用程序可能在这里,这成为他们都可以利用的非常强大的可扩展事件引擎。

所以,这是第三个用例。 即使在事件中,在运行时数据共享功能或用例中,大部分数据都是瞬态的。 尽管它是从永久数据中派生的,并且它可能会从该永久数据中重新创建它,但要做到这一点需要做很多工作,而且这些数据通常是临时的,因为它的性质使用临时的。 通常不会,不需要保存在数据库中。 它只需要被消耗。 因此,缓存再次成为唯一的存储,因此就像会话和其他问题一样,可靠性必须发挥作用。因此,这些是使用分布式缓存的三种常见方式。

所以,这三个用例的好处是不需要编程,因为 ASP.NET framework 允许您插入第三方提供商。 因此,例如,对于会话,如果您要进行会话,我将快速向您展示一个快速示例,您所要做的就是转到 Web 配置,当然,在 ASP 中.NET core,这个范式会稍微改变,但想法是一样的。

配置 ASP.NET 会话缓存

因此,如果您转到 Web.config,这只是一个简单的 ASP.NET 应用程序。 您转到 Web.config,您需要首先添加您要使用的任何缓存的程序集,以防万一 NCache,您只需在 NCache 会话存储提供程序,您只需复制粘贴,而您真正需要做的第二件事就是在此处进行更改。

因此,网络中有一个会话状态标签,您需要在其中配置您需要确保模式是自定义的并且超时是您的超时时间。 并且,如果发生 NCache,那么你实际上只需要添加这一行,还有一堆其他参数,你可以指定我不会进入,但其中一个只是缓存的名称。 的情况下 NCache,所有缓存都被命名了,我实际上也会给你一个演示,但是。 因此,您只需指定缓存的名称。 缓存已经创建。 这就像一个连接字符串,它告诉您要连接到哪个缓存,因为您可能有多个缓存,一个用于会话,一个用于应用程序数据,仅此而已。 我的意思是你做了这个改变,你只是做一个健全性测试,检查你的应用程序的所有常见用例,你的应用程序突然准备好将会话存储在一个 分布式缓存 NCache. 所以,最简单的受益方式和最大的收获实际上是会话。

因此,这就是您在分布式缓存中使用会话状态所需要做的一切,例如 NCache 或任何其他视图状态输出缓存也是如此。 这都是基于配置的更改。 我不打算深入讨论它们中的每一个。 我只是想向您展示这个作为示例。

应用数据缓存

所以,让我们来谈谈分布式缓存的核心,我说核心是因为你大部分时间都将花在这上面。 如果您选择合并分布式缓存,您将在大部分时间进行应用程序数据缓存。 那么,典型的 API 是什么样的呢?

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");

如果你们知道 ASP.NET 缓存对象, NCache 尽管我们是超集,但我们试图尽可能地模仿它,所以还有更多。 每个缓存都有自己的 API。 这是什么 NCache API看起来像。 您连接到缓存,它是一个命名缓存。 你得到一个缓存句柄,你把那个缓存句柄保存在你保存的应用程序周围和内部,只需执行 Cache.Get。 获取、包含、添加、插入、删除,还有添加异步、插入异步。 插入意味着如果它不存在则添加或如果它已经存在则更新。 这与您使用的 ASP.NET 缓存对象的术语相同,这也是我们也使用它的原因。 而且,Async 方法基本上意味着您不必等待该操作完成。 您实际上可以,还有第三个参数是您可以指定回调。 因此,如果出现问题,您的回调将被调用,否则您几乎可以假设一切正常。

保持缓存新鲜

因此,当我们在这里讨论应用程序数据缓存时,最大的担忧是您必须保持缓存新鲜。 所以,一个好的分布式缓存必须允许你这样做,因为如果它没有,它会强制你缓存只读数据。 无论如何,只读数据约占数据的 10% 到 15%。 那么,如果您只缓存应缓存的 10% 到 15% 的内容,您将如何真正从该缓存中获益呢? 因此,您要做的是缓存所有数据,实际上是所有数据,很少有数据会出现在您说缓存没有任何意义的地方。 但是,几乎所有的数据。 您将在短时间内缓存的一些数据。 因此,一旦您缓存了该数据,这就是所有应用程序数据,最难的缓存确保缓存是新鲜的,它可以做的不同方式是过期。

保持缓存新鲜

使用基于时间的过期

到期是绝对到期,并且存在滑动到期。 即使它们都是过期的,它们2具有非常不同的含义。 绝对过期是您应该做的以保持缓存新鲜,因为您正在猜测您所说的,我正在将此客户对象保存在缓存中。 我认为在五分钟内缓存是安全的。 你只是在做一个猜测,这是一个有根据的猜测,但它是一个猜测。 在五分钟内,您希望没有人会在数据库中修改它,但如果他们这样做,那么您的缓存将与数据库不一致。 另一方面,滑动过期与保持缓存同步无关。 它与驱逐有关,或者与缓存的自动清理有关。

所以,会话,你是说当没有人登录时,在 20 分钟不活动后删除会话。 所以,你做的就像一个清理工作。 你说缓存请清理它,为我清理它。 我不想跟踪所有这些。 我已经把它放在缓存中,我已经指定了它应该在缓存中保留多长时间,即使没有人触摸它,然后清理它。 因此,与绝对到期和滑动到期相比,永久到期的目标非常不同。 因此,滑动到期,您将用于临时数据的会话。 绝对到期,您将用于永久数据。

我想使用的另一个术语是参考数据与交易数据。 参考数据是不经常改变的数据,但它确实改变了,它不是只读的。 它是您的产品表,价格可能每天或每周或某事都发生变化,但它不像客户对象或活动对象或某事或订单对象那样频繁。 所以,事务数据就是我们想要缓存的。 当然,参考数据是我们想要缓存的给定数据,但事务数据也是我们要获取所有数据的地方。 因此,如果到期时间不足以确保您的缓存保持新鲜,那么您需要拥有更多功能。

使用数据库依赖

所以,下一个特性,一个好的分布式缓存必须具备的一个非常强大的特性是,它应该能够在不涉及您、不让您监视事物的情况下将缓存与数据库同步。 所以,你应该能够告诉缓存我正在缓存这个对象。 这与数据库中的这个数据集有关。 所以,请监控数据库中的这个数据集。 看看有没有变化,请去做一两件事,要么从缓存中删除这个项目,删除意味着下次应用程序想要它时,它不会在缓存中找到它。 当您在缓存中找不到它时会发生什么? 你从数据库中得到它。 所以,这就像获得一个新副本或第二个它可能只是自动重新加载一个新副本。 自动重新加载新副本需要另一个称为通读的功能,我将对此进行讨论。

所以,我会回到那个,但是 数据库同步 是一个非常非常强大的功能。 这让您高枕无忧,以确保您的缓存保持新鲜。 您不必担心要缓存的任何数据,并且有不同的方法可以将缓存与数据库同步。 最常见的是 SQL 依赖项,它实际上是 ADO.NET 或 SQL 服务器功能, NCache 用途。

因此,例如,我将实际向您展示我应该展示的代码。 所以,让我快点……我将快速向您展示代码的样子。 那去哪儿了? 所以,如果你有一个 .NET 应用程序,假设这是 NCache,当然,你会引用两个 NCache 库。 NCache.运行时和 NCache.Web。 因此,我们再次尝试将其命名为接近 ASP.NET 缓存对象命名空间,因此 NCache.Web。 当我们在 2005 年问世时,ASP.NET 缓存对象是唯一的缓存,所以我们是这个领域中最古老的,所以我们选择这个名称是为了方便人们使用。 因此,在应用程序中,您将包括几个 NCache 命名空间。 然后,您将连接到您的缓存,您将获得一个缓存句柄,现在您有了一个缓存句柄,假设您创建了您的对象并想要执行 Cache.Add。 所以, Cache.Add 需要一个键。 请注意,键实际上是一个字符串,所以我们遵循了这一点。 好吧,这不遵循该命名约定,但通常是 Customer:CustomerID: 无论该客户的 ID 是什么,因此您执行 Cache.Add 之后,然后您,在这种情况下,它指定一分钟绝对到期。 话说不要做任何滑动到期和所有其他事情。 因此,这只是为了让您了解缓存的外观。

非常易于使用,非常简单的 API,比做 ADO.NET 或任何其他编程要简单得多。

缓存是什么样的?

让我实际上,让我实际向您展示缓存的外观,但具有实际缓存。 所以,我有这些虚拟机和 Azure。 所以,我有演示 1 和 2 两个。 这是我将要使用的两个缓存服务器。 这些是缓存虚拟机,我将拥有我的应用程序服务器。 我只是将其称为演示客户端。 因此,我的应用程序将在演示客户端上运行。 好的! 所以,我有远程桌面。 我要去以防万一 NCache 我将运行这个名为 NCache 经理,我这里确实有。 而且,我会继续创作。 让我快速确保没有该名称的缓存。 好的! 所以,我将继续创建一个新的缓存。 我将调用我的缓存演示缓存。 我将把其他所有内容作为默认值。 我将选择一个缓存拓扑。 我不打算详细介绍,但这种缓存拓扑同时进行分区和复制。 因此,当您执行此拓扑时,您的缓存将如下所示。

缓存拓扑

因此,这些是您的缓存服务器。 所以,一些数据,这 1 2 3 4 是数据元素。 因此,一些数据在分区 1 中,一些数据在分区 2 中,每个分区都备份到不同的服务器上。 所以,如果你在这里有 3 台服务器。

分区副本

假设您有分区 1 2 和 3,服务器 2 有分区 1 的副本,服务器 3 有分区 2 的副本,服务器 1 有分区 3 的副本。所以,缓存实际上是一个服务器。 它实际上不止一台服务器,它位于一个集群中。 他们彼此认识,我现在要尽快带你回到这个话题。 所以,假设我选择了一个分区副本拓扑。 我将选择演示 1 作为我的第一个缓存服务器。 为什么这么慢? Demo 2 作为我的第二个缓存服务器。 我想这可能是因为互联网很慢,也许吧。 我不知道。 所以,我有一个两节点缓存集群。 所以,演示一和二现在互相了解了。 所以,他们将在这个端口上互相交谈。 在我可以更改的端口 7802 上。 为什么这么慢? 确保。

好的! 所以,接下来我要指定缓存应该有多少内存。 所以,它有一场演出,正如我所说,你可能会有 13 场演出或其他什么。 然后,我将指定最近最少使用的驱逐策略。 我会节省 15%...对不起,驱逐 5% 的缓存。 这真的很慢,我不知道发生了什么。 这整个盒子很慢,连点击都是,连CPU都没有,耶! 看起来像。 是啊,就是!

好的! 因此,基本上,您有一个逻辑上称为缓存的服务器集群,您仅通过演示缓存了解它们。 在你的盒子上,比方说,你的应用服务器盒子,比方说 NCache 安装在这里。 您将拥有一个配置文件,其中包含该缓存名称和代表它的服务器列表。 因此,这只是一个起点,但您将再次知道整个集群只是一个缓存名称,您连接到它,然后您的客户端 API 将连接到此图中的所有缓存服务器。 在分区副本的情况下,每个客户端都与所有服务器通信,因此它可以直接进入数据所在的位置,即分区部分。

我将继续为此添加一个客户端,这是我的演示客户端。 我要继续点击缓存助手,需要很长时间才能点击,我会说启动缓存。 所以,只要说缓存将在这两个盒子上启动。 NCache 是一个基于 Windows 的缓存,因此它具有一个好的基于 Windows 的产品所具有的所有易于使用的功能。 因此,您可以从一个中心位置完成所有这些操作,您也可以通过脚本来完成所有这些操作。

数据库同步 - 演示

那么,让我向您展示一下数据库同步是什么样的。 因此,例如,您所做的是,再次它是相同类型的应用程序,您拥有缓存,当您尝试将数据添加到缓存中时,假设您正在执行 Cache.Add here,这是当然 NCache 代码,您指定一个 SQL 缓存依赖项,它是 NCache 类,但它在后端映射到 SQL 服务器 SQL 依赖类。 并且,您向它传递一个 SQL 字符串,然后由 NCache 连接到数据库,缓存服务器现在成为数据库的客户端。 因此,例如,如果您的应用程序在这里,假设您的代码在这里运行,您刚刚发出了这个调用。 哎呀,对不起! 您刚刚发出了该广告的缓存调用,并传递了此 SQL 缓存依赖项。 客户端将所有这些发送到缓存服务器。

所以,缓存服务器之一或多个。 而且,缓存服务器现在打开了与数据库的连接,因为您在这里也指定了连接字符串。 而且,这种连接强度当然是池。 所以。 如果多次指定相同的连接字符串,则后端有一个连接池。 因此,另一个缓存现在已成为您数据库的客户端。 它将监视您的数据库,因此数据库将通知 NCache 您要求我监控的此数据已更改的服务器以及 NCache 此时服务器可以决定是从缓存中删除该项目还是从数据库中重新加载它。 而且,要重新加载它,您必须真正通过通读功能。

好的! 所以,这是一种方法。 它真的很强大。 它是事件驱动的。 一旦发生变化,数据库就会通知缓存,缓存会立即采取行动。 但是,这个数据库服务器端有开销,因为每次执行 SQL 缓存依赖时,都必须在 SQL 服务器中创建一个数据结构来监控该数据集。 现在,如果你有 1 万个这样的数据,我可以保证你的 SQL 服务器会崩溃。 再说一次,既然我们在谈论可扩展性,你需要考虑非常大的数字。 所以,如果你有数千或数万个这样的,没问题。 但是,如果您有数十万或数百万个,那么不同的策略将是更好的策略。

数据库依赖

另一种策略称为数据库依赖,这是我们自己的 NCache 功能是基于轮询的依赖项。 我们已经在哪里实现了这个。 有一个特殊的表,我们要求您修改触发器,以便您可以更新该表中相应行的标志,然后每当您从缓存中执行数据库依赖时,缓存会在该表中创建一个条目,然后在一次提取中,缓存可以获取数千行标志为真,更新已经发生。 所以,这就像我们自己的跟踪方式。 它是基于轮询的,所以它不是即时的。 默认情况下大约 15 秒延迟,但您可以重新配置。 你也不想拉得太频繁。 所以,这是另一个,但即使有限制,如果该表中有 1 万行带有真假标志,索引看起来会很大,对吗? 有一个真索引和一个假索引,它们是树的两个节点。 因此,DB 依赖比 SQL 依赖更有效,但不是实时的,但即使它也有局限性。

CLR 程序

第三个是 CLR 过程,您实际上可以从数据库中的触发器调用 CLR 过程,因此无论何时添加、更新或删除任何项目,您都可以调用该过程。 该过程对缓存进行异步调用。 它说请从缓存中添加或更新或删除此项目。 异步之所以重要,是因为您不想延迟事务,即数据库事务。 否则它将开始超时。 因此,异步调用将立即返回,并且至少可以提交数据库事务并且可以更新缓存。 因此,缓存与数据库的同步是关键特性。

将缓存与非关系同步

如果您有非关系型,或者您可能有大型机或遗留或任何其他数据源,您可能有云数据源,您可能想要进行 Web 方法调用,甚至检查该数据是否是否更新和 NCache 允许您拥有此自定义依赖项功能,您的代码可以监控 NCache,每隔一小段时间调用你的代码,你去监控你的数据源,看看数据是否改变了,如果有你通知 NCache 和 NCache 将以相同的方式删除或重新加载。

关系数据的处理

因此,保持缓存新鲜是至关重要的。 任何不允许您这样做的缓存都会限制您受益的能力。 我将跳过对关系数据的处理,尽管这不是什么,让我快速说一下,你有一对多的关系,一对一的关系。 因此,如果您在缓存中有一项,并且在缓存中也有许多项,那么当您从逻辑上删除缓存中的一项时,也应该删除许多项,因为如果您从数据库中删除了这些项会怎样。 因此,缓存应该能够跟踪所有这些。 您可以在您的应用程序中执行此操作,但这只会使您的应用程序信用复杂化,因为现在您正在为缓存进行大量簿记。 就像您在应用程序中构建数据库同步或数据完整性代码一样,这不是您的应用程序的工作。 您不会为数据库这样做。 数据库会为您执行此操作,因此缓存也应为您执行此操作。

读通和写通

所以,通读、通写是你的缓存应该具备的另一个非常强大的特性。 通读基本上是,同样,这个概念非常简单。

读通写通

您实现一个接口,以防万一 NCache 您在这里实现了一个名为 read-through provider 的接口。 你能看到吗?

阅读提供者

是的,它有三种方法。 缓存启动时会调用一个 Init,以便您可以连接到数据源。 当缓存停止时,您可以进行清理,并且大多数情况下您将从源代码调用此加载。 因此,它通过了您的密钥。 关键是您要知道的关键,即要获取数据源中的哪个项目,然后将其归还,以防万一 NCache 提供者缓存项。 而且,您可以在此处指定到期和重新同步,各种标志,然后将其传递给 NCache. NCache 缓存它。

那么,通读是如何工作的呢? 我们通过工作的方式是,您的应用程序总是询问缓存。 它说 Cache.Get。 如果缓存没有数据,而不是说我没有,它会从数据库中获取数据。 因此,您的应用程序突然变得更加简单。 许多持久性代码,您刚刚从您的应用程序中取出。 因此,通读的一个好处是您已经在某种程度上简化了代码,您已经将其全部封装到缓存层中。 缓存层现在拥有越来越多的持久层。 并非所有代码都可以通过通读完成,但很多代码都可以。

到期重新加载

通读的第二个好处是我之前谈到的重新加载功能。 现在想象一下,如果您有一个电子商务应用程序并且您的价格发生变化,并且每次价格变化时,这些项目都必须从缓存中删除并重新加载,但它的流量确实很大,所以当它们被删除时,很多客户端请求都会命中数据库。 第一个将获取它并将其放入缓存中,但直到那时缓存突然有很多不必要的流量,如果这种情况继续发生,如果你有很多这种情况发生,数据库将会得到很多不必要的命中如果您只是说到期时重新加载,则可以避免这种情况。 那么,重新加载过期,有什么作用? 它不会在过期时删除该项目。 它只是重新加载它,因此当它到期时,缓存将调用通读并从您的数据源中获取它并进行更新。 所以,只有一个更新操作发生。 没有删除和添加操作,因此数据或项目始终在缓存中。 所以,缓存现在突然变成了。 它可以照顾自己,并且可以在需要重新加载数据时自行重新加载。

直写

所以,这是一种非常强大的通读能力。 因此,当您将其与过期相结合时,您也可以通过数据库同步来做到这一点。 当数据库同步再次发生时,为什么要删除它? 只需重新加载。 另一个功能是直写,它的工作原理与直读类似,只是它会写入。 它还有一件事,它还可以进行批量写入。 而且,我会稍微解释一下它进行批量写入的原因。 所以,同样有一个 Init,有一个 dispose,现在有一个对数据源的写入。 写入并不意味着仅添加或插入。 它也可以是删除,因此写入具有操作类型,然后可以添加、更新或删除。 而且,这取决于缓存操作是什么。 然后,您也可以批量执行此操作。 因此,就简化代码而言,直写具有与直读相同的好处,但又具有另一个好处。 因此,通读具有重新加载的好处,而直写具有可以在后面写的好处。

后写

而且,write-behind 是一个非常非常强大的功能。 为什么? 因为数据库更新是一个瓶颈。 同样,数据库是您必须忍受的必要邪恶。 你不能没有它,但它会在你的应用程序中造成各种瓶颈。 因此,您对它的依赖越少,您的应用程序就越好。 事实上,你不能没有它你仍然必须拥有它。 那么,后记有什么作用呢? 它说您更新缓存的速度非常快,至少比数据库快十倍(如果不是更多的话),然后缓存负责数据库更新。 所以,有一个异步直写,这是一个后写。 所以,你会去更新缓存,回来继续你的东西,缓存去更新数据库。

当然,缓存必须解决很多问题。 一说缓存要更新数据库,缓存服务器崩溃了怎么办? 那个队列会发生什么? 所以,万一 NCache,如果任何服务器出现故障,队列本身将被复制到多个服务器,您不会丢失队列。 然后还有重试。 如果该更新失败,那么您可以重试。 您还可以进行批量更新。 所以,有一堆你可以做一个批量更新。 因此,它可以进一步优化事物。 所以,直写和直读是非常非常强大的功能。 这称为服务器端代码。 这是位于缓存集群上的代码。 它位于此处,并将该代码保留在服务器上可以简化您的应用程序。 因此,您下推的代码越多,应用程序就越简单。

数据分组

好的! 现在,假设您确信应该使用缓存。 您有不同的用例,现在您有信心缓存大量数据。 所以现在,缓存已经开始看起来像数据库了。 它开始有很多,您将在缓存中拥有数百万个项目。 那么,当缓存中有数百万个项目时,仅基于键读取内容是否好? 不! 如果是基于键从缓存中读取项目的唯一方法,那么与您可以做的事情相比,您的应用程序将非常具有挑战性,那么根据这个搜索条件给我所有的东西。

数据分组

所以,搜索和分组成为一个缓存的一个非常非常强大的需求或者非常重要的需求。 同样,正如我所说,目的是让您了解有什么好处。 好处是您可以缓存越来越多的数据。 您缓存的数据越多,您就越需要查看它或拥有更多的数据库类型的功能。 这些功能之一是能够执行元数据。 在数据库中,您可以对许多不同的属性进行索引。 在这里你可以做标签,命名标签,实际上当你缓存对象时,以防万一 NCache 它还允许您创建索引。 因此,您可以索引一个对象。 假设客户可以在城市属性上被索引,因为您要在城市上搜索,所以它应该被索引。 如果它没有被索引,那么搜索将是非常痛苦的。 想象一下,您必须首先反序列化数百万个项目以检查每个对象,以便了解奥兰多的哪些客户。 不是一张好照片,不是一个漂亮的景象。

因此,从编码的角度再次对子分组标签和名称标签进行分组非常简单。 我将快速向您展示这一点。 从录音的角度来看非常容易使用。 您添加了一堆项目并为其分配标签,然后,对不起! 组和子组,组子组,然后您说获取组数据,或者您也可以进行 SQL 搜索并说给我所有组名称为电子产品的产品对象。 因此,分组和子分组标签和标签也是 AppFabric 顺便提一下 AppFabric XNUMX月停产。 我们有更多的时间,我要加快速度。

查找数据

同样,查找数据与分组数据有关,您希望能够基于 SQL 搜索数据,所以我想我……对象查询语言在哪里? 它在那里。 所以,我可以,基本上,我有一堆数据,我可以发出一条 SQL 语句,我可以指定多个属性并传递参数,我会得到一个记录集,以防万一 NCache 就像 SQL 服务器一样,它是完整 SQL 的一个子集。 它不做关节,但你可以做分组和标记而不是加入,这就是你可以将多个对象组合在一起的方式。

查找数据

因此,对于 LINQ, NCache 已实现 LINQ 提供程序,因此 Iqueryable 接口。 你去拿那个收藏品 NCache 然后像对任何其他对象集合一样执行 LINQ 查询,它将继续为您获取这些对象的集合,即产品对象。 因此,如果 LINQ 是您在搜索方面真正的舒适区,请使用 LINQ 进行搜索。 当您发出此查询时,您将进入集群,相同的查询将被发送到所有服务器,结果将被合并,然后显示给您。 所以,它可能,虽然在这里看起来很简单,但在幕后有很多工作正在完成 NCache.

所以,我们有 SQL 和 LINQ。 我们也有批量,正如我所说,您可以进行索引。

运行时数据共享

我很快就会……有基于键的事件,有缓存级事件,有发布子事件,有一个连续查询。

运行时数据共享

连续查询是一项类似于 SQL 依赖项功能的功能,只是它位于缓存上。 您要求缓存为您监控数据集。 所以,就像我们使用 SQL 依赖并要求 SQL 服务器监控这个数据集并说如果这个数据集发生变化,请通知我。 现在,你问 NCache,请说,这是我的 SQL 语句,选择 Customer.City 等于 New York 的客户,您是说如果从缓存中添加、更新或删除任何符合此条件的客户,请通知我,这可能是任何地方网络,缓存集群上的任何地方,你可以是任何其他客户端。 您会收到通知。 因此,通过现在拥有这些类型的功能,您可以突然监控缓存发生的情况并收到通知而不是轮询事物,这就是我所说的缓存成为真正强大的运行时数据共享平台。

高可用性

好的! 我也打算跳过这个。 我的意思是你使用的任何缓存都必须是动态的。 它必须提供高可用性,以防万一 NCache,它有一个点对点的架构。

高可用性

客户端缓存

我确实想让你知道有一个功能叫做 客户端缓存. 有人称它为近缓存。

近缓存

这实际上是一个位于应用程序服务器本地的缓存。 它就像一个独立的缓存,只是它不是独立的。 所以,它甚至可以是 InProc。 它可以在您的应用程序进程中,这意味着您实际上是在对象堆上获取东西。 您的堆具有对象形式的数据。 没有什么能比得上这种表现,对吧? 如果您可以从堆中获取数据而不是转到缓存本地盒 OutProc,因为当您跨进程时,它必须通过 IPC,它必须进行序列化,反序列化,当您通过网络时,它甚至更多,当你去数据库它是非常昂贵的,相对而言。

因此,这是您的应用程序进程中的本地缓存或盒子上的本地缓存。 但是,它保持同步。 您无需为客户端缓存进行任何特殊的 API 编程。 您只需调用缓存,以防万一 NCache,它只是插入配置更改并拦截调用,并且无论您获取什么,它都会在本地保留一份副本。 因此,下次您获取它时,它会自动从本地缓存中获取它。 性能上的巨大提升。 这是只有 NCache 在.NET 方面。 在 Java 方面,还有其他具有客户端缓存的产品,但在 .NET 上仅此而已。 这就像缓存顶部的缓存,这就是很多人从独立 InProc 缓存转移到分布式缓存时抱怨的原因,我的性能实际上已经下降,我的应用程序更慢,我认为分布式缓存是应该提高我的性能,我们告诉他们不应该提高可扩展性。 没有任何东西可以匹配本地 InProc 缓存,没有人可以。 我的意思是这不是我们可以发明和做的事情。 您正在跨越流程,这是需要的成本。

因此,我们说得好,克服这一挑战的一种方法是使用客户端缓存。 因此,客户端缓存又是一个子集。 通常,每个缓存服务器中有 16 到 32 个演出。 所以,如果你有三到四台服务器,你可能有大约一百多个缓存数据,客户端缓存可能是一个,可能是两个,可能是三到四个,每个最大值取决于你有多少工作进程有。 如果您只有一个工作进程,请将其设为四个 gig。 如果您有八个工作进程,我们的许多高端客户在他们的 Web 层上都有,那么您不希望仅在客户端缓存中有四倍八。 因此,也许,最好有一个 XNUMX gig 的进程外缓存,这仍然比进入缓存层要好。 它仍然更快,或者您可以拥有更小的一演出或少于一演出的缓存,即 InProc。 现在,您有八个副本,但它们也是同步的。 因此,如果您要从缓存中获得价值,那么您必须考虑使用客户端缓存。

现在,我的目标不是向您推销任何缓存功能,而是说明一个好的缓存必须具备的条件以及您将在 Java 方面找到的许多这些功能。 Java 在缓存方面是一个更加成熟的市场。 他们使用内存数据网格这个词而不是分布式缓存,但无论您看到什么功能 NCache,您会在 Java 端看到其中许多,但在 .NET 端 NCache 是唯一的一个。

广域网复制

另一个特点是,如果你有多个数据中心,你会希望你的数据库被复制,那么为什么不缓存呢? 你会怎样做? 你要重建整个缓存吗? 购物车呢? 会议怎么样? 因此,多个数据中心已成为现实,而云使这一切变得更加容易,因为您无需付出任何努力。 你只是去说区域一和区域二,你有两个数据中心,对吗? 但是潜在的问题并没有消失,如果您使用不支持 WAN 复制的分布式缓存,您就会陷入困境。 如果没有复制缓存,您就无法拥有主动-主动甚至主动-被动的多数据中心解决方案,这是非常重要的功能。

万复制

NCache 当然有这个。 我已经为您提供了动手演示。 NCache 是市场上最古老的 .NET 缓存。 我们是在 2005 年推出的,比它老得多。

NCache vs Redis

所以,我要快速过去 NCache 与 Redis,非常非常高的水平,那是因为 Redis 是不是很多人来问我们,你和我们相比如何? Redis 因为微软为 Azure 选择了它们。

redis航班吗ncache

Redis, 是一个很棒的产品。 它超级快。 它主要来自Linux方面。 它没有很多功能。 它不会在功能上获胜。 它只是因为它来自 Linux 方面而获胜,而微软希望占领 AWS 市场,因此他们无法采用 .NET 解决方案。 他们不得不采用多平台。 所以,他们的 Linux 版本非常稳定,非常好,但是微软自己做的 Windows 移植是一种孤立的移植。 微软自己不使用它。 当您在 Azure 中并使用 Redis,您没有使用 Windows 端口 Redis,您使用的是 Linux 版本。 所以,如果你没有使用 azure 并且你将使用 Windows 端口 Redis, 谨防。 我的意思是没有人拥有它。 Redis 实验室,如果你去他们的网站,他们甚至没有 Windows 下载。 我的意思是他们只有 Linux 下载,它是 Redis. 微软,正如我自己所说的那样,就使用承诺而言,他们并没有把钱放在嘴边。

所以, NCache 对您来说是唯一可行的选择,而且它是开源的,所以如果您没有钱,请使用免费的开源版本。 如果您的项目很重要并且您想要支持和更多功能,即企业功能。 企业 NCache 建立在开源之上。 它不像一个单独的东西。 开源不是孤儿。 我的意思是我们拥有它,我们维护它,企业建立在上面。 因此,开源必须是稳定的,但如果您想要支持和更多功能,那么只需购买企业版。

我们是原生的 .NET。 我们使用 c-sharp 进行开发,并且获得了 Windows Server 2012 r2 认证。 我们也将很快得到下一个。 所以,我们的意思是,就微软而言,我们并不处于领先地位。 我们几乎就是 .NET,这就是我们的样子。 我们有一个 Java 客户端,但几乎所有购买的客户都使用我们的 Java NCache 对于 .NET,因为他们在内部拥有它,所以他们也从 Java 中使用它。 因此,我们的生计和整个生存都在 .NET 上。 所以,我们总是会成为最新和最伟大的,第一个和最简单的。

接下来做什么?

 

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

联系我们

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