.NET Core 2.0のリリースによって、Microsoftは、2016年にリリースした汎用目的、モジュール構造、プラットフォーム不問のオープンソースのプラットフォームの次期メジャーバージョンを手にしました。.NET Coreは、現行の.NET Frameworkで利用可能なAPIの大部分を持つように設計されています。元々はASP.NETソリューションの次世代版を実現するために開発されましたが、現在ではIoTやクラウド、次世代モバイルソリューションなど、まったく違うシナリオを担う、基盤的な存在となっています。.NET Coreを取り上げたこのシリーズの第2回では、.NET Coreのさらなるメリットと、既存の.NET開発者のみならず、堅牢性、パフォーマンス、経済性を兼ね備えたソリューションを市場に投入する必要のあるすべての技術者にとっての価値を探ります。
キャッシュは、ASP.NET Coreアプリケーションのパフォーマンス向上を支援します。分散キャッシュは、サーバファームやスケーラブルなクラウド環境にデプロイされるASP.NETアプリケーションを開発する場合に有効です。Microsoftの資料にはSQL ServerやRedisでの実施例がありますが、この記事では別の方法をご紹介したいと思います。Couchbass Servcerは、memory-first(memory-onlyも可能)ストレージアーキテクチャを備えた、キャッシュに最適な分散型データベースです。Redisとは違い、よりリッチな機能のスイートを持っているので、後にユースケースやプロダクトが拡大しても使用することができます。しかし今回の記事では、キャッシュ機能とASP.NET Coreとの統合に注目したいと思います。ご紹介する内容はすべて、GitHubmにあるコードサンプルに従っています。
分散キャッシングの利点
- パフォーマンス。キャッシュはデータをRAMに格納して、素早く簡単に検索できるようにします。オリジナルのソースを毎回使用するよりも、このキャッシュからデータを取得する方が速い場合が多いのです。
- キャッシュデータの共有。 ASP.NET Coreアプリケーションでマルチサーバデプロイメントを使用している場合、ロードバランサがASP.NET Coreサーバのいずれかにユーザをリダイレクトする可能性があります。キャッシュされたデータがWebサーバ自体にある場合は、スティッキーセッション(sticky session)をオンにして、ユーザが常に同じASP.NET Coreサーバに向けられるようにしなくてはなりません。これは負荷の偏りなどネットワークの問題を引き起こす可能性があります - 詳細はStack Overflowでの回答を確認してください。
- 堅牢性。 ASP.NET Core Webサーバがダウンしたり、何らかの理由でリスタートしなければならない場合でも、キャッシュデータには影響しません。再起動後も、分散キャッシュにはデータが残ります。
分散キャッシュとして使用するツールが何であるか(Couchbase、Redis、SQL Server)に関わらず、ASP.NET Coreは、使用するすべてのテクノロジに対して、一貫性のあるインターフェースを提供します。
Couchbaseのインストール
最初のステップは、分散キャッシュサーバを立ち上げることです。一番都合のよいインストール方法を選択してください。Dockerやクラウドプロバイダを使ったり、あるいはローカルマシンにインストールすること(このブログ記事で紹介する方法)も可能です。ダウンロードは無償で、Couchbase Communityエディションは無料で使用できます(Enterpriseエディションも、開発期間中は無償で無制限に使用できますが、今回のブログ記事ではCommunityエディションを使用します)。
Couchbaseをインストールしたら、Webブラウザを立ち上げて、簡単なウィザードを実行してください。今回の記事では、デフォルト設定で問題ありません。
Couchbaseをインストールしたら、”バケット(bucket)”を作成します。これがキャッシュデータが格納される場所になります。私はバケット名を“infoqcache”にしました。ここでは“Ephemeral”バケット(memory-onlyオプション)を生成しましたが、”Couchbase“バケット(まずメモリにデータを格納し、非同期にディスクに永続化する)を使うことも可能です。
セットアップの最後のステップはセキュリティです。Couchbaseユーザを適切な権限でバケットに追加してください。私はユーザ名を“infoq”、パスワードを“password“にしました(みなさんはもっと強力なものを使用してください!)Enterpriseエディションではたくさんのロールを選択できますが、今回のシンプルなユースケースでは必要ありません。infoqcacheへの”Bucket Full Access“で十分です。
ASP.NET Coreに取り掛かる前に、これらのインストールステップをすべて実施しておいてください。それぞれのステップを、詳細資料へのリンクと合わせて挙げておきます。
- Couchbaseのインストール(ダウンロードページの指示に従ってください)
- Couchbaseのセットアップ(Explore the Server Configuration)
- バケットの作成(Creating a Bucket)
- バケットへのアクセス権を持ったユーザの作成(Creating and Managing Users with the UI)
ASP.NET Coreアプリケーションの新規作成
ASP.NET Coreの分散キャッシング機能を紹介するために、ASP.NET Core APIのサンプルアプリケーションを作成することにしましょう。2つのエンドポイントを備えた、小さくてシンプルなアプリケーションです。
私はVisual Studio 2017を使用していますので、メニューから、File→New→Web→ASP.NET Core Web Applicationを選択します。
次のステップは、使用するASP.NET Coreプロジェクトテンプレートの選択です。今回は、認証やDockerサポートのないベアボーン“API”を使用します。
プロジェクトにはValuesController.cs
というファイルがありますが、このクラス内のコードの大部分を、自分で書いたコードに置き換えます。以下に示すのは、作成した最初のエンドポイントです。キャッシュは使用せず、レイテンシの高いデータアクセスをシミュレートするため、Thread.Sleep
を使用します(Thread.Sleep
の部分が、遅いWebサーバのコールや複雑なデータクエリに置き換えられると理解してください)。
[Route("api/get")]
public string Get()
{
// generate a new string
var myString = Guid.NewGuid() + " " + DateTime.Now;
// wait 5 seconds (simulate a slow operation)
Thread.Sleep(5000);
// return this value
return myString;
}
websiteを起動しましょう(Visual StudioではCtrl+F5)。エンドポイントとの通信にはPostmanなどのツールが利用できますが、今回の例であればブラウザで十分です。私のサンプルプロジェクトでは、サイトはlocalhost.64291
をローンチし、エンドポイントにはapi/getをルートするように設定されていますから、ブラウザからlocalhost:64921/api/get
にアクセスします。
これは単純な例ですが、このエンドポイントが a) いくつかのユニークな文字列値を取得するために、b) 非常に時間が掛かるものであることを示しています。リフレッシュする度に、少なくとも5秒は待たなくてはなりません。キャッシュを導入してレイテンシとパフォーマンスを改善するには、うってつけの状況です。
ASP.NET CoreとCouchbaseの統合
ここまでで、キャッシングとCouchbase Serverインスタンスの支援が必要なASP.NET Coreアプリケーションがひとつ出来上がりました。それでは、これらをまとめてみましょう。
最初のステップは、NuGetからのパッケージのインストールです。NuGet UIを使ってCouchbase.Extensions.Cachingを検索するか、あるいはPackage Manager Consoleでコマンド“Install-Package Couchbase.Extensions.Caching -Version 1.0.1
”を実行することもできます。これはオープンソースプロジェクトで、全ソースコードがGitHubで公開されています。
NuGetは、あなたのASP.NET CoreアプリケーションがCouchbase Serverと通信するために必要なすべてのパッケージをインストールした上で、ASP.NET Coreに組み込まれた分散キャッシング機能と統合してくれます。
それでは、プロジェクトのStartup.cs
ファイルを開いてみましょう。ここでConfigureServices
メソッドにセットアップコードを追加する必要があります。
services.AddCouchbase(opt =>
{
opt.Servers = new List<Uri>
{
new Uri("http://localhost:8091")
};
opt.Username = "infoq";
opt.Password = "password";
});
services.AddDistributedCouchbaseCache("infoqcache", opt => { });
(サンプルでは、ファイルの先頭に“using Couchbase.Extensions.Caching;
”と “using Couchbase.Extensions.DependencyInjection;
”も追加していますが、これらは私が使用しているReShaperが自動的に識別して追加したものです)。
上のコードではAddCouchbase
とAddDistributedCouchbaseCache
が、拡張メソッドとして組込みのASP.NET Core IServiceCollection
インターフェースに追加されます。
AddCouchbase
では、前述のユーザ/パスワードを指定して、Couchbaseに接続する方法をASP.NET Coreに伝えています。
AddDistributedCouchbaseCache
では、前述したバケットの名前を指定して、Couchbaseを分散キャッシュとして使用する方法をASP.NET Coreに指定します。
この拡張機能に関する資料はGithubdにあります。ConfigureServicesmethodにcleanup/tear downコードを忘れずに追加してください。
ASP.NET Coreの分散キャッシュを使用する
ASP.NET Coreのキャッシュの設定方法が分かったので、簡単な例で試してみましょう。
分散キャッシングを実践する上で最も簡単なのは、ValuesControllerにインジェクトしてIDistributedCachedirectlyを使う方法です。
まず、コンストラクタのパラメータにIDistributedCacheasを追加します。
public ValuesController(IDistributedCachecache)
{
_cache = cache;
}
Startup.cs
ですでに分散キャッシュを設定しているので、ASP.NET Coreにはこのパラメータをセットする方法(依存性注入を使用する)が分かっています。これで、ValueController
の_cacheを使ったキャッシュの値の取得と設定が可能になりました。私はここで、GetUsingCache
という別のエンドポイントを記述しました。キャッシュを使う点を除けば、これは前述のGetエンドポイントとまったく同じです。最初の呼び出し後に値がストアされて、以降の呼び出しがThread.Sleep
に届くことはありません。
[Route("api/getfast")]
public string GetUsingCache()
{
// is the string already in the cache?
var myString = _cache.GetString("CachedString1");
if (myString == null)
{
// string is NOT in the cache
// generate a new string
myString = Guid.NewGuid() + " " + DateTime.Now;
// wait 5 seconds (simulate a slow operation)
Thread.Sleep(5000);
// put the string in the cache
_cache.SetString("CachedString1", myString);
// cache only for 5 minutes
/*
_cache.SetString("CachedString1", myString,
new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(5)});
*/
}
return myString;
}
The first request to /api/getfast will still be slow but refresh the page, and the next reques twill pull from the cache. Couchbaseコンソールに戻って、メニューの“Buckets”をクリックすれば、“infoqcache”バケットにアイテムがひとつあることが分かります。
ValuesController
について指摘すべき重要な点は、Couchbaseのどのライブラリとも直接的な結び付きがなく、すべてをASP.NET Coreのライブラリに依存していることです。この共通インターフェースを使うことで、標準的なMicrosoft ASP.NET Coreライブラリを使用可能な場用でさえあれば、Couchbase分散キャッシュを利用することができるのです。さらに、IDistributedCacheインターフェースでカプセル化されているため、テストの記述も容易です。
上記の例では、キャッシュされたデータはキャッシュに永続的に存在しますが、有効期限を指定することも可能です。次に示す例では、エンドポイントは5分間データをキャッシュします(スライディング有効期限)。
_cache.SetString("CachedString1", myString,
new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(5)});
まとめ
ASP.NET CoreはCouchbase Serverと密接に連携して、分散キャッシュを実現します。標準化された分散キャッシュインターフェースにより、簡単にキャッシュを使い始めることができます。キャッシュを活用して、ASP.NET Core分散アプリケーションを高速化しましょう。
Couchbase.Extensions.Cachingプロジェクトについて疑問や意見のある方は、GitHubリポジトリやCouchbase .NET SDKフォーラムをチェックしてください。
著者について
Matthew D. Groves氏はコーディングが大好きです。C#でもjQueryでもPHPでも構わず、何にでもプルリクエストを送ります。90年代に両親のピザショップ用の販売管理アプリケーションをQuickBASICで書いて以来、プロとしてコーディングを続けていて、現在はCouchbaseのデベロッパアドボケートとして働いています。“AOP in .NET”(Manningより出版)の著者であり、Microsoft MVPでもあります。
.NET Core 2.0のリリースによって、Microsoftは、2016年にリリースした汎用目的、モジュール構造、プラットフォーム不問のオープンソースのプラットフォームの次期メジャーバージョンを手にしました。.NET Coreは、現行の.NET Frameworkで利用可能なAPIの大部分を持つように設計されています。元々はASP.NETソリューションの次世代版を実現するために開発されましたが、現在ではIoTやクラウド、次世代モバイルソリューションなど、まったく違うシナリオを担う、基盤的な存在となっています。.NET Coreを取り上げたこのシリーズの第2回では、.NET Coreのさらなるメリットと、既存の.NET開発者のみならず、堅牢性、パフォーマンス、経済性を兼ね備えたソリューションを市場に投入する必要のあるすべての技術者にとっての価値を探ります。