[AppFabric Caching] A to Z


Azure における最新の Redis Cache サービスについては「Azure Redis Cache の使用 (.NET, PHP, Node.js)」に記載しました。(以下は、古い記事です。)

関連ナンバー

こんにちは。

Tech Ed Japan ではかなりお茶を濁した表現になってしまいましたが、先日開催された PDC 10 で、Windows Azure AppFabric Caching が遂にアナウンスされました。( ゆっくりとですが、Windows Server AppFabric と Windows Azure AppFabric の垣根が低くなってきました . . .)

Windows Azure AppFabric SDK V2.0 CTP – October 2010 Update (英語) :

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=d89640fc-c552-446e-aead-b1e0d940f31b

Windows Azure AppFabric Labs (ベータ用) :

http://portal.appfabriclabs.com/

まずは、Tech Ed Japan 2010 の復習になりますが、この AppFabric の Caching (Windows Server AppFabric の Cache Services) について、どのような機能が使えるのかをザッと復習しておきましょう。
なお、基本的な AppFabric caching の使用方法 (チュートリアル) については、以前 こちら に掲載しましたので、ご参照ください。

補足 : なお、Windows Azure caching では、セキュリティも、ACS トークンを使用した方法が採用されています。また、下記の Region、Tag、Notification (通知)、HA などについても、現在の Windows Azure caching には実装されていないので注意してください。(使用できる API も、一部、制限されています。) 2012/06 削除

 

Region と Tag

Region と Tag を使用して、格納する Key-Value ペアのキャッシュ アイテム (データ) に対して、検索用のグループ化をおこなうことができます。
まず、Region (領域) は、「グループ化」という表現がまさにふさわしく、アイテムを排他的に分類します。一方、Tag (タグ) は、検索用のタグ付けに相当し、Region と異なり、1 つのアイテムに対して複数のタグを設定できます。

例えば、下図を参照してください。さまざまな購入品のアイテムが登録されている場合、下記の通り、PC (パソコン) というグループ化された Region を作成し、この中に、「ビジネス用」、「ノート型」などの Tag を設定できます。

Region と Tag を設定すると、下記の通り、その単位で一括検索やバルク削除などをおこなうことができます。(Tag では、GetObjectsByAllTags、GetObjectsByAnyTag などを使用した And / Or 検索も可能です。ただし、ノードをたどった取得になるため、重複検索などがおこなわれる点に注意してください。)

. . .

cache.CreateRegion("PC");
cache.Add("prod1", "notebook", "PC");
PCItem obj = (PCItem) cache.Get("prod1", "PC");

var cache = factory.GetCache("HogeHoge");
cache.CreateRegion("PC");
DataCacheTag tag1 = new DataCacheTag("note");
DataCacheTag tag2 = new DataCacheTag("business");
cache.Add("prod1",obj1,new List<DataCacheTag> {tag1},"PC");
cache.Add("prod2",obj2,new List<DataCacheTag> {tag2}, "PC");
cache.Add("prod3",obj3,new List<DataCacheTag>{tag1,tag2}, "PC");
IEnumerable<KeyValuePair<string, object>> result =
    cache.GetObjectsByTag(tag1, "PC"); // prod1, prod3
. . .

なお、Region は パーティション化の対象となり、同じ Region のアイテムは同じホストに配置されます。このため、異なる Region に対して同じ Tag を付けても、結局、Region ごとにしか検索できないので注意してください。

キャッシュ アイテムのバージョン

アイテムには「バージョン」が付与されます。ただし、このバージョンの概念は、「世代すべての管理」とはやや異なる概念ですので注意してください。

通常、「バージョン管理」というと、過去のすべてのバージョンのアイテムが管理され、過去のアイテムへのロールバックなども可能な場合が多いでしょう。しかし、Velocity における「バージョン」は、こうしたバージョン管理ではなく、単に、アイテムに対してバージョン キーを付与するというものです。このため、例えば、いつの世代のアイテムであるかアプリケーションから検証する場合などに使用できます。
以下に、サンプルを掲載します。

. . .

DataCacheItemVersion ver1 = cache.Add("Foo", obj1);
DataCacheItemVersion ver2 = cache.Put("Foo", obj2);
DataCacheItemVersion ver = default(DataCacheItemVersion);
MyObj res = (MyObj) cache.Get("Foo", out ver);
if (ver.CompareTo(ver1) == 0)
    Console.WriteLine("res is Version1"); // not hit
else if(ver.CompareTo(ver2) == 0)
    Console.WriteLine("res is Version2"); // hit !
. . .

キャッシュ アイテムのセキュリティ

Velocity で管理されるアイテムは、セキュリティ モード (Security Mode) と保護レベル (Protection Level) という 2 つの概念で保護できます。

セキュリティ モード (Security Mode)
None いかなるクライアントもアクセス可能です
Transport (既定) 許可された Windows アカウント(ユーザー、グループ、マシン) のみが接続可能です
保護レベル (Protection Level)
None 保護しないモード
Sign データの整合性チェックをおこない、データの不正操作や改ざんを防止します
(Security Mode が Transport の場合のみ有効です)
EncryptAndSign (既定) 上記の改ざん防止に加え、データを暗号化することで外部からの読み取りも防止します
(Security Mode が Transport の場合のみ有効です)

このセキュリティの設定は、サーバー側とクライアント側の双方でおこないます。(クライアント側は、.config に記載する方法と、プログラムを使用して securityProperties に設定する方法があります。)

このセキュリティ設定ですが、既定では、上記の通り EncryptAndSign になっていますが、無論、セキュリティ設定によるオーバーヘッドも無視できない場合があるので、注意してください。下記は、PowerShell を使って、サーバー側のセキュリティ設定を無効にする場合の例です。

Set-CacheClusterSecurity -SecurityMode None -ProtectionLevel None

キャッシュ アイテムのライフサイクル

アイテムは、既定では揮発的なものです。
そして、以下の Expiration と Eviction の概念の組み合わせで、この生存方針を設定できます。

Expiration
Expirable False にすると下記の Eviction のみが評価され、True にすると有効期限 (時間) が評価されます
(既定は True です)
default TTL Time To Live (生存時間) を設定します
(既定は 10 分です)
Eviction
EvictionType ここは、現在、None (Eviction なし) か LRU (least recently used, 使用頻度が高いアイテムを優先するアルゴリズム) しか指定できません
(既定は LRU です)

このライフサイクルは、PowerShell やサーバー上の構成を使ってキャッシュごとに設定しますが、キャッシュ アイテムごとに生存時間 (TTL) を上書きできます。

なお、Expiration と Eviction を無効にすると、生存状態をすべてアプリケーションで管理できます。(下記は、PowerShell での設定例です。) しかし、それでも、ホストが停止した場合 (かつ、HA オプションが有効でない場合) など、アイテムが消滅する可能性は常にあるので、基本的に、揮発的なデータを管理するものとして使用してください。

New-Cache HogeHoge -Expirable false -Evication None

ローカル キャッシュ

キャッシュ アイテム (の Primary) は、分散された (サーバーの) ホスト上のどこか 1 箇所に必ず存在し、クライアント (Web アプリケーションなど) からアイテムを取得する場合、この問い合わせはルーティングされ、該当のホストからアイテムが取得されます。(この既定の状態を Partitioned Cache と呼びます。)
ここで紹介するローカル キャッシュでは、参照系データなどの場合に、このアイテムをクライアント側にキャッシュすることで、さらに効率化 (呼び出しのオーバーヘッドの低減) をおこなうことができます。また、アイテムは、シリアライズされず、参照が使用されるため、大きなデータなどではスループットはさらに向上します。(なお、ローカルにアイテムがない場合は、サーバーからアイテムが取得され、逆シリアライズされます。)

このローカル キャッシュには、時限方式の TimeoutBased と、ポーリングベースの NotificationsBased が使用できます。下記の構成 (クライアント側の .config) は、NotificationBased を使用している設定例です。

. . .

<dataCacheClient>
  <localCache isEnabled="true" sync="NotificationBased" objectCount="100000" ttlValue="300" />
  <!--(optional) キャッシュ更新通知のポーリング間隔 -->
  <clientNotification pollInterval="300" />
  . . .

localCache (上記) には、以下の属性を設定できます。

isEnabled True に設定することで、ローカル キャッシュを有効化します
sync 上述した TimeoutBased  (時限方式によるキャッシュ無効化) と NotificationsBased  (時限方式に加え、通知方式によるキャッシュ無効化) の設定です
(既定では、300 秒ごとにポーリングをおこないます)
objectCount クライアント側にキャッシュできるデータの個数を指定します
(既定値は 100000 です)
ttlValue 無効化の時間設定 (単位は秒) です
(既定値は 300 です)

ローカル キャッシュでは、そのメカニズムから、データ一貫性が犠牲になるという点に注意してください。
また、Tech Ed Japan 2010 でも説明したように、このローカル キャッシュは、キャッシュ ファクトリー単位で設定されます。(プログラム コードを使って、ファクトリーごとに設定することも可能です。詳細は、「Velocity における Partitioned キャッシュとローカルキャッシュの併用」 を参照してください。) このため、例えば、ASP.NET の Web アプリケーションなどで、毎回ファクトリーを作成しなおすようにプログラミングしている場合は、ローカル キャッシュが効かなくなってしまいますので注意してください。(ASP.NET の場合、キャッシュ ファクトリーを、Application、Session、static 変数などに保持します。)

悲観ロック (Pessimistic locking)

上述の通り、Partitioned Cache では、単一のホスト上のアイテムが使用されるため、アイテムの書き込み / 読み取りの一貫性が保証されます。しかし、例えば、データを読み込んでカウント アップするようなケースなど、一連の時間を伴う処理での一貫性は保証されません。
こうした場合には、下記の通り、悲観的ロックのための API (GetAndLock / PutAndUnlock / Unlock) が使用できます。

. . .

obj1 = cache.GetAndLock("Foo", TimeSpan.FromSeconds(10),
  out handle, true);
任意の処理の実行 ...
cache.PutAndUnlock("Foo", obj2, handle);
. . .

この API ですが、現状は、「待機」の仕組みを持っていません。(このため、待機をおこなうには、例外を処理する必要があります。) また、ロック時には、他からの Put 処理なども保護されません。(あくまでも、アプリケーション側で、統一的に PutAndLock をおこなった場合に、ロックが有効になります。)
このため、悲観的ロックを使用する場合は、アプリケーション側でも、このロック メカニズムを意識した実装をおこなう必要があります。

通知 (Notification)

Velocity では、キャッシュ / Region / アイテムの各レベルの更新を通知できます。
例えば、以下は、キャッシュ全体で、アイテムと Region に発生した更新処理を通知するサンプルです。

. . .
using Microsoft.ApplicationServer.Caching;

static void Main(string[] args)
{
    DataCacheOperations allCacheOperations =
        DataCacheOperations.AddItem |
        DataCacheOperations.ReplaceItem |
        DataCacheOperations.RemoveItem |
        DataCacheOperations.CreateRegion |
        DataCacheOperations.ClearRegion |
        DataCacheOperations.RemoveRegion;

    var factory = new DataCacheFactory();
    var cache = factory.GetCache("HogeHoge");
    cache.AddCacheLevelCallback(allCacheOperations, delegate(
        string myCacheName,
        string myRegion,
        string myKey,
        DataCacheItemVersion itemVersion,
        DataCacheOperations OperationId,
        DataCacheNotificationDescriptor nd)
        {
            Console.WriteLine("Cache-Level Notification");
            Console.WriteLine("\tCache:{0}", myCacheName);
            Console.WriteLine("\tRegion:{0}", myRegion);
            Console.WriteLine("\tKey:{0}", myKey);
            Console.WriteLine("\tOperationId:{0}", OperationId.ToString());
            Console.WriteLine("\tDescriptor:{0}", nd.ToString());
        });

    Console.WriteLine("終了するには Enter");
    Console.ReadLine();
}
<configuration>
  <configSections>
    . . .
  </configSections>
  <dataCacheClient>
    <hosts>
      <host name="kkdeveva01" cachePort="22233"/>
    </hosts>
    <clientNotification pollInterval="10" />
  </dataCacheClient>
  . . .

この通知ですが、上記の構成 (.config) を見ていただくとわかるように、ポーリングによる通知メカニズムであるという点に注意してください。このため、現状は、キャッシュの更新処理をトリガするような Cache through feature のような目的で使用することはできません。
また Remove も通知されますが、expiration / eviction による通知は、非常に遅いタイミングで返ってきますので注意してください。

高可用性オプション (High Availability, HA)

AppFabric cache では、障害発生によるノード (マシン) の突然の停止の際に、キャッシュ内のデータをロストしないための設定が可能です。Windows PowerShell で、下記の通り設定します。

New-Cache HogeHoge -Secondaries 1

上記の設定をおこなうことで、Key-Value のアイテムは、常に、Primary と Secondary の双方が異なるノード上に配置されるようになります。(書き込みをおこなうと、Primary、Secondary の双方に、同期的に書き込みをおこないます。) そして、ノードがトラブルなどで停止した場合も、Primary、Secondary の再配置をして、引き続き、高可用性を保障します。

この動きのイメージを、下記のスライド ショーで示します。(下図を Click してください)

なお、Windows Server 2008 以降の Enterprise Edition / Datacenter Edition 以上のエディションが必要となるので、注意してください。

管理 / 監視

以前、「Windows Server AppFabric caching 入門」で解説したように、Windows PowerShell を使って、クラスター、キャッシュの操作 (開始/停止、キャッシュ作成、など) がおこなえますが、こうした「操作」以外の管理用途でも Windows PowerShell を活用することができます。
例えば、以下のコマンドでは、そのノードに配置されているアイテムの状況 (個数など) を確認できます。

Get-CacheStatistics -HostName machine1 -CachePort 22233

また、プログラミングを使って、構成 (config) の設定、オブジェクトの取得など、管理的な記述もおこなえます。例えば、下記では、すべての Region のすべてのアイテム (Key-Value) の内容を確認しています。(C# の例です。)

string cachename = Console.ReadLine();
var factory = new DataCacheFactory();
var cache = factory.GetCache(cachename);
List<string> regions = (List<string>) cache.GetSystemRegions();
foreach (string region in regions)
{
  IEnumerable<KeyValuePair<string, object>> items = 
    cache.GetObjectsInRegion(region);
  if (items.Count<KeyValuePair<string, object>>() > 0)
    Console.WriteLine("Region:{0}", region);
  foreach (KeyValuePair<string, object> item in items)
  {
    Console.WriteLine("Key:{0} Value:{1}",
      item.Key, item.Value.ToString());
  }
}

Windows PowerShell の Get-CacheRegion (Region の一覧と、ホスト名が返ってきます) と上記を組み合わせれば、どのアイテムが、どのホストにあるか、一覧を取得することもできます。チューニングや状態確認などをおこなう上で、Windows PowerShell やプログラム コードが非常に役に立つことがおわかり頂けるでしょう。

また、サービス起動時のエラーなど基本的なものはイベント ビューアー (eventvwr) で確認できますが、キャッシュへの操作内容 (Get など) の監視など、細かな操作の監視をおこなう場合は、Windows SDK の tracelog.exe を使用して、以下の通り、ETW トレースをおこないます。

rem -- ETW トレースを開始して test.etl に出力
tracelog -start debugtrace -f test.etl -guid "C:\Windows\System32\AppFabric\Manifests\ProviderGUID.txt" -level 5 -cir 512
rem -- ETW トレースを終了
tracelog -stop debugtrace
rem -- トレースの内容を CSV として出力
tracerpt .\test.etl -o test.csv -of CSV

アプリケーションへの応用

Velocity では、基本的には、Get/Put/Add/Remove などのプリミティブ (Primitive) な操作を提供するのみで、アプリケーション レベルの Abstraction は、開発者みずからが構築します。
しかし、いくつかの基本的な Abstration (アプリケーション) については、下記の通り、既にさまざまな形で提供されていますので、いくつかを紹介します。

  • ASP.NET Session での使用 :
    ASP.NET の Session データの格納先としてこのインメモリ キャッシュ (AppFabric Cache) を使いたい場合、実は、Velocity が提供しているアセンブリの中に、既にこのためのプロバイダー クラスが提供されています。以下は、このクラス (DataCacheSessionStoreProvider) を使って sessionState を構成したサンプルです。(Tech Ed Japan で説明したいくつかの注意点がありますが、ここでは、これらの説明は省略します。。。)

<sessionState mode=”Custom” customProvider=”MyVelocity”>
<providers>
<add name=”MyVelocity”
type=”Microsoft.ApplicationServer.Caching.DataCacheSessionStoreProvider, Microsoft.ApplicationServer.Caching.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3,856ad364e35″
cacheName=”SessionTest”/>
</providers>
</sessionState>

  • OR マッパーの second level cache としての使用 :
    ADO.NET Entity Framework や NHibernate などの second level cache として使用する場合、CodePlexSourceForge に Velocity 用のライブラリが提供されています。
  • ASP.NET のキャッシュ プロバイダー :
    ASP.NET 4 では、System.Web.Caching.OutputCacheProvider クラスから派生して独自のキャッシュ プロバイダーを作成できます。
    この手法を使用して、Velocity を使用した出力キャッシュのプロバイダーを構築することも可能です。(なお、Windows Azure caching では、このプロバイダー クラスが既定で提供されています。)

補足 : ASP.NET Session で使用する際には、下記の通り、アプリケーション プールの Virtual Account にもキャッシュの利用権限を付与しておきましょう。
Grant-CacheAllowedClientAccount “IIS APPPOOL\ASP.NET v4.0”

 

以上、スタートされる方のために、まず、どのようなことが可能か大まかに解説しました。以降の詳細 (疑問等) は、是非 MSDN をご活用ください。

 

Comments (0)

Skip to main content