.NET Core およびASP.NET Core シンプルな設計、軽量、オープンソース、Windows と Linux の両方で実行できることにより、人気が高まっています。 その結果、多くの既存のアプリケーションも次のようなものに移行しています。 .NET Core .NET Framework。 ほぼすべての新しいアプリケーションが開発されています。 .NET Core.
これらの多く .NET Core アプリケーションは本質的に高トラフィックであり、数百万のユーザーとトランザクションにサービスを提供します。 結果として、これらのアプリケーションはビジネスに多大な影響を与えるため、非常に重要です。
.NET Core 通常、スケーラビリティを必要とするアプリケーションは、非常に速い応答時間で大量のトランザクションを迅速に処理する必要があるサーバー アプリケーションです。 これらのアプリケーションの多くは顧客向けであり、顧客の要求を処理していることを意味します。 顧客の要求を迅速に実行しない場合、収益の損失と満足している顧客の喪失という点で、ビジネスへのコストは高くなります。
フォロー .NET Core アプリケーションにはスケーラビリティが必要です。
興味深いことに、上記のアプリケーションはすべて、非常にスケーラブルなアプリケーション レベルのアーキテクチャを備えています。 それぞれのサーバー、VM、またはコンテナー インスタンスとロード バランサーを追加することで、トランザクション負荷の増加に応じて線形に拡張できます。
しかし、アプリケーション層では非常にスケーラブルなアーキテクチャにもかかわらず、 .NET Core 今日のサーバー アプリケーションは、スケーラビリティの大きなボトルネックに直面しています。 これらのボトルネックは、次のようなさまざまな領域で発生しています。
すべての高トラフィックの最大のボトルネック .NET Core application はアプリケーション データベースです。 現在のほとんどのアプリケーションは依然として SQL Server や Oracle などのリレーショナル データベースを使用しています。 これらのアプリケーションのトランザクション負荷が増加すると、これらのデータベースはすぐにスケーラビリティのボトルネックになります。 これは、VM 上で SQL Server を使用している場合でも、Azure SQL Database 上で使用している場合でも当てはまります。
これは、リレーショナル データベースをデータベースのように論理的に分割できないために発生します。 NoSQL database その代わり、物理的に XNUMX つの場所に留まります。 一部の列レベルのパーティショニングであっても、真のパーティションとはまったく異なります。 NoSQL スタイルのパーティション。 したがって、データベース サーバーを追加することによってデータベース層のトランザクション容量を増やすことはできません。 NoSQL database.
たとえば、トランザクションの負荷が増加するにつれて、アプリケーション層には 10、20、30、またはそれ以上のアプリケーション サーバーが簡単に追加される可能性がありますが、データベース層は同じようにはまったく増加できません。
このため、リレーショナル データベースは、そこに保存するデータ (アプリケーション データまたはその他のデータ) のパフォーマンスのボトルネックになります。
SQL Server では、XNUMX 秒あたりのトランザクション数を増やすためにインメモリ最適化が導入されました。 Oracle は、独自のバージョンのインメモリ テーブルも提供しています。
インメモリの最適化はパフォーマンスの向上をもたらしますが、線形スケーラビリティという中核的な問題には対処しません。 インメモリ テーブルは通常、読み取り専用データに使用され、読み取り専用トランザクション容量を拡張するには、ハイエンド マシンに SQL Server のインスタンスを追加する必要があります。
インメモリ テーブルにはデータのサイズにも制限があります。 テーブル全体をメモリに配置する必要があるため、大きなテーブルをメモリに配置することはできません。 また、他の SQL Server インスタンスへのレプリケーションは、適切なデータベースではなく、他のインメモリ テーブルに対してのみ実行できます。
要約すると、SQL Server および Oracle データベースのこれらのインメモリ最適化では、問題に完全に対処することはできません。 .NET Core アプリケーションのスケーラビリティのニーズ。
理由のひとつ NoSQL databaseが普及したのは、ハッシュベースおよびその他のアルゴリズムに基づいてデータを適切に分割できるためです。 これにより、SQL Server や Oracle などのリレーショナル データベースが直面するトランザクション容量のスケーラビリティの問題の多くが解決されます。
しかし、理由はあります NoSQL databaseこれらのデータベースのボトルネックに対する理想的な解決策ではありません。
上記のすべての問題の解決策は、次のようなインメモリ分散キャッシュを使用することです。 NCache 自分で .NET Core アプリケーションの展開。 NCache .NET 用のオープンソース分散キャッシュです。 .NET Core これは非常に高速で、直線的に拡張可能です。 これは、分散されたメモリ内データ ストアであると考えてください。 インメモリであるため非常に高速になり、分散しているため直線的にスケーラブルになります。
NCache は、低コストのキャッシュ サーバー (Web アプリ サーバーと同じ構成だがメモリが多い) の TCP クラスターを構築し、これらすべてのサーバーのメモリと CPU リソースを XNUMX つの論理容量にプールするため、直線的にスケーラブルです。 NCache これにより、トランザクションの負荷が増大したときに、実行時にこのクラスターにキャッシュ サーバーを追加できるようになります。 それ以来 NCache すべてメモリ内にあるため、超高速であり、リレーショナル データベースやリレーショナル データベースでは期待できないミリ秒未満の応答時間を実現します。 NoSQL databases.
線形スケーラビリティを提供することに加えて、次のような分散キャッシュ NCache データをインテリジェントにレプリケートするため、キャッシュ サーバーがダウンした場合でもデータの信頼性を確保しながら、パフォーマンスが損なわれることはありません。
NCache スケールを調整できます .NET Core アプリケーションは次のとおりです。
が直面している最も重要なボトルネックは、 .NET Core アプリケーションは「アプリケーション データベース」です。 良い点 NCache それは違いますか NoSQL databases, NCache 既存のリレーショナル データベースの使用を停止するように要求するものではありません。 SQL Server、Azure SQL Database、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:アプリのデータキャッシュにインメモリ分散キャッシュを使用する
もう XNUMX つのボトルネックとなる可能性があるのは、ASP を保管している場合です。.NET Core SQL Server またはスタンドアロン MemoryCache のセッション。 どちらのオプションにも、パフォーマンスとスケーラビリティに関して大きな制限があります。 SQL Server ストレージは ASP には適していません.NET Core セッションが発生し、アプリケーション データと同様にすぐにボトルネックになります。
NCache ASP を保管するのに最適な場所です.NET Core セッションは他のストレージ オプションよりもはるかに高速で拡張性が高いためです。 NCache メモリ内にあり、ASP が提供する「オブジェクト」である値を持つ keyvalue インターフェイスを提供するため、高速です。.NET Core セッションです。 また、分散キャッシュであるため、スケーラブルです。
と、 NCache ASPもインテリジェントに複製します.NET Core 豊富なキャッシュ トポロジを通じてセッションを維持できるため、キャッシュ サーバーがダウンした場合でもセッション データが失われることはありません。 このレプリケーションが必要な理由は、 NCache インメモリストアを提供し、メモリはストレージに違反しています。
NCache ASP のシリアル化も高速化されます.NET Core アウトプロセスで保存する前に必要なセッション。 NCache これは、通常の .NET よりも 10 倍高速なダイナミック コンパクト シリアル化機能を使用して実行されます。 .NET Core 連載化。 この機能は、コードを変更せずに使用できます。
あなたが使用することができます NCache ASPとして.NET Core セッションは XNUMX つの方法で保存します。
以下は、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 Response Cache Middleware と呼ばれるページ応答キャッシュ メカニズムを提供しています。 と、 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 プロバイダー
NCache ASPを導入しました.NET Core SignalR Backplane プロバイダ。 NCacheのASP.NET Core SignalR Backplane プロバイダーは Pub/Sub メッセージング機能を使用します NCache 完全にメモリ内にあるため、超高速です。 これにより、ASP は.NET Core SignalR アプリケーションは、すべての Web サーバー間での SignalR イベントの伝播を高速化し、結果としてクライアントへの伝播を高速化します。
また、これにより、リアルタイム 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 のクライアントとして登録し、SQL クエリベースのデータセットとともに SqlDependency 呼び出しを発行します。 その後、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 と同期する方法の例です。
リードスルー キャッシュは、開発してキャッシュに提供したリードスルー ハンドラーを呼び出すことによって、データベースからデータを読み取ることができるキャッシュです。 同様に、ライトスルー キャッシュは、開発してキャッシュに提供したライトスルー ハンドラーを呼び出すことによって、データの変更をデータベースに書き込むことができます。 ライトビハインド キャッシュは、データベースの更新が非同期で行われる点を除いてライトスルーと同じです。
リードスルー、ライトスルー、ライトビハインドは、ユーザーに多くのメリットをもたらします。 .NET Core 以下を含むアプリケーション:
以下は、Read-through を使用する方法の例です。 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: リードスルー ハンドラーの使用 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 分散キャッシュに必要な XNUMX つの非常に重要なアーキテクチャ上の目標があります。 NCache 満たします。
以下でそれぞれについて説明していきます。
NCache は、アプリケーションに非常に近いローカル キャッシュであるクライアント キャッシュを提供します。 InProc (アプリケーション プロセス内に存在することを意味します) またはローカル OutProc のいずれかになります。 いずれの場合でも、このアプリ サーバー上のアプリケーションが現時点で必要とするキャッシュ データのサブセットへの非常に高速なアクセスが可能になります。 同時にクライアント キャッシュはキャッシュ層との同期を維持するため、キャッシュ層内の他のユーザーまたはアプリケーションによって変更されたデータはすぐにクライアント キャッシュに伝播されます。 クライアントを使用すると、非常にスケーラブルなキャッシュ層の一部でありながら、InProc 速度を実現できます。
の最も重要なアーキテクチャの目標のXNUMXつ NCache キャッシング トポロジを通じてデータの信頼性を備えた線形スケーラビリティを実現することです。 ここにあるいくつかの NCache キャッシングトポロジ これらの両方の目標を達成するのに役立ちます。
の最も重要なアーキテクチャの目標のXNUMXつ NCache 高可用性とキャッシュの弾力性を実現することです。 これは、次のアーキテクチャ機能を通じて行われます。