我们可以在我们的应用程序和数据库之间放置一个缓存服务器,以使我们的应用程序更快。 但当我们需要扩展我们的应用程序时,这还不够。 让我们看看两种缓存模式以获得更好的性能以及如何 NCache 实施它们。
通过数据分区实现可扩展性
通过数据分区,我们将大数据集分成较小的数据集,并将它们分布在节点之间。 这样,我们在节点之间拆分读取和写入,从而提高应用程序的整体性能。 NCache 支持不同的 缓存拓扑. 在此上下文中,拓扑是一种数据存储、复制和客户端连接策略。 有两种实现数据分区的拓扑: 分区和分区副本拓扑. 在这两种拓扑中, NCache 将数据划分到桶中并将这些桶放在我们集群的节点中。
NCache 使用 1000 个桶并将它们平均分配给集群中的节点。 例如,如果我们用单个节点启动一个缓存集群, NCache 将所有桶分配给我们的单个节点。 如果我们添加另一个节点, NCache 将这 1000 个桶分成两个 500 个桶的节点。 另外,如果我们删除一个节点, NCache 将它的桶分布到剩余的节点中。
自 NCache 将我们的数据分成桶和节点,缓存客户端连接到所有节点,但直接在包含项目的节点上执行读写操作。 即使节点不可用,缓存客户端也会使用活动节点重新路由我们的请求以完成我们的操作。 NCache 在节点之间分配桶,使每个节点中的数据大小几乎相同。 这样,我们不仅可以在节点之间拆分读取和写入,还可以通过添加每个节点来增加集群的存储容量。
由于数据分区、分区和分区-副本拓扑可扩展事务负载和存储容量。 当然,Partition 和 Partition-Replica 只是支持的拓扑结构中的两种。 NCache 有更多 拓扑结构 具有不同的数据存储和复制策略。 例如,其中一些适用于具有更多读取或写入的应用程序。
缓存策略
通过数据分区,我们提高了应用程序的可用性和性能,因为我们可以在集群中缓存比在单个服务器中缓存更多的项目。 此外,我们可以通过选择填充缓存的方式来提高应用程序的性能。 有两种策略来填充我们的缓存:cache-aside 和 Read-Through/Write-Through。
使用缓存端策略,我们的缓存服务器位于我们的数据库旁边。 如果我们的缓存不包含某个项目,我们的应用程序会从我们的数据库中读取它并将其存储在缓存中。 使用这种策略,缓存服务器不会直接与我们的数据库交互。 可能,当我们想到缓存时,缓存端策略是我们首先想到的。
与 cache-aside 策略不同,使用 Read-Through/Write-Through 策略,我们的缓存就像数据的主要来源一样工作。 在这里,我们的缓存从数据库读取数据并将数据写入数据库。 因此,这些策略更适用于我们经常读取和定期更改的参考数据,以及我们可以轻松映射到缓存项的数据库行。
通过 Read-Through/Write-Through,我们将一些数据访问代码从我们的应用程序移到缓存中,使我们的应用程序代码更简单、更小。 NCache 支持Read-Through和Write-Through缓存策略。
直读缓存
NCache 如果存在缓存未命中,则使用自定义的 Read-Through 提供程序调用基础数据库。 另外,我们可以强制 NCache 始终读取数据库,即使我们没有缓存未命中。 我们的 Read-Through 提供者应该实施 IReadThruProvider 接口. 它包含类似的方法 从源加载 和 从源加载数据类型.
一旦我们有一个 通读提供程序 部署到我们的缓存服务器,要么通过 NCache Manager 或 PowerShell 脚本,我们可以从客户端应用程序中使用它,将 ReadThruOptions 对象作为参数传递给 Get 方法,如下所示,
1 2 3 4 5 6 7 8 9 10 11 |
// After having NCache up and running... var key = $"Product:123456"; var readThruOptions = new ReadThruOptions { Mode = ReadMode.ReadThru }; // Retrieve a cached item with Read-Thru enabled var data = cache.Get<Product>(key, readThruOptions); // Do something with the cached product here... |
直写缓存
另一方面,通过直写策略, NCache 首先更新我们的缓存,然后才更新我们的数据库。 NCache 可以同步或异步更新我们的数据库。 NCache 调用异步直写式更新:Write-Behind。
我们的 Write-Through 提供者应该实现 IWriteThruProvider 接口. 它包含带有单个和多个项目重载的 WriteToDataSource 方法,以及 数据结构. 我们的 Write-Through 提供者应该支持写入操作来添加、删除和更新项目。
类似于部署一个 Read-Through provider,我们需要部署我们的 直写提供程序 到我们的缓存。 一旦我们部署了我们的提供者,在我们的客户端应用程序中,我们应该通过 直写选项 将项目插入缓存时的对象,像这样,
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// After having NCache up and running... var product = BuildProduct(); var key = $"Product:{product.ProductId}"; var cacheItem = new CacheItem(product); var writeThruOptions = new WriteThruOptions { Mode = WriteMode.WriteThru; } // Add an item with Write-Thru enabled cache.Insert(key, cacheItem, writeThruOptions); |
Read-Through 和 Write-Through 帮助我们提高应用程序的可扩展性和性能。 使用 Read-Through,我们的缓存项始终可用,因为 NCache 可以自动读取过期的项目。 而且,通过直写,我们的应用程序不必等待数据库写入,因为 NCache 可以异步更新我们的数据库,甚至有节流机制,减轻我们数据库的压力。
结论
这些是提高性能和可伸缩性的两种缓存模式:数据分区和缓存策略。 我们可以用 NCache 在我们的应用程序中实现它们。 通过数据分区,我们在节点之间拆分读取和写入并增加缓存的存储容量。 我们有 NCache 分区和分区副本拓扑。 通过Read-Through/Write-Through,我们将缓存服务器作为数据源,减轻了数据库的压力。
要了解有关数据分区和直读/直写的更多详细信息,请查看以下两个指南: 分区和分区副本拓扑 和 数据源提供者 用于缓存。 如果你想从这两种缓存模式中获益来扩展你的应用程序,给 NCache 一试。