.NET Core 和ASP.NET Core 由于其设计简单、轻量级、开源并且能够在 Windows 和 Linux 上运行而越来越受欢迎。 因此,许多现有的应用程序也正在迁移到 .NET Core 来自 .NET Framework. 几乎所有新的应用程序都在开发中 .NET Core.
其中很多 .NET Core 应用程序本质上是高流量的,服务于数百万用户和交易。 因此,这些应用程序会对您的业务产生巨大影响,因此非常重要。
.NET Core 通常需要可扩展性的应用程序是服务器应用程序,它们必须以非常快的响应时间非常快速地处理大量事务。 其中许多应用程序都是面向客户的,这意味着它们正在处理客户请求。 如果他们不快速执行客户请求,那么在收入损失和失去满意客户方面,企业的成本就会很高。
跟随 .NET Core 应用程序需要可扩展性:
有趣的是,上面提到的所有应用程序都具有非常可扩展的应用程序级架构。 它们中的每一个都允许您通过添加更多服务器、VM 或容器实例以及负载均衡器来随着事务负载的增长而线性扩展。
但是,尽管应用层的架构非常可扩展, .NET Core 今天的服务器应用程序面临着主要的可扩展性瓶颈。 这些瓶颈发生在不同的领域,例如:
所有高流量的最大瓶颈 .NET Core applications 是他们的应用程序数据库。 今天的大多数应用程序仍在使用关系数据库,如 SQL Server 或 Oracle。 随着您增加这些应用程序上的事务负载,这些数据库很快成为可伸缩性瓶颈。 无论您是在 VM 上使用 SQL Server 还是在 Azure SQL 数据库上使用,都是如此。
发生这种情况是因为关系数据库不能像 NoSQL database 而是留在一个物理位置; 甚至一些列级分区也不是真正的 NoSQL 风格分区。 因此,您无法通过添加更多数据库服务器来增加数据库层事务容量,就像使用 NoSQL database.
例如,虽然随着事务负载的增长,您的应用层可以轻松拥有 10、20、30 或更多的应用服务器,但您的数据库层根本无法以同样的方式增长。
由于这一切,您的关系数据库成为您存储在其中的任何数据(应用程序数据或其他数据)的性能瓶颈。
SQL Server 引入了内存优化以增加每秒的事务数。 Oracle 还提供了他们自己的 In-Memory 表版本。
虽然内存优化带来了性能改进,但它们并没有解决线性可扩展性的核心问题。 In-Memory 表通常用于只读数据,为了扩展只读事务容量,您需要在更高端的机器上添加更多 SQL Server 实例。
In-Memory 表对数据的大小也有限制; 您不能将大表放在内存中,因为必须将整个表放在内存中。 并且它们到其他 SQL Server 实例的复制只能复制到其他 In-Memory 表而不是适当的数据库。
总之,SQL Server 和 Oracle 数据库中的这些内存优化无法完全解决您的 .NET Core 应用程序的可扩展性需求。
其中一个原因 NoSQL databases 变得流行是因为它们提供了基于哈希和其他算法的适当数据分区。 这解决了 SQL Server 和 Oracle 等关系数据库面临的许多事务容量可扩展性问题。
但是,有原因 NoSQL databases 并不是这些数据库瓶颈的理想解决方案。
上述所有问题的解决方案是使用 In-Memory Distributed Cache,如 NCache 在您的 .NET Core 应用部署。 NCache 是 .NET 的开源分布式缓存和 .NET Core 这是非常快速和线性可扩展的。 将其视为也是分布式的内存数据存储。 在内存中使其速度非常快,而分布式使其具有线性可扩展性。
NCache 是线性可扩展的,因为它构建了一个低成本缓存服务器的 TCP 集群(与您的 Web 应用程序服务器相同的配置,但具有更多内存)并将所有这些服务器的内存和 CPU 资源汇集到一个逻辑容量中。 NCache 然后允许您随着事务负载的增长在运行时将缓存服务器添加到此集群。 而且,由于 NCache 全部在内存中,速度超快,为您提供亚毫秒级的响应时间,这是您无法从关系数据库甚至是 NoSQL databases.
除了提供线性可扩展性之外,分布式缓存 NCache 智能地复制数据,因此您的性能不会受到影响,同时在任何缓存服务器出现故障的情况下实现数据可靠性。
NCache 让你扩展你的 .NET Core 通过以下方式申请:
面临的最重要瓶颈 .NET Core 应用程序是“应用程序数据库”。 关于美好的事情 NCache 是不是不像 NoSQL databases, NCache 不会要求您停止使用现有的关系数据库。 您可以继续使用 SQL Server、Azure SQL 数据库、Oracle 等作为您的数据库,并且仍然可以通过使用实现线性可伸缩性 NCache 在您的关系数据库之上。 这是因为 NCache 消除了所有关系数据库的可扩展性瓶颈,因为与您的数据库不同, NCache 实际上是线性可扩展的。
应用程序数据缓存使您能够消除数据库瓶颈。 NCache 允许您缓存应用程序数据并减少那些昂贵的数据库访问。 您可以预期将 80-90% 的数据库流量转移到 NCache. 这减少了数据库的压力,并允许它更快地执行并处理更大的事务负载而不会减慢速度。
应用程序数据缓存意味着您缓存从关系数据库获得的任何应用程序数据。 这通常采用域对象(也称为实体)的形式。 这是一个如何使用分布式缓存的示例 NCache 用于应用程序数据缓存。
Customer Load(string custId)
{
ICache cache = CacheManager.GetCache("myCache");
string key = "Customer:CustomerID:" + custId;
Customer cust = cache.Get<Customer>(key);
if (cust == null) {
// Item not in cache so load from db
LoadCustomerFromDb(cust);
// Add item to cache for future reference
cache.Add(key, cust);
}
return cust;
}
图 3:使用内存中分布式缓存进行应用数据缓存
另一个可能的瓶颈是如果你存储你的 ASP.NET Core SQL Server 或独立 MemoryCache 中的会话。 这两个选项在性能和可扩展性方面都有很大的限制。 SQL Server 存储不适合 ASP.NET Core 会话并很快成为瓶颈,就像应用程序数据一样。
NCache 是存储 ASP 的好地方.NET Core 会话,因为它比其他存储选项更快且更具可扩展性。 NCache 更快,因为它在内存中,并提供一个键值接口,其值是 ASP 的“对象”.NET Core 会话是。 而且,它是可扩展的,因为它是一个分布式缓存。
而且, NCache 还智能复制 ASP.NET Core 通过其丰富的缓存拓扑进行会话,因此即使缓存服务器出现故障,也不会丢失会话数据。 这种复制是必要的,因为 NCache 提供内存存储,而内存是违反存储的。
NCache 还可以加快 ASP 的序列化.NET Core 在进程外存储之前需要的会话。 NCache 通过使用比常规 .NET 快 10 倍的动态压缩序列化功能和 .NET Core 序列化。 您无需更改任何代码即可使用此功能。
您可以使用 NCache 作为您的 ASP.NET Core 会话存储有两种方式。
下面是如何配置 ASP 的示例.NET Core 要使用的应用程序 NCache 会话提供者:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Specify NCache as the session provider
services.AddNCacheSession(Configuration.GetSection("NCacheSettings"));
...
}
public void Configure(IApplicationBuilder app, ...)
{
// select NCache session provider for ASP.NET Core
app.UseNCacheSession();
...
}
}
图 4:插件 NCache 作为ASP.NET Core 会议
ASP.NET Core 原本具有相当动态内容的应用程序面临这样的情况,即对于它们的某些页面,内容或响应不会在多个请求中发生变化。 但是这些页面仍然必须在每次请求到来时执行。 而且,这会给 Web 服务器资源以及该应用程序的所有层带来不必要的负担。 结果,这也增加了性能瓶颈并限制了应用程序的可扩展性。
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Turn on ASP.NET Core Response Cache with IDistributedCache
services.AddResponseCaching();
// Select NCache as IDistributedCache provider
services.AddNCacheDistributedCache(Configuration.GetSection("NCacheSettings"));
...
}
}
图 5:插件 NCache 作为ASP.NET Core 响应缓存中间件
为了解决页面响应不变的重复页面执行的开销,ASP.NET Core 提供了一种页面响应缓存机制,称为 ASP.NET 响应缓存中间件。 和, NCache 在 ASP 中实现了 IDistributedCache 接口.NET Core 因此,您可以无缝插入 NCache 作为您的 ASP.NET Core 响应缓存中间件。
因此,您可以使用 NCache 缓存 ASP.NET Core 页面响应一段时间,因此下次使用相同的参数调用相同的页面时,可以重新调整此缓存的响应,而不是再次执行整个页面。 下面是如何配置的代码示例 NCache 作为您的 ASP.NET Core 响应缓存中间件。
如果你的 ASP.NET Core 应用程序是一个实时 Web 应用程序,那么它很可能使用 ASP.NET Core SignalR 用于提供这种实时行为。 实时 Web 应用程序提供从服务器到客户端的高频更新。 此类应用的示例包括游戏、拍卖、投票、社交网络等。
如果你的 ASP.NET Core 应用程序在负载平衡的多服务器环境中运行,那么它必须使用 ASP.NET Core SignalR Backplane 提供者,以便在多个 Web 服务器之间共享事件。 而且,这个背板必须是可扩展的。 否则,您的 ASP.NET Core SignalR 应用程序开始面临性能瓶颈。
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Specify NCache as the ASP.NET Core SignalR Backplane
services.AddSignalR().AddNCache(ncacheOptions =>
{ ncacheOptions.CacheName = "myPartitionedCache"; });
...
}
public void Configure(IApplicationBuilder app, ...)
{
// Use SignalR in ASP.NET Core
app.UseSignalR(config => { config.MapHub<MessageHub>("/messages"); });
...
}
}
图 6:插件 NCache 作为ASP.NET Core SignalR Backplane Provider
NCache 已实施 ASP.NET Core SignalR Backplane 供应商。 NCache的ASP.NET Core SignalR Backplane 提供商使用 Pub/Sub 消息传递功能 NCache 由于完全在内存中,所以速度非常快。 这允许您的 ASP.NET Core SignalR 应用程序可加速 SignalR 事件在所有 Web 服务器之间的传播,从而加速到客户端。
并且,这使您的实时 Web 应用程序在向客户端提供这些频繁更新时更具响应性。 而且,您可以不断增加客户端数量并添加更多 Web 服务器,而不必担心任何性能瓶颈。
如果你的 .NET Core 应用程序需要使用 Pub/Sub 消息传递或事件,那么它很可能使用不是完全在内存中的 Pub/Sub 消息传递平台,而是将所有消息存储在磁盘上。 因此,如果您的应用程序是真正的高事务,这很容易成为性能瓶颈。
NCache 还提供了超快的 Pub/Sub 消息传递,因为它完全是内存中的。 而且,它将所有消息复制到另一个 NCache 服务器以确保在任何一台服务器宕机的情况下不会丢失数据。
因此,如果您的 .NET Core 应用程序使用 NCache 作为其 Pub/Sub 消息传递平台,它将体验到超快的性能和线性可扩展性,因为 NCache 本身是线性可扩展的。
下面是如何使用 Pub/Sub 消息传递的示例,由 NCache 在您的 .NET Core 应用程序。
private void PublishMessage (string topicName)
{
ITopic topic = _cache.MessagingService.GetTopic(topicName);
Order order = Order.GenerateOrder<Order>();
// Publish message containing "order" with expiry
Message message = new Message(order, new TimeSpan(0, 0, 15));
topic.Publish(message, DeliveryOption.All, true);
}
private ITopicSubscription SubscribeMessage (string topicName)
{
ITopic topic = _cache.MessagingService.GetTopic(topicName);
// Subscribes to the topic. Message delivered to MessageReceivedCallback
return topic.CreateSubscription(MessageReceivedCallback);
}
static void MessageReceivedCallback(object sender, MessageEventArgs args) { ... }
图 7:使用 Pub/Sub 消息传递 .NET Core 应用
您最大的可扩展性瓶颈 .NET Core 应用程序必须从应用程序数据库中删除。 在这方面,您的应用程序可以通过应用程序数据缓存实现高性能和线性可扩展性。 这样做的原因是简单的。 最多 .NET Core 应用程序处理来自数据库的大量数据。
当谈到应用程序数据缓存时,人们最大的恐惧是缓存变得陈旧,这意味着它包含已由另一个用户或另一个应用程序在数据库中更改的旧版本数据。
这种对缓存过时的恐惧是如此强烈,以至于大多数人只缓存只读或静态数据(参考数据)。 但是,这些只读数据仅占查找表和其他参考数据形式的总数据的 20%。 数据库中的大部分数据都是事务性的,包括客户、帐户、活动等。而且,如果您不缓存这些事务性数据,那么您就不会从缓存中充分受益。
因此,如果您可以缓存所有类型的数据,而不必担心缓存变得陈旧,那么缓存的真正好处就来了。 NCache 提供了许多功能来解决这个问题。
保持缓存最新的最有效方法是始终使其与数据库保持同步。 NCache 允许您对各种数据库执行此操作,如下所示:
当您将缓存与 SQL Server 同步时,您会问 NCache 将自己注册为 SQL Server 的客户端,然后发出 SqlDependency 调用以及基于 SQL 查询的数据集。 然后,当 SQL Server 看到此数据集中的任何更改时,它会通知 NCache 关于它
private static void CreateSqlDependency (Product product)
{
string connectionString = "Data Source=localhost;Database=northwind;...";
// SQL stmt on which the SQL Dependency is created in SQL Server
string sqlStmt = "SELECT ProductID, ProductName, QuantityPerUnit, UnitPrice " +
"FROM dbo.PRODUCTS WHERE ProductID = " + product.Id;
CacheDependency sqlDependency = new SqlCacheDependency(connectionString, sqlStmt);
CacheItem cacheItem = new CacheItem(product) { Dependency = sqlDependency };
string key = "Product:ProductId:" + product.Id; ;
cache.Add(key, cacheItem);
}
图 8:使用 SqlDependency 与 SQL Server 同步缓存
然后, NCache 从缓存中删除这个项目,所以下次应用程序需要它时,它必须从数据库中获取最新的副本。 如果您使用的是通读处理程序(见下文),那么 NCache 还可以为您自动重新加载数据库中的最新副本。 下面是一个示例,说明如何使用 SqlDependency 将缓存与 SQL Server 同步。
Read-through Cache 是一种缓存,它能够通过调用您开发并提供给缓存的 Readthrough Handler 从数据库中读取数据。 类似地,直写缓存能够通过调用您开发并提供给缓存的直写处理程序将数据更改写入数据库。 Write-behind Cache 与 Write-through 相同,只是数据库更新是异步完成的。
Read-through、Write-through 和 Write-behind 为您提供了很多好处 .NET Core 应用包括:
下面是一个示例,说明如何使用 Read-through with NCache.
// Read through handler for SQL Server
public class SqlReadThruProvider : Runtime.DatasourceProviders.IReadThruProvider
{
public void Init(IDictionary parameters, string cacheId) {}
public void Dispose() {}
// Get object from the database/data-source based on the key
public ProviderCacheItem LoadFromSource(string key) {}
// Bulk-Get objects from the database/data-source based on the keys
public IDictionary<string, ProviderCacheItem> LoadFromSource(ICollection<string> keys)
{}
}
图 9:使用 Read-through Handler NCache
一旦您对缓存所有数据感到满意,您就可以开始将大量数据放入分布式缓存中。 在这里,您可以开始面临如何快速轻松地找到您的数据的另一个特殊问题。 由于大多数分布式缓存都是键值存储,因此仅通过键来跟踪所有数据变得非常困难。
这是哪里 NCache 为您提供多种快速从缓存中查找数据的方法。 示例包括:
下面是一个示例,说明如何使用基于 LINQ 的查询 NCache.
// Search the cache based on object attributes by using LINQ
IQueryable>Product< products = new NCacheQuery<Product>(_cache);
var result = from product in products
where product.Id > 10
select product;
if (result != null)
{
foreach (Product p in result1)
{
// Process each “product” fetched from the database
Console.WriteLine("ProductID : " + p.Id);
}
}
图 10:使用 LINQ 查询 NCache
交通拥挤 .NET Core 应用程序不能下降,尤其是在高峰时段。 对于这些类型的应用程序,良好的 InMemory 分布式缓存具有三个非常重要的架构目标 NCache 满足。
让我在下面解释每一个。
NCache 提供一个客户端缓存,它是一个非常靠近您的应用程序的本地缓存。 它可以是 InProc(意味着它驻留在您的应用程序进程中)或本地 OutProc。 无论哪种方式,它都可以非常快速地访问此应用服务器上的应用程序此时需要的缓存数据子集。 客户端缓存同时与缓存层保持同步,因此缓存层中其他用户或应用程序更改的任何数据都会立即传播到客户端缓存。 客户端允许您拥有 InProc 速度,同时仍然是非常可扩展的缓存层的一部分。
最重要的架构目标之一 NCache 是通过其缓存拓扑实现具有数据可靠性的线性可扩展性。 这里有一些 NCache 缓存拓扑 这有助于实现这两个目标。
最重要的架构目标之一 NCache 就是实现高可用和缓存弹性。 它通过以下架构功能做到这一点: