Java EE7 䛸㻌JCache

Preview:

DESCRIPTION

 

Citation preview

Java EE7 と JCache

@maruyama097 丸山不二夫

はじめに

o  筆者の基本的な問題意識は、ネットワーク上のマーケットが急速に拡大するという展望の中で、エンタープライズ・システムを、もっと高速でスケーラブルなものにしつつ、トランザクションの正確性をきちんと担保することである。

o  そこでは、キャッシュ技術は欠かせない。 事実、分散キャッシュについては、多くの商業製品、オープンソースのプロジェクトが登場し利用されている。にもかかわらず、エンタープライズJavaの標準的なキャッシュ技術というべきものは、存在しなかった。

o  その点で、Java EE7の仕様の一つとして、エンタープライズJavaの標準的なキャッシュ技術となるべく検討されている、JCacheに、注目している。

はじめに

o  プレゼンの前半で、同じキャッシュというくくりで、CPUとメモリーの間に置かれている、キャッシュの問題についてCliff Clickの議論の紹介をした。もっとも、これは、キャッシュが有効に機能していないという例なのだが。

o  また、CPUのMulti-core化が、キャッシュにとってどういう意味を持つかを考えてみた。意外と複雑で、残念ながら、すっきりした見通しは持てなかった。

o  現在のJCacheの仕様には、分散キャッシュの実装、あるいは、そのインターフェースの利用について、明示的な言及は無い。昨年、立ち上がった、JSR 347: Data Grids for the JavaTM Platform が、その一つの答えだと思うのだが、今後の進展を注目している。

Agenda

o  CPUとキャッシュ o  Multi-Core CPUとメモリー o  システムの階層性とキャッシュ o  WebアプリのScale-outと

分散メモリーキャッシュ、NoSQL o  JSR 347: Data Grids for the JavaTM

Platform o  JSR 107: JCACHE - Java Temporary

Caching API

CPUとキャッシュ

Not Your Father's Von Neumann Machine:A Crash Course in Modern Hardware Cliff Click Azul Systems Brian Goetz Sun Microsystems http://www.azulsystems.com/events/javaone_2009/session/2009_J1_HardwareCrashCourse.pdf から

CPU Performance

Multicore era

Frequency scaling era

CISC era

CPUとメモリーのスピードのギャップ

o  CPUとメモリーのスピードのギャップは拡大している。かつてのCPUのメモリーアクセスは、レジスターのフェッチよりほんの少し遅いだけだった。今日では、メイン・メモリーからのデータの取り込みは数百クロック・サイクルを要する。 http://t.co/PekDYDFf

CPUのキャッシュ

o  かつては、乗算は高価な処理で、メモリーからのLoadは安価な処理だった。しかし、今では、乗算は安価な処理で、メモリーからのLoadは、高価な処理である。

o  CPUとメモリーのスピードのギャップが広がる中で、今日のCPUは、洗練された多段のキャッシュを発展させてきた。ただ、CPUのパフォーマンスに、決定的な影響を与えるのは、CPUの実行スピードではなく、キャッシュ・ミスなのである。

o  Static RAMは、高速だが高価である。Dynamic RAMは、安価だが低速である。CPUのキャッシュとは、高速のSRAMをCPUの近くに配置して、メモリーのパフォーマンスを良くしようと言うもの。

コードとデータの局所性

o  キャッシュが効くのは、多くのプログラムのコードもデータも「局所性」を持つから。コードとデータは、それぞれ固有の「局所性」を持つので、コードのキャッシュとデータのキャッシュの両方が必要である。

データをCPUの近くに置く

o  「データをCPUの近くに置くこと!」 メモリー遅延の最大の要因は、伝送線の遅延である。ここでは、情報伝達の上限である光のスピードが問題になる。1GHzのCPUの1クロックの間に、信号は、光のスピードでも、30cm以上を進むことが出来ない。

o  CPU-メモリーのスピードギャップが広がるにつれ、多段のキャッシュが必要になってきた。ただレジスタへのアクセスが、1クロック以下で可能なのに対して、L1キャッシュは3clk、L2キャッシュは15clk、メモリーアクセスには200clk必要 http://t.co/pmEqEmt9

メモリーは、新しいディスク

o  キャッシュミスの確率は、現在ではかなり低い。ただ、キャッシュミスによって、100〜1000命令分の時間のコストが発生する。だから、キャッシュミスの確率が5%前後だとしても、パフォーマンスに対するインパクトは、キャッシュミスの方が大きなものになる。

o  CPUとメモリーのスピードのギャップが拡大するにつれて、キャッシュミスがCPUのパフォーマンスを決めるといってもいいのだ。「いまや、メモリーは、新しいディスクなのだ。」

Multi-coreとキャッシュ

o  Multi-coreのシステムでは、最下層のキャッシュは、いくつかのコアで共有されている。

o  しかし、全てのキャッシュが、全てのコアから見える訳ではない。

Multi-Core CPUとメモリー

http://www.socip.org/socip/speech/pdf/20110708-080436-Perfectvips-SoCIP%202011%20Presentation.pdf

わずか10年の間のトランジスタ数の変化

Multi-Coreのコア数とトランジスター数

コア数 トランジスター数 CPU

2 300M Apple A5

10 2600M Westmere EX

48 1300M SCC

100 500M Tile GX 100

Multi-Coreのコア数と外部メモリー

o  コアの数が増えても、そのチップからアクセス可能なメモリーの量は、コアの数に比例して増えていく訳ではない。‎100コアのTilera TileGX100が、10コアのWestMere-EXの、10倍のメモリー空間を持つ訳ではない。

o  Multi-Coreチップの外部メモリーの量は、コアの数ではなく、そのチップが何個のメモリー・コントローラを持っているかで上限が決まっている。4個のメモリーコントロラーをもつSCCのメモリーは、4x16の64G「しか」ない。

o  そこは、コモディティ化したノードをメモリー、ディスクごと増やしていく、これまでのスケールアウト・アーキテクチャーのメモリーの計算の仕方とは、異なる。

SCCのメモリー構造

共有外部メモリー(可変長)

コア毎の 外部メモリ (可変長)

L1 Cache 16K

cpu_0 L2

Cache 256K

コア毎の 外部メモリ (可変長)

L1 Cache 16K

cpu_47 L2

Cache 256K

チップ上の共有メッセージ・パッシング・バッファー 384K 8K/core

SCCの共有仮想メモリー空間

o  コアをまたいだ、共有仮想空間が利用できる。

o  アプリケーションから見ると、単一のメモリー空間に見える。

o  複数のcore間で、シームレスにデータ構造やポインターを共有できる。

共有 仮想メモリー

アプリケーション

基本的に、Parallel型の利用法

SCCの物理アドレス

o  SCCのそれぞれのコアは、32ビット(4GB)のアドレス空間を持っている。

o  通常は、物理アドレスは、FSB(Front Side Bus)上に見える。

o  SCCでは、物理アドレスは、十分ではない。64GBのメモリーと、無数のSCCシステム・アドレス(12bit+34bit)がある。

o  物理アドレスをSCCシステム・アドレスに変える変換器が必要である。

48コアが、4つのメモリーコント ローラを持つ。デフォールトでは 12コアに一つのコントローラが 割り当てられている。

In-Memory Communication Mechanisms for Many-Cores - Experiences with the Inte SCC

http://communities.intel.com/docs/DOC-19423

Efficient Memory Copy Operations on the 48-core Intel SCC Processor

http://dare.uva.nl/document/356252

システムの階層性とキャッシュ

処理スピードで規定される階層性

o  システムの階層性を規定しているのは、処理のスピードである。次のような階層がある。 CPU > メモリー > ディスク > ネットワーク

o  キャッシュは、基本的には、階層間をつなぐ働きをする。 n  CPU/メモリー: L1,L2キャッシュ n  メモリー/ディスク: nio、mmap。ディスクのメモリー・キャッシュ。

SSD。 n  メモリー/ネットワーク: ... n  ディスク/ネットワーク: ...

メモリーのコストの階層性

o  処理スピードの階層性の他に、コストの階層性がある。基本的には、処理スピードの階層性を裏打ちしているようにも見えるが、本来は、別の原理である。 SRAM > DRAM > SSD > Disk

o  SRAMのように高速で、DRAMのように安価なメモリーが登場すれば、アーキテクチャは、大きく変わりうる。

ネットワークのスピードとコスト

o  こうした処理スピードとコストの階層性は、固定的なものでは無い。ネットワークの処理スピードは向上し、コストは低下しうる。もし、次のようになったら? CPU = ネットワーク > メモリー > ディスク

o  Gilderは、かつて、次のように述べていた。 ネットワークがコンピュータの内部バスと同じぐらい早くなれば、マシンは、特定の目的を持ったデバイスのあつまりへとネットワーク上で分解するだろう。

Hard Disk

http://www2s.biglobe.ne.jp/~sakharov/index.html

ディスクの価格低下のインパクト

半導体のMoore則

ディスクの価格低下

ディスク1G 5円

ACM 2012 The Future of Microprocessors

o  プロセッサのパフォーマンスの新しい基本的な制限が、エネルギー効率だと言う視点からの分析。

o  今日のプロセッサのパフォーマンスは、毎秒100Giga-opのオーダーである。パフォーマンスは、次の10年で30倍になり、毎秒3Tera-opに達するであろう。

o  少なく見積もっても、この時、9T-オペランド、すなわち64b × 9T-オペランド (576T-bits!) が、毎秒、レジスター/メモリーから演算器等に移動するのだが、それはエネルギーを消費する。

http://delivery.acm.org/10.1145/1950000/1941507/p67-borkar.pdf

o  もしもオペランドが平均して1mm (ダイサイズの10%)移動するとして、0.1pJ/bitの割合だとすると、576T-bitsの移動は、約58ワットを消費することになり、計算に必要なエネルギーは、ほとんど残っていない。

o  Many-coreシステムのコアは、コアとコアの間を、チッ

プ上のネットワークを通じてデータが移動する。 o  オペランドの10%がネットワーク上に流れ、平均10ホッ

プで移動するとして、0.06pJ/bit としてネットワークの電力消費は、35ワットになり、プロセッサーに割り当てられている電力の半分以上を消費することになる。

WebアプリのScale-outと 分散メモリーキャッシュ、NoSQL

Web Appli Multi-tier のScale-out戦略

Web Server  Business Logic Daa Base

・・・・・・・

Web Appli Multi-tier のScale-out戦略

Load Balancer

Web Server Business Logic

Daa Base

・・・・・・・

Web Appli Multi-tier のBottle Neck

Load Balancer

Web Server Business Logic

Daa Base

Multi-tier の分散メモリーCache

・・・・・・・

Load Balancer

Web Server Business Logic

Daa Base

Cloud上の分散データベース

On Memory Hash

Persistency

分散キャッシュのプロダクト

o  市場には、多くの分散キャッシュのプロダクトが、存在している。

o  代表的なものをあげれば、 OracleのCoherence (Cameron Purdy)、 IBMのeXtreme Scale (Billy Newport)、 TerracottaのEhCache (Greg Luck)、 MicrosoftのAppFabric。

o  もちろん、低レーヤでは、オープンソースのmemcachedが広く利用されている。日本発のキャッシュ技術も、優れたものがある。

n  個人的には、JSR107のEGに、Cameron Purdy、Billy

Newport、Greg Luckの三人が入っているのに、期待している。

キャッシュとNoSQLの比較

o  キャッシュは、Key/Value。 NoSQLのあるものは、Key/Value。

o  キャッシュの主目的は、パフォーマンス。 NoSQLの主目的は、永続性。

o  キャッシュは、永続性を持ちうる。 NoSQLは、常に永続性を持つ。

o  永続するキャッシュは、NoSQLのユースケースの一部をカバーする。NoSQLのあるものは、キャッシュのユースケースをカバーする。

キャッシュとNoSQLの比較

o  キャッシュのサイズは小さい。〜数十GB NoSQLのサイズは、数TB〜数PB

o  キャッシュはメモリーに置かれる。 NoSQL、RDBMSは、ディスクに置かれる。

o  キャッシュは、メモリー上のデータストア。 NoSQLは、Relation無しのDBMS。

JSR 347: Data Grids for the JavaTM Platform

Description

o  この仕様は、分散データグリッドに、アクセスし、格納し、データを管理するAPIを提供することを目的としたものである。

o  最初のAPIは、JSR-107 (JCACHE) APIの上に、その拡張として構築されるだろう。JSR-107は、キャッシュにアクセスする一般化されたMAPに似たAPIに加えて、イン・メモリーのデータをパーシステントなストレージにスプールするSPI、CacheManagerから名前のついたCacheを取得するAPI、イベント・リスナーを登録するAPIを定義している。

o  JSR-107の上にそれを超えて、このJSRは、権限の引き渡し、複製化、分散、トランザクション(JTAの仕様に基づいて)の特徴と期待される特質を定義するだろう。

o  さらに、非同期で、ノンブロッキングなAPIを、JSR-107の最初のAPIに変わるものとして定義するだろう。というのも、データに対するノンブロッキング・アクセスは、データグリッドのように、リモート呼び出しを実行する必要のある実装では、関心事になるからである。

o  この仕様は、まだ完成していないJSR-107の上に構築される。我々は、彼らのスケジュールが、このJSRのスケジュールと両立出来ることを保証する為に、JSR-107のEGと、ともに作業する意向である。もし、JSR-107が完成することが出来なければ、最後の利用可能なドラフトを、この仕様にマージすることを提案する。

Proposed features

o Async API (Future based) public interface AsyncCache<K, V> {

Future<V> get(K key); Future<Void> put(K key); Future<V> getAndPut(K key); Future<Boolean> remove(K key); Future<V> getAndRemove(K key); ... etc ... }

Proposed features o Distributed code execution

n  Map/Reduce n  Alternate proposal

o Group API o CDI (Contexts and Dependency

Injection) integration o  Transactions (JTA) integration o Operation Mode o  Eventually Consistent API

Proposed features

o Configuration o Drop-In Replacement for JSR-107

Compliant Caches

JSR-347 Spec Lead Manik Surtani氏とのインタビュー

o  JSR 347はJavaプラットフォーム向けのデータグリッドとしても知られていますが、APIとプログラミングモデル、そしてフォルトトレラントなインメモリの分散キーバリューストアの振る舞いについて標準化するために提案されたものです。JSR 107 (Javaプラットフォーム向け一時キャッシュ)との違いはたくさんあります。

o  データの永続性。JSR 347はレコードの保存機構であり、本質的な分散の仕組みによって耐久性を提供します。一方、JSR 107は一時的で揮発性の高いデータを保存する前提の仕様です。

http://www.infoq.com/jp/news/2011/10/java-data-grid

JSR-347 Spec Lead Manik Surtani氏とのインタビュー

o  分散。JSR 107の実装は分散化されていてもかまいません。一方、JSR 347の実装は分散化されていなければなりません。従って、JSR 347の方がデータストアの使い勝手を向上させるためにより機能豊富なAPIを提供します。例えば、グリッド上のデータの保存場所を制御するAPIや非同期のノンブロッキングAPI、実装の一貫性をサポートするAPIは、実装が分散化されているということを知っていなければ意味がありません。

JSR-347 Spec Lead Manik Surtani氏とのインタビュー

o  Map/Reduceと分散コード実行。データがグリッド上に分散/パーティションされている場合、コードの実行をデータ側に移動させた方が他の方法よりも合理的な場合があります。JSR 347はこのようなことを実現するAPIも提供する予定です。

JSR-347に対する VMWareの反対意見

o  VMware has serious concerns around the proposed JSR's relationship with JSR-107. While we note that some other EC members hope that the necessary harmonization can occur after the approval of this JSR, we would prefer to see such discussions take place before another potentially competing JSR is approved, and see that path as less risky.

JSR-347に対する VMWareの反対意見

o  We do believe that this area is important and warrants interest from the JCP. The JSR-347 proposal includes useful functionality, but raises a serious risk of fragmentation and confusion.

o  We would prefer to see JSR-107 brought swiftly to a conclusion without excessive scope creep, allowing a new JSR then to be presented building upon it.

Object Caching for Java

Functional Specification for Object Caching Service for Java (OCS4J), 2.0

http://jcp.org/aboutJava/communityprocess/jsr/cacheFS.pdf

Objectの三つのタイプ

1. 決して変化しないオブジェクト n  staticで初期化すればいい

2. ユニークで使い捨てのオブジェクト n  使うたびにnewすればいい

3. 上記2つの中間のオブジェクト n  Javaは、先2つのタイプのオブジェクトは簡単に扱え

るが、第三のタイプのオブジェクトを扱うのは不便。

「第三のタイプ」とは、複数のリクエストをまたいで、ユーザーの間やプロセスの間で、 変化し共有されうる情報やオブジェクト。

Object Caching Service for Java (OCS4J) の目的

o  Caching Service for Java (OCS4J)の目的は、アプリケーションが、リクエストやユーザーやプロセスをまたいで、オブジェクトを共有することを可能にすること。

o  このシステムは、任意のJavaオブジェクトを扱うことが出来る。全てのオブジェクトは、「名前」によって位置づけられ、プロセス中の全てのスレッドによって共有される。

キャッシュされた オブジェクトのLife Cycle

o オブジェクトの生成 n  ユーザーが定義したLoaderで行われる n  不要な生成を避ける為に、キャッシュシステムと

の協調が必要 o オブジェクトの無効化

n  アプリから明示的に行うことも可能 n  “time to live” あるいは “idle time” に関連して n  キャッシュシステムの容量オーバー(設定可能)

o オブジェクトの削除

キャッシュされた オブジェクトのLife Cycle

o  オブジェクトの削除 n  最近使われていないオブジェクト n  削除されたオブジェクトは、ディスクにスプール可能 n  スプールの決定は、ユーザーが定義したオブジェク

トの属性による

o  コールバック n  オブジェクトがキャッシュシステムで無効化あるいは

削除された時、登録されたコールバック・メソッドを呼び出すように出来る。

キャッシュとプロセス

o  システムの単純性、可用性、パフォーマンスの為に、オブジェクト・キャッシュは、それぞれのプロセスに結びつけられている。

o  キャッシュ・システムでのオブジェクトの生成には、中央からのコントロールといったものは存在しない。

o  しかし、オブジェクトの更新と無効化についてはプロセス間の調整がある。 n  あるプロセスでオブジェクトが更新あるいは無効化

された時、その名前と関連情報は、他の全てのキャッシュのインスタンスにブロードキャストされる。

GAEでのJCache の利用

Cache インスタンスの取得

Cache cache; try { CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory(); cache = cacheFactory.createCache(Collections.emptyMap()); } catch (CacheException e) { // ... }

値の設定と取得

String key; // ...         byte[] value; // ... // Put the value into the cache. cache.put(key, value); // Get the value from the cache. value = (byte[]) cache.get(key);

有効期限の設定

Cache cache; Map props = new HashMap(); props.put(GCacheFactory.EXPIRATION_DELTA, 3600); try { CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory(); cache = cacheFactory.createCache(props); } catch (CacheException e) { // ... }

値の有効期限は次のプロパティで制御

o  GCacheFactory.EXPIRATION_DELTA: 値を設定した時点から有効期限までを秒数で指定する整数値

o  GCacheFactory.EXPIRATION_DELTA_MILLIS: 値を設定した時点から有効期限までをミリ秒数で指定する整数値

o  GCacheFactory.EXPIRATION: 有効期限の日時を指定する java.util.Date

設定ポリシーの設定

Map props = new HashMap(); props.put(MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT, true);

o  MemcacheService.SetPolicy.SET_ALWAYS: キーに値が存在しない場合は値を追加し、そのキーの値が存在する場合は既存の値を置き換えます。これがデフォルトの設定です。

o  MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT: キーに値が存在しない場合は値を追加し、そのキーの値が存在する場合は何も実行しません。

o  MemcacheService.SetPolicy.REPLACE_ONLY_IF_PRESENT: キーに値が存在しない場合は何も実行せず、そのキーの値が存在する場合は既存の値を置き換えます。

キャッシュの統計

CacheStatistics stats = cache.getCacheStatistics(); int hits = stats.getCacheHits(); int misses = stats.getCacheMisses();

サポートされていない JCache 機能

o  JCache Listener API は、onPut リスナや onRemove リスナなど、アプリケーションの API 呼び出しの処理中に実行できるリスナについては一部サポートされています。onEvict など、バックグラウンド処理が必要なリスナはサポートされていません。

o  アプリケーションは、キャッシュ内に指定のキーがあるかどうかをテストすることはできますが、指定の値があるかどうかはテストできません(containsValue() はサポートされません)。

o  アプリケーションでキャッシュのキーまたは値の内容をダンプすることはできません。

o  アプリケーションで手動でキャッシュの統計をリセットすることはできません。

o  非同期のキャッシュ読み込みはサポートされていません。

o  put() メソッドは、キーの以前の値を認識していても値を返さず、常に null を返します。

JSR107 JCache 仕様

「一時的なメモリー内のJavaオブジェクトのキャッシングのAPIとセマンティックスを規定する。オブジェクトの生成、共有アクセス、スプーリング、無効化、複数のJVMをまたいだ整合性を含む。」

経緯

o  2001年5月 JSRスタート o  2003年12月 CoherenceのCameron Purdy、

Spec Leadに o  2007年5月 EhCacheのGreg Luck、co-Spec

Leadに o  2012年4月 新しい体制 Brian Oliver (Oracle), Cameron Purdy (Oracle), Greg Luck,..., Billy Newport o  Early Draft 1, still in progress.

https://github.com/jsr107/jsr107spec

現時点でのRIに 含まれているパッケージ

o  javax.cache o  javax.cache.annotation o  javax.cache.event o  javax.cache.mbeans o  javax.cache.spi o  javax.cache.transaction

https://github.com/jsr107/jsr107spec/tree/master/src/main/java/javax/cache

Chapter 1 - Introduction

目的

o  キャッシングは、アプリを劇的にスピードアップする、試されずみの、真実の方法である。

o  アプリは、生成するのに高価だが再利用可能なライフタイムを持つ一時的なデータを、しばしば、使うことがある。

o  例えば、サーブレットは、複数のデータベース、ネッチワークのコネクション、そして高価な計算から得られるデータから、Webページを生成する。これらのデータセットは、同じ、あるいは異なった時間のあいだ、再利用可能かもしれない。

o  この仕様は、Javaオブジェクトのキャッシングの標準化を行い、その効果的な実装を可能とし、キャッシュのエクスパイア、相互排他制御、スプーリング、キャッシュの整合性といったものを実装する重荷を、プログラマーから取り除くようにしようとするものである。

目標

o  Object Cache: このAPIは、Javaオブジェクトをキャッシュする。

o  Support for By-Value caching and optionally, By-Reference. 後者の参照はヒープの中に、前者では、キーと値は、両方とも、値に変換される。

o  Support for Flexible Implementations 仕様は、プロセスでの実装と、分散での実装の両方をサポートする。

o  Java SE   この仕様はJava SEのもとで機能する。 o  Java EE

この仕様は、Java EEのもとで機能する。この仕様は、Java EE7に含まれることを目標としている。

o  Annotations この仕様は、ランタイムのキャッシュ・アノテーションを定義する。

o  Transactions トランザクションのオプショナルなサポート。ローカルとXAの双方が定義される。

Chapter 2 - Caches

キャッシュとは?

o  キャッシュは、一時的なデータを格納する場所である。それは、Mapに似たAPIを提供する。Mapと同様に、データはキーの値として格納される。

o  データは、Mapと同じく、ユニークな識別子であるキー経由でアクセスされる。与えられたキーに対して、キャッシュには一つのエントリーしか存在出来ない。

o  最も重要なプログラミングの対象物は、Cacheインターフェースである。Cacheへの呼び出しは、このインターフェースを通じて行われる。

キャッシュの利用

o  データベースからのデータがキャッシュされるとよく思われている。もし、JPAを使っているなら、確かに、そういうことになる。

o  ただ、基本的には、作り出すのが高価で時間を要するものは、なんであれキャッシュに格納出来る。

キャッシュの利用例

o  データベースの行のキャッシング o  プロセス中のNoSQLデータのキャッシング o  サーブレットのレスポンスのキャッシング o  クライアント側でのWebサービス呼び出しのキャ

ッシング o  イメージのレンダー等の高価な計算のキャッシング o  DOMのキャッシング

キャッシュのKey/Value

o  KeyとValueに、特別の型の制限はない。 o  ただし、KeyとValueは、Nullであってはなら

ない。nullキーでのアクセスも、null valueを設定しようとした場合にも、NullPointerExceptionが返る。

o  キャッシュは、 storeByValueをサポートしなければならない。その意味は、キー/バリューを、オブジェクトではない表現に変換する方法がなければいけないということである。 これは、典型的には、ネットワーク上で送信出来る、あるいは、永続的なストアに格納出来る、メモリー外での表現のことを意味する。

o  これを達成する一つの方法は、キー/バリューが、Serializableインターフェースを実装することである。ただ、実装には他の方法を用いることも出来る。Serializable以外の方法をサポートするスキームは、実装依存であり、実装間の移植性を必要とはしない。

キャッシュを見つける

o CacheManagerは、キャッシュを管理する。 o キャッシュは、名前で同定され、アクセスされる。 o キャッシュへの参照は、次のようにgetCache

で得られる。 Cache cache = cacheManager.getCache(“Greg’s Cache”);

Chapter 3 - Cache Operations

Cache Operations

o  Cacheインターフェースは、 ConcurrentMapパターンに基づいている。ただ、それを継承したものではない。

o  というのも、 ConcurrentMap (とMap)のメソッドのあるものは、分散環境では、効率的ではないシグニチャーをもつからだ。例えば、Map.putは、ある値を返すのだが、たいていの場合、それは無視される。

Cache メソッド

o  V get(K key) o  Map<K,V> getAll(Set<?

extends K> keys) o  boolean

containsKey(K key) o  Future<V> load(K key) o  Future<Map<K,? extends

V>> loadAll(Set<? extends K> keys)

o  CacheStatistics getStatistics()

o  void put(K key, V value) o  V getAndPut(K key,

      V value)

o  void putAll(Map<? extends K,? extends V> map)

o  boolean putIfAbsent (K key, V value)

o  boolean remove(K key) o  boolean remove 

(K key,V oldValue) o  V

getAndRemove(K key) o  boolean replace(K key,

V oldValue, V newValue) o  boolean replace(K key,

V value)

Cache メソッド

o  V getAndReplace (K key, V value)

o  void removeAll(Set<? extends K> keys)

o  void removeAll() o  CacheConfiguration<K,V

> getConfiguration() o  boolean

registerCacheEntryListener(CacheEntryListener<? super K,? super V> cacheEntryListener)

o  Iterator<Cache.Entry<K,V>> iterator()

o  boolean unregisterCacheEntryListener(CacheEntryListener<?,?> cacheEntryListener)

o  Object invokeEntryProcessor(K key, Cache.EntryProcessor<K,V> entryProcessor)

o  String getName() o  CacheManager

getCacheManager() o  <T> T

unwrap(Class<T> cls)

Cache Entry Expiration

o  キャッシュ中のエントリーは、最終更新時あるいは最終アクセス時間に基づいて、エクスパイアする。javax.cache.CacheConfiguration.ExpiryTypeによってコントロールされる。

Read-Through Caching

o  read-through キャッシュは、read-through ではないキャッシュと全く同じように振る舞う。ただ、エントリーがキャッシュに見つからなかった場合、get()とgetAll()が、CacheLoaderを呼び出す点が異なる。

Write-Through Caching

o  Proxyである。どのような変化も、常に、CacheWriterを呼び出す。

o  write-through モードの時、removeAllNoWriteThroughは、キャッシュのみを全消去する。

ライター

参考:eXtreme Scale 後書きキャシング

o  後書きキャッシングは、ローダー・プラグインへの更新情報を 非同期でキューに入れます。eXtreme Scale トランザクションをデータベース・トランザクションから分離することにより、マップの更新、挿入、 および除去の、 パフォーマンスを改善 できます。非同期更新は、時間ベース の遅延 (例えば、5 分)、 またはエント リー・ベースの遅延 (例えば、1000 エントリー) 後に 実行されます。

http://publib.boulder.ibm.com/infocenter/wxsinfo/v7r1/index.jsp?topic=%2Fcom.ibm.websphere.extremescale.over.doc%2Fcxswritethr.html

CacheLoader o  CacheLoaderインターフェースは、キャッシュのプリ・ロ

ードと、キャッシュミス時の特別なアクションを可能とする2つの場合に用いられる。

o  後者の場合は、例えば、read-throughが実装されている場合には、CacheLoaderが利用される。

CacheEntryListener n  CacheEntryCreatedListener n  CacheEntryUpdatedListener n  CacheEntryRemovedListener n  CacheEntryReadListener

o  Listenerは、次のいずれかの通知スコープに登録される。 n  local – このJVMの中でイベントが発生する n  remote – リモートのJVMでイベント発生

Chapter 4 - Cache Managers

Cache Managers

o CacheManagerは、キャッシュの集まりで、そのコンテナーである。コンテナーとして、それは、キャッシュのライフサイクルの全ての局面を管理する。

Cache Managersの機能

1.  キャッシュを名前で見つけ出す機能 2.  Transactionマネージャにとって、XA Resourceとして

働く。 3.  キャッシュのユニットに対して設定の対応をする。 4.  自身が起動されると、全ての設定されたキャッシュを起動

する。 5.  CacheManagerがシャットダウンされると、その内部の

全てのキャッシュはシャットダウンされる。 6.  分散キャッシュのクラスターの統合ポイントである。起動

時には、必要なリソースを割り当て、シャットダウン時には、それらを解放する。

Cache Managersの機能

7.  デフォールトのキャッシュのテンプレートを提供し、新しいキャッシュが意味のあるデフォールトで作られるようにする。

8.  シングルトンとして、ただ一つのCacheManagerしか存在しない場合に用いられることもあるし、もっと複雑なケースでは、VMあたり複数のCacheManagerがもちられることもある。

9.  キャッシュの繰り返しや追加や削除をサポートする。

Construction

o シングルトンのCacheManagerは、次のように構成され、参照される。

  CacheManager.getInstance() o インスタンスの構成

複数のCacheManagerのインスタンスは、次のようにして生成される。

  new CacheManager()

Default CacheManager o  利用を簡単にするために、実装はデフォールトの

設定を提供すべきである。そうすれば、ユーザによって提供される実装に特有の設定ファイルが無い場合でも、CacheManagerを生成することが出来、キャッシュはそれに追加される。

o  Java SEが、この仕様と参照実装を追加して、こうした機能がJava SE でも利用可能になることが期待されている。

Cache<Integer, Date> myCache2 = cacheManager. <Integer, Date>createCacheBuilder("myCache2"). build();

Cache Configuration

Cache<Integer, String> myCache1 = cacheManager. <Integer, String>createCacheBuilder("myCache1"). setCacheLoader(cl). setStoreByValue(true). setReadThrough(true). setWriteThrough(false). setStatisticsEnabled(true). setTransactionEnabled(false). registerCacheEntryListener(listener1,          NotificationScope.LOCAL, false). registerCacheEntryListener(listener2,         NotificationScope.LOCAL, false). build();

simple example

String cacheName = "sampleCache"; CacheManager cacheManager = Caching.getCacheManager(); Cache<Integer, Date> cache = cacheManager.getCache(cacheName); if (cache == null) { cache = cacheManager.<Integer,Date>createCacheBuilder(cacheName).build(); } Date value1 = new Date(); Integer key = 1; cache.put(key, value1); Date value2 = cache.get(key);

o  boolean putIfAbsent(K key, V value) if (!cache.containsKey(key)) { cache.put(key, value); return true; } else { return false; }

Interface CacheManager o  <K,V> CacheBuilder<K,V> createCacheBuilder(String

cacheName) o  <K,V> Cache<K,V> getCache(String cacheName) o  Iterable<Cache<?,?>> getCaches() o  String getName() o  Status getStatus() o  UserTransaction getUserTransaction() o  boolean isSupported(OptionalFeature optionalFeature) o  boolean removeCache(String cacheName) o  void shutdown() o  <T> T unwrap(Class<T> cls)

Interface CacheBuilder<K,V>

o  Cache<K,V> build() o  CacheBuilder<K,V>

registerCacheEntryListener(CacheEntryListener<K,V> cacheEntryListener)

o  CacheBuilder<K,V> setCacheLoader(CacheLoader<K,? extends V> cacheLoader)

o  CacheBuilder<K,V> setCacheWriter(CacheWriter<? super K,? super V> cacheWriter)

o  CacheBuilder<K,V> setExpiry(CacheConfiguration.ExpiryType type, CacheConfiguration.Duration duration)

o  CacheBuilder<K,V> setReadThrough(boolean readThrough)

Interface CacheBuilder<K,V>

o  CacheBuilder<K,V> setStatisticsEnabled(boolean enableStatistics)

o  CacheBuilder<K,V> setStoreByValue(boolean storeByValue)

o  CacheBuilder<K,V> setTransactionEnabled(IsolationLevel isolationLevel, Mode mode)

o  CacheBuilder<K,V> setWriteThrough(boolean writeThrough)

Interface CacheLoader<K,V>

o  CacheLoaderは、read-throughキャッシングで利用され、データをキャッシュにロードする。

o  Cache.Entry<K,V> load(K key) Loads an object.

o  Map<K,V>loadAll(Iterable<? extends K> keys) Loads multiple objects.

Interface CacheWriter<K,V>

o  CacheWriterは、 背後にあるリソースへのwrite-throughキャッシングとwrite-behind キャッシングで利用される。

o  void delete(Object key) o  void deleteAll(Collection<?> entries) o  void write(Cache.Entry<K,V> entry) o  void writeAll(Collection<Cache.Entry

<? extends K,? extends V>> entries)

Class Caching

o  JDKのServiceLoaderのSPI規約を利用して、CacheManagers を生成する為のFactoryである。

o  プロバイダが発見される為に、そのjarファイルは、次のように、CachingProviderを実装したクラス名のリソースを含まなければならない。

META-INF/services/ javax.cache.spi.CachingProvider 例えば、参照実装では、この中味は次のようになる。 "javax.cache.implementation.RIServiceFactory"

Class Caching

o  もしも、一つ以上のCachingProviderが見つかったら、 getCacheManagerFactoryは、例外を投げる。

o  Cachingクラスはまた、このfactoryで生成された全てのCacheManagersの追跡をする。getCacheManager()を、再び呼び出した時には、同じ CacheManagerが返る。

Interface CachingProvider o  CacheManager factory プロバイダによって実装される

べきインターフェース。 CacheManagerを生成する為に、 Cachingクラスによって呼び出される。

o  このインターフェースの実装は、引数を持たないpublicなコンストラクタを持たなければならない。

o  CacheManagerFactory getCacheManagerFactory() Returns the singleton CacheManagerFactory.

o  boolean isSupported(OptionalFeature optionalFeature) Indicates whether a optional feature is supported by this implementation

キャッシュは、 CacheManagerの中にある

o  キャッシュは、キャッシュ・クラスタとの統合のようなCacheManager の機能を必要とすることがあるので、CacheManagerの外部で起動されてはならない。 キャッシュは、まず最初に、追加されねばならない。

o  それらが設定ファイルにあれば、CacheManagerは、起動時に、自動的に追加を行う。動作中のCacheManager に、プログラムを通じてキャッシュを追加することも可能である。

Chapter 5 - Transactions

Transactions

o  トランザクションは、この仕様のオプショナルな要件である。トランザクションは、JTA仕様で提供された意味を持つ。もし、実装されれば、トランザクションはここで規定されたように動作する必要がある。

o  2つのトランザクション・モデルがサポートされている。 1.  グローバル・トランザクション:XAトランザクションとし

て知られているもの 2.  ローカル・トランザクション:トランザクション境界は、

CacheManager

o  トランザクションを提供する動機は、キャッシュにとってデータベース、メッセージキュー、その他のXAリソースと強い整合性を保ち続けることが、しばしば、非常に重要になるからである。

o  トランザクションのサポート無しには、キャッシュのエントリーは、これらと整合的であるという保証は出来なくなる。

o  あるキャッシュは、ローカルキャッシュか、XAトランザクションの一つをサポート出来るが、その両方を同時にはサポート出来ない。

XA Transactions

o キャッシュのXAトランザクションは、JTAの仕様と選択された隔離レベルに基づいて機能する。

o XAトランザクションは、 Transaction Managerの存在を必要とする。

o あるXAトランザクションのコンテキスト外のXAキャッシュを操作しようと試みると、CacheExceptionが引き起こされる。

トランザクション・サンプル

//Get a global transaction assuming in a // Java EE app server UserTransaction utxg = jndiContext.lookup(“java:comp/UserTransaction”); // start the transactions utxg.begin(); // do work cache1.put(“key1”, “value”); cache2.remove(“key3”); cache3.put(“key5”, “value4”); // commit the transactions utxg.commit();

Enlistment o  Enlistmentとは、トランザクション・マネージャが、あるX

Aリソースがあるトランザクションに参加しようとしていると、それによって告げられるプロセスである。

o  javax.transaction.xa パッケージは、トランザクション・マネージャとリソース・マネージャとの契約を定義している。それは、トランザクション・マネージャが、JTAトランザクションにおいて、(リソース・マネージャ・ドライバーによって与えられる)リソース・オブジェクトのリストへの登録とリストからの削除を可能にする。

o  Enlistmentsは、 TransactionManager.getTransaction().enlistResource(XAResource xaRes)を用いることで終了する。

o  TransactionManagerへの参照が獲得される方法は、JTAの仕様では定義されていない。Java EEアプリケーション・サーバは、典型的には、参照を取得する為に、ベンダー固有の、よく知られているJNDIパスを利用している。

o  XAリソースの最初のオペレーションでは、TransactionManagerによって、start() が呼ばれる。

o  XAは、コネクション指向である。 キャッシュは、コネクションを信じてはいない。これらは、インピーダンス・ミスマッチを生み出す。

o  我々がコネクションを閉じることは無いので、XAResource.end()が呼びだされることはない。

o  我々は、two-phaseコミット・プロトコルがはじまる前にトランザクション・マネージャが、我々の為にend()を呼び出すことを期待する。(こうしたことは、JTAの仕様では、全く規定されていないとしても) これが、ほとんど全てのTransactionManagersの振る舞いである。

o  JTAの仕様は次のことを要求している。 「同一のリソースを使って、複数のトランザクション・コンテキストをインターリーブすることは、それぞれのトランザクション・コンテキスト・スイッチに対してXAResource.start と XAResource.endが適切に呼び出される限りで、トランザクション・マネージャによって可能となるだろう。リソースが異なるトランザクションで利用されるたびごとに、このリソースが関連づけられていた以前のトランザクションに対して、必ず、XAResource.endメソッドが呼び出され、現在のトランザクション・コンテキストに対して、必ず、XAResource.startが呼び出されなければならない。」

o  もしXAResourceがCacheManagerのレベルにあったとすると、我々は、endを呼び出さないのだから、このことは、CacheManagerをまたいでは、同時には、一つのトランザクションのみが実行可能であることを意味する。これが、可能な実装である。

o  それぞれのトランザクションごとに、ある新しいXAResource が生成されて、一つのキャッシュ・マネージャが、トランザクションがあるたびに、沢山のXAResourceをオープンすることが、示唆される。このようにして、並列トランザクションがサポートされる。インターリービングの問題は、回避される。

o  可能な別の実装は、キャッシュの操作のたびごとに、XAResourceを生成することである。これは、高い並列性を実現するが、より多くの、高価なenlistResource()メソッドの呼び出しを要求する。

Recovery

o  Cachesは、JTAで定義されている、リカバリー・プロトコルを実装しなければならない。特に、 XAResource.recover()は、必ず、サポートしなければならない。

o  永続するストアを持たず、新しいプロセスが空のキャッシュで再起動されるような、ローカルなプロセス中のキャッシュの場合には、recover()が、javax.transaction.xa.Xid[]の空な配列を返すことが認められる。

o  トランザクション・マネージャは、この場合には、Heuristic Exceptionを報告するかもしれない。

o  このことは、待機中のトランザクションが、他のXAResourcesに対して、正しくリカバーされることを妨げはしないだろう。さらに、ローカル・キャッシュは、読み出しのいかなる試みに対しても空なので、影響される値はキャッシュ・ミスとなり、この値に対するユーザのロジックは、影響を受けない。

Local Transactions

o  トランザクションをサポートするキャッシュは、4つの隔離レベルを持つローカル・トランザクションをサポートするだろう。

o  ローカル・トランザクションは、トランザクション・マネージャの存在を要求しない。

o  ローカル・トランザクションは、分散であれローカルであれ、同一のキャッシュ・マネージャ内の、一つ以上のキャッシュに対する複数のキャッシュ操作をまたいだ、シングル・フェーズのコミットを可能とする。

o  このことは、CacheManagerに対する複数の変更を、全て、単一のトランザクションで適用させることになる。

o  もし、データベースのような他のリソースに対して変更を適用することも望むなら、それらに対するトランザクションを開いて、整合性を保証する為に、手動でコミットとロールバックを取り扱う必要がある。(あるいは、XA Transactionsを使用する)

o  例えば、キャッシュAに対して2つのputを行い、キャッシュBに対して一つのremoveを行い、キャッシュCに対して4つのputを行うとする。これらは、全て、単一のローカル・トランザクションの中に納められる。

o  JTA APIは、ローカル・トランザクションのコントロールに使用される。

o  javax.transaction.UserTransactionインターフェースは、アプリケーションにトランザクション境界をプログラムでコントロールする能力を与える。

//Get a transaction UserTransaction utx = cacheManager.getUserTransaction(); // start a transaction utx.begin(); // do work cache1.put(“key1”, “value”); cache2.remove(“key3”); // commit the work utx.commit();

o  全てのローカル・トランザクションに関しての、ベスト・プラクティスは、これらのステップを、try-catchブロックの中に置いて、もし、例外が投げられたら、rollback()を呼ぶことである。(詳細は、JTAの仕様を参照されたい)

o  ローカル・トランザクション・コンテキストの外部からキャッシュを操作する試みは、javax.cache.transaction.TransactionExceptionを引き起こすだろう。

o  単一のスレッドが、XAトランザクションとローカル・トランザクションを開始することは可能である。キャッシュ操作は、トランザクション・コンテキストが存在する故に、XAならびにローカルなトランザクション・キャッシュの双方に受け入れられる。しかしながら、トランザクションは分離している。

o  別のプログラム例(EJB言語で、bean managed)、cache1とcache2はローカル・トランザクションとして設定され、cache3はXAトランザクションとして設定されているは、それを示している。次のようになるだろう。

o  ただ、これは動くのだが、一つのトランザクションが成功し、他のが失敗することもあり得るので、特に、役に立つという訳でもない。

//Get a local transaction UserTransaction utxl = cacheManager.getUserTransaction(); //Get a global transaction assuming in a Java EE app server UserTransaction utxg = jndiContext.lookup(“java:comp/UserTransaction”); // start the transactions utxl.begin(); utxg.begin(); // do work cache1.put(“key1”, “value”); cache2.remove(“key3”); cache3.put(“key5”, “value4”); // commit the transactions utxl.commit(); utxg.commit();

o  ローカル・トランザクションは、すべてCacheExceptionのサブクラスである、自身の例外を持っている。

o  TransactionException n  一般的な例外

o  TransactionInterruptedException n  キャッシュがトランザクションの処理中に、Thread.interrupt()

が呼ばれた時 o  TransactionTimeoutException

n  トランザクションのタイムアウトが過ぎてから、キャッシュの操作、あるいは、コミットが呼ばれた場合。

Recovery

o  Recoveryは、XAトランザクションに関連している。 Tローカル・トランザクションでは、コミット以前にクラッシュした場合、変化は、隔離レベルにディペンドする。

Chapter 6 - Isolation Levels

Isolation Levels

o  キャッシュの隔離レベルは、生成時に設定され、そのキャッシュのライフサイクルを通じて、変更不能なままにとどまる。

  隔離レベルには、次の4つがある。 o  READ_COMMITTED o  READ_UNCOMMITTED o  REPEATABLE_READ o  SERIALIZABLEの

READ_COMMITTED

o  内容の変化は、COMMIT が呼ばれるまで、ローカル・キャッシュでも分散キャッシュでも、他のトランザクションには見えない。

o  その時まで、次のいずれかの実装が自由である。 n  古いコピーを返す n  コミット、あるいは、ロールバックが呼ばれるまでブロックする。

o  両方のアプローチとも、READ_COMMITTED 隔離レベルを満たす。

READ_UNCOMMITTED

o  キャッシュの変化は、ローカル・キャッシュでも分散キャッシュでも、実装上の伝搬の遅延に従いながら、トランザクションが利用されなかったように、ただちに他のトランザクションに見える。

o  commit時には、値の変化は観測されない。 o  rollback時には、値は、以前の値に戻される。これは、

もちろん、目に見える変化だ。 o  timeout時には、JTA の仕様は、ロールバックが呼ば

れると記述している。だから、timeoutでも、古い値に戻される。正確にいえば、いつrollbackが起きるかは、実装依存である。

SERIALIZABLE

o  内容の変化は、COMMIT が呼ばれるまで、ローカル・キャッシュでも分散キャッシュでも、他のトランザクションには見えない。

o  さらに、他のトランザクションによって起こされたキャッシュの変化は、そのトランザクションが完了するまで、見えない。

o  SERIALIZABLE隔離レベルは、 REPEATABLE_READの上に、Phantom readsからの、さらに進んだ保護を提供する。

o  An alternative is to exclusively write lock a collection of keys of interest before starting your transaction. We could use lockAll(Collection keys). This would create a ReadWrite lock. Other transactions would block until this transaction.

o  This behaviour could be achieved pessimistically with a ReadWrite lock over the entire cache or also achieved optimistically by triggering a RollbackException if any changes made to the keys used (for reads or writes) in this transaction have been made.

REPEATABLE_READ

o  Mutating changes are not visible to other transactions in a local cache or a distributed cache until COMMIT has been called.

o  Further no changes to the cache made by other transactions for keys once they have or written by this transaction are visible to this transaction until it completes.

o  This behaviour could be achieved pessimistically with a ReadWrite lock acquired over the keys as they are used or also achieved optimistically by triggering a RollbackException if any changes made to the keys used (for writes) in this transaction have been made.

Chapter 7 – Caching Annotations

Caching Annotations

o  この章では、Java Caching 1.0 仕様で定義された、アノテーションについて議論する。アノテーションは、この仕様のオプショナルな部分であり、独立したライブラリーとしても実装可能である。

o  アノテーション・クラスのJavaDocは、機能の詳細な記述として読まれるべきである。

Annotations Overview

o アノテーションとそのサポートクラスは、javax.cache.annotationパッケージにある。

Annotation Inheritance and Ordering

o  この仕様は、アノテーションの継承について、Java仕様のCommon Annotations の2,1節に従っている。

o  この仕様外のアノテーションに関する、インターセプターの実行の順序については定義されておらず、アノテーションをサポートする実装に委ねられている。

Multiple Annotations

o  一つのメソッドには、一つのメソッド・レベルのキャッシング・アノテーションのみが指定でき、パラメータでは、一つのパラメータ・レベルのアノテーションのみが指定出来る。

o  もし、一つ以上のアノテーションが、メソッドないしはパラメータに指定された場合には、アプリの初期化時、あるいは、メソッドの呼び出し時に、CacheAnnotationConfigurationException が投げられねばならない。

@CacheDefaults

o  @CacheDefaultsは、クラス内で利用されるキャッシングに関連した全てのアノテーションのデフォールトのプロパティの値を定義するのに用いられる、クラス・レベルのアノテーションである。

o  cacheName, cacheResolverFactory, cacheKeyGeneratorといったプロパティが指定される。ただし、全て、オプショナルである。

o  もし、@CacheDefaultsがクラスに指定されて、メソッド・レベルのキャッシング・アノテーションが存在しない場合、 @CacheDefaultsアノテーションは無視される。

o  次の例は、このクラスのキャッシュのデフォールトとして利用される、”cities”という名前のキャッシュを指定している。

o  getCityメソッドの、@CacheResultアノテーションは、実行時にこのキャッシュの名前を利用する。

@CacheDefaults(cacheName=”cities”) public class CitySource { @CacheResult public City getCity(int lat, int lon) { //... } }

package my.app; @CacheDefaults(cacheName="domainCache") public class DomainDao { @CacheResult public Domain getDomain(String domainId, int index) { ... } @CacheRemoveEntry public void deleteDomain(String domainId, int index) { ... } @CacheResult(cacheName="allDomains") public List<Domain> getAllDomains() { ... } }

@CacheResult o  @CacheResultは、メソッド・レベルのアノテーションで

ある。その返り値がキャッシュされることを、メソッドにマークする為に用いられる。この時、キーは、メソッド・パラメータから生成され、同一のパラメータでのその後の呼び出しでキャッシュは、このキーを返す。

o  @CacheKeyParam アノテーションは、キーの生成において、パラメータのサブセットを選択するのに利用されうる。

o  オプション 1.  cacheNullプロパティを通じて、返り値nullのキャッシュをコン

トロールする 2.  オプショナルなキャッシングと名前を持つキャッシュ自身の例外

の再発行。キャッシュ固有の例外の機能を含む。 3.  Cacheが呼ばれた時、オプションで、事前実行をスキップする。

アノテーションをつけられたメソッドが、常に実行され、返り値がキャッシュにおけれるべき時には役に立つ。

o  @CacheResult は、staticなメソッドに置かれた場合には、無視される。

package my.app; public class DomainDao { @CacheResult public Domain getDomain(String domainId, int index) { ... } }

package my.app; public class DomainDao { @CacheResult public Domain getDomain(@CacheKey String domainId, Monitor mon) { ... } }

@CachePut o  @CachePutは、メソッド・レベルのアノテーションで、そ

のメソッドの引数の一つがキャッシュに格納されるべきことをマークする。一つの引数は、それがキャッシュされるべきことを示す為に、@CacheValue アノテーションでマークされねばならない。

o  もし、@CacheValueアノテーションが指定されなければ、アプリの初期化時あるいはメソッドの呼び出し時に CacheAnnotationConfigurationExceptionが投げられねばならない。

o  @CacheKeyParam アノテーションは、キー生成時にパラメータのサブセットを選択するのに用いられるが、@CacheValueアノテーションのパラメータは、キー生成に含まれることは無い。

o  オプション 1.  cacheNullプロパティを通じて、返り値nullのキャッシュをコン

トロールする 2.  Cache.putの呼び出しが、このメソッドの実行以前、あるいは

実行後に起きるのかを指定する。 3.  呼び出しの後に、キャッシングが起きれば、アノテートされたメソ

ッドからの例外は、Cache.put呼び出しをキャンセル出来る。 o  @CachePutは、staticなメソッドに置かれた場合には

、無視される。

package my.app; public class DomainDao { @CachePut(cacheName="domainCache") public void updateDomain(String domainId, int index, @CacheValue Domain domain) { ... } }

@CachPutでアノテートされたメソッドが呼び出された時、CachKeyが生成され、指定されたキャッシュ上でCache.put(Object, Object)が呼び出され、@CacheValueでマークされた値を、キャッシュに格納する。 Null値は、デフォールトではキャッシュされるが、この振る舞いは、cacheNull()プロパティで、無効にできる。

@CacheRemoveEntry

o  @CacheRemoveEntryは、メソッド・レベルのアノテーションで、エントリー中のメソッドの呼び出しの結果が指定されたキャッシュで削除されることをマークする。

o  @CacheKeyParam アノテーションは、キーの生成において、パラメータのサブセットを選択するのに利用される。

o  オプション 1.  Cache.removeの呼び出しが、このメソッドの実行以前、あるい

は実行後に起きるのかを指定する。 2.  呼び出し後に削除が起きれば、アノテートされたメソッドによって

投げられた例外は、Cache.remove呼び出しをキャンセルできる。 o  @CacheRemoveEntryは、staticなメソッドに置かれ

た場合には、無視される。

package my.app; public class DomainDao { @CacheRemoveEntry(cacheName="domainCache") public void deleteDomain(String domainId, int index) { ... } }

@CacheRemoveAll o  @CacheRemoveAllは、メソッド・レベルのアノテーショ

ンで、メソッドの呼び出しの結果のエントリー全てが、指定されたキャッシュで削除されることをマークする。

o  オプション 1.  Cache.removeAllの呼び出しが、このメソッドの実行以前、あ

るいは実行後に起きるのかを指定する。 2.  呼び出し後に削除が起きれば、アノテートされたメソッドによっ

て投げられた例外は、Cache.removeAll呼び出しをキャンセルできる。

o  @CacheRemoveAllは、staticなメソッドに置かれた場合には、無視される。

package my.app; public class DomainDao { @CacheRemoveAll(cacheName="domainCache") public void deleteAllDomains() { ... } }

デフォールトの振る舞いでは、アノテートされたメソッドが呼び出された後に、Cache.removeAll()が呼ばれる。 この振る舞いは、afterInvocation() をfalseにすることで変更出来る。この場合、Cache.removeAll()は、アノテートされたメソッドが呼び出される前に呼ばれる。

@CacheKeyParam

o  @CacheKeyParamは、パラメータ・レベルのアノテーションで、パラメータがCacheKeyGeneratorを通じてCachKeyを生成するのに利用されることをマークする。

o  実行時、@CacheKeyParamでアノテートされたパラメータは、 CacheKeyInvocationContext.getKeyParameters() アレーの中に置かれる。.

o  @CacheResult, @CachePut, @CacheRemoveEntryと一緒に使うことは出来ない。

@CacheValue

o  @CacheValueは、パラメータ・レベルのアノテーションで、@CachePutでアノテートされたメソッドの、キャッシュされるべきパラメータをマークするのに用いられる。@CachePutでアノテートされたパラメータは、CacheKeyInvocationContext.getKeyParameters() アレーに含まれてはいけない。.

o  @CachePutと一緒に用いられる。

Cache Resolution

o  メソッド・レベルのアノテーションは、全て、CacheResolverFactory の仕様とキャッシュを決定する為に用いられるキャッシュの名前が、実行時に相互に作用することを可能にする。

Cache Name

o  もし、キャッシュの名前が、メソッド・レベルのアノテーションでも、@CacheDefaults アノテーションでも指定されていなければ、名前は、次のように生成される。

o  package.name.ClassName.methodName(package.ParameterType,package.ParameterType)

o  @CacheResultは、追加的に、 exceptionCacheNameプロパティを持っている。もし、この名前が指定されていなければ、デフォールトの例外キャッシュ名も例外キャッシュも利用されない。

CacheResolverFactory

o  指定されたCacheResolverFactoryは、 毎回のアノテートされたメソッドの呼び出しのたびに利用されるCacheResolverを決定する為に、アノテートされたメソッドについて、正確に、一回呼ばれねばならない。

o  アノテートされたメソッドが実行されると、以前に取得されたCacheResolverが、CacheInvocationContextに基づいて利用すべきキャッシュを決定する為に用いられる。

o  javax.cache.annotation.CacheResolverFactory がアノテーションと@CacheDefaultsで指定されると、デフォールトのCacheResolverFactory のロジックが利用される。

o  デフォールトの CacheResolverFactoryのルール: 1.  Caching.getCacheManager()を通じて、利用する

CacheManager を取得する。 2.  キャッシュの名前で、CacheManager.get(String)を呼ぶ。 3.  Cacheが返らなかったら、CacheManager.createCacheBuilder

を使って、キャッシュを生成する。 4.  見つかった/生成されたキャッシュをラップし、常にキャッシュを返

すCacheResolverを生成する。 o  もし、CacheResolverFactoryが例外を投げたら、そ

の例外は、CacheResolverFactoryの実行をトリガーしたアプリケーション・コードまで、伝搬されねばならない。

CacheResolver o  CacheResolverは、CacheResolver ファクトリーによ

って返えされる。このことは、それが返されるアノテートされた全てのメソッドの呼び出しのたびに、 呼び出され、この呼び出しに利用されるキャッシュを返す。

o  もし、CacheResolverが例外を投げたら、その例外は、CacheResolverの実行をトリガーしたアプリケーション・コードまで、伝搬されねばならない。

Key Generation

o  @CacheResult, @CachePut, @CacheRemoveEntryアノテーションは、全て、キャッシュ・キーが生成されることを要求する。これらのアノテーションの全ては、 CacheKeyGeneratorの実装の仕様に従う。

o  指定されたCacheKeyGeneratorは、アノテートされたメソッドの呼び出しのたびに、一回だけ呼ばれる。アノテートされたメソッドと現在の呼び出しの情報は、 CacheKeyInvocationContextによって与えられる。

o  開発者がキーで利用されるように指定した、メソッドのパラメータは、getKeyParameters() メソッドで返されるCacheInvocationParameterアレーに含まれる。カスタムのCacheKeyGenerator は、CacheKeyを生成する為に、それが利用可能ないかなる情報も利用出来る。

o  もしjavax.cache.annotation.CacheKeyGenerator と@CacheDefaultsがアノテーションに指定されれば、デフォールトのCacheKeyGeneratorが利用されねばならない。

o  デフォールトのCacheKeyGeneratorのルール: 1.  CacheKeyInvocationContext.getKeyParameters()で

返されたアレーから、CacheInvocationParameter.getValue() を使って、Object[]を生成する。

2.  Object[]をラップしたCacheKeyインスタンスを生成する。Arrays.deepHashCodeを使ってそのhashCodeを計算し、Arrays.deepEqualsを使って、他のキーとの比較を行う。

o  もし、CacheKeyGeneratorが例外を投げたら、その例外は、CacheKeyGeneratorの実行をトリガーしたアプリケーション・コードまで、伝搬されねばならない。

Annotation Support Classes

o  CacheMethodDetails n  キャッシング・アノテーションを持つメソッドについての、Static

な情報。実行時に、CacheResolverFactory によって、 CacheResolver を決定する為に利用される。

o  CacheInvocationContext n  キャッシング・アノテーションを持つメソッドの実行についての実

行時の情報。CacheResolver によって、利用すべきキャッシュを決定するのに利用される。CacheMethodDetails を継承した、全てのstaticな情報が利用可能である。

o  CacheKeyInvocationContext n  @CacheResult, @CachePut, @CacheRemoveEntryの

いずれかでアノテートされた、キー生成が行われるメソッドの実行に関する実行時の情報。CacheKeyGenerator によって、CacheKey を生成する為に利用される。CacheInvocationContext を継承した、全ての実行時あるいは、staticな情報が利用可能である。

o  CacheInvocationParameter n  メソッドの実行のパラメータについての実行時の情報。パラメ

ータ・アノテーション、その位置、型、値が含まれる。CacheInvocationContextとCacheKeyInvocationContextによって与えられる。

o  CacheKey n  CacheKeyGeneratorインターフェースによって生成される。

CacheKey は、アノテーションによって相互作用する全てのキャッシュのキーとして利用される。全てのCacheKey は、複製不可でかつserializable出なければならない。

Chapter 8 - Container and Provider Contracts for Deployment and Bootstrapping

Container and Provider Contracts for Deployment and Bootstrapping

o  Java SEの環境では、 CacheManagerFactory.getCacheManagerメソッドは、新しいCacheManagerの生成を要求することがある。その為に、 javax.cache.CacheManager.CacheManagerFactoryProvider インターフェースのインスタンスを位置づける。

o  Java SEの環境で走るキャッシュ・プロバイダーの実装は、JARファイルの仕様で記述されたサービス・プロバイダの設定ファイルを備えた、サービス・プロバイダとしても動作すべきである。

o  プロバイダーの設定ファイルは、プロバイダの実装クラスを、そのプロバイダをキャッシュ・マネージャのファクトリーとして位置づけて、CacheManagerFactory ブートストラップ・クラスに、エキスポートする役割をはたす。

o  The provider supplies the provider configuration file by creating a text file named javax.cache.spi.CacheManagerFactoryProvider and placing it in the META-INF/services directory of one of its JAR files. The contents of the file should be the name of the provider implementation class of the javax.cache.CacheManager.CacheManagerFactoryProvider interface.

o  Example: o  A persistence vendor called ACME caching

products ships a JAR called acme.jar that contains its cache provider implementation. The JAR includes the provider configuration file. acme.jar

META-INF/services/javax.cache.spi.CacheManagerFactoryProvider com/acme/cache/CacheManagerFactoryProvider.class ...

o  The contents of the META-INF/services/javax.cache.spi.CacheManagerFactoryProvider file is nothing more than the name of the implementation class: com.acme.cache.CacheManagerFactoryProvider

o  Cache provider jars may be installed or made available in the same ways as other service providers, e.g. as extensions or added to the application classpath according to the guidelines in the JAR File Specification.

o  If more than one provider jar is registered the first one found by java.util.ServiceLoader will be used. If no provider is found, CacheManagerFactory.getCacheManager will thow an IllegalStateException.

Use of Caching

o  The API provides a static means of accessing caching support through the class javax.class.Caching.

o  Examples include

// get the default cache manager CacheManager defaultCacheManager = Caching.getCacheManager(); // the default cache manager can also be fetched by name assert defaultCacheManager == Caching.getCacheManager(javax.cache.Caching.DEFAULT_CACHE_MANAGER_NAME); //Can get a non default named CacheManager CacheManager myCacheManager = Caching.getCacheManager("MyManager");

Chapter 9 - Glossary

o  CacheManager A container for caches, which holds references to them.

o  Cache A collection of related items. o  Caching Unit A logical grouping under the

control of a CacheManager o  Key A way of unambiguously identifying a

unique item in a Cache. o  Value The value stored in a Cache. Any Java

Object can be a value. o  CacheLoader A user-defined Class which is

used to load key/value pairs into a Cache on demand.

o  CacheWriter A user-defined Class which is used to write key/value pairs into a cache after a put operation.

o  Cache Store A place where cache data is kept. Caches may have multiple stores.

o  CacheEventListener A user-defined Class which listens to Cache events.

o  Eviction Policy Method by which elements are evicted from the cache. E.g. FIFO, LFU, …

Resin 4.0 jcache (distributed caching)

public class MyServlet extends GenericServlet { @Current Cache _cache; public void service(ServletRequest req, ServletResponse res) { PrintWriter out = res.getWriter(); String data = (String) _cache.get("my-data"); if (data != null) { out.println("cached data: " + data); } else { data = generateComplicatedData(); _cache.put("my-data", data); out.println("new data: " + data); } } }

http://www.facebook.com/note.php?note_id=58113794812

<web-app xmlns="http://caucho.com/ns/resin" xmlns:cluster="urn:java:com.caucho.cluster"> <cluster:ClusterCache name="comment-cache"/> </web-app>

Maven Snippet

<dependency> <groupId>javax.cache</groupId> <artifactId>cache-api</artifactId> <version>0.3</version> </dependency>

Creating a CacheManager CacheManager cacheManager = Caching.getCacheManager(); CacheManager cacheManager = Caching.getCacheManager(“app1”,       Thread.currentThread().getContextClassLoader()); CacheManager cacheManager = new RICacheManager(“app1”,       Thread.currentThread().getContextClassLoader()); String className = "javax.cache.implementation.RIServiceProvider"; Class<ServiceProvider> clazz       =(Class<ServiceProvider>)Class.forName(className); ServiceProvider provider = clazz.newInstance(); return provider.createCacheManager(Thread.currentThread(). getContextClassLoader(), "app1");

o  We expect implementations to have their own well-known configuration files which will be used to configure the CacheManager.

o  The name of the CacheManager can be used to distinguish the configuration file.

o  For ehcache, this will be the familiar ehcache.xml placed at the root of the classpath with a hyphenated prefix for the name of the CacheManager. So, the default CacheManager will simply be ehcache.xml and “myCacheManager” will be app1-ehcache.xml.

Creating a Cache cacheManager = getCacheManager(); CacheConfiguration cacheConfiguration =    cacheManager.createCacheConfiguration() cacheConfiguration.setReadThrough(true); Cache testCache =    cacheManager.createCacheBuilder(“testCache”)     .setCacheConfiguration(cacheConfiguration).build();

Getting a reference to a Cache

o  You get caches from the CacheManager. To get a cache called “testCache”:

Cache<Integer, Date> cache =     cacheManager.getCache(“testCache”);

Basic Cache Operations

o  To put to a cache: Cache<Integer, Date> cache =   cacheManager.getCache(cacheName); Date value1 = new Date(); Integer key = 1; cache.put(key, value1); o  To get from a cache: Cache<Integer, Date> cache = cacheManager.getCache(cacheName); Date value2 = cache.get(key);

o  To remove from a cache:

Cache<Integer, Date> cache = cacheManager.getCache(cacheName); Integer key = 1; cache.remove(key);

Annotations

o  The JSR107 annotations cover the most common cache operations including: n  @CacheResult – use the cache n  @CachePut – put into the cache n  @CacheRemoveEntry – remove a single entry from

the cache n  @CacheRemoveAll – remove all entries from the

cache

public class DomainDao { @CachePut(cacheName="domainCache") public void updateDomain(String domainId, @CacheKeyParam int index, @CacheValue Domain domain) { ... } }

Annotation Example

public class BlogManager { @CacheResult(cacheName="blogManager") public Blog getBlogEntry(String title) {...} @CacheRemoveEntry(cacheName="blogManager") public void removeBlogEntry(String title) {...} @CacheRemoveAll(cacheName="blogManager") public void removeAllBlogs() {...} @CachePut(cacheName=”blogManager”) public void createEntry(@CacheKeyParam String title, @CacheValue Blog blog) {...} @CacheResult(cacheName="blogManager") public Blog getEntryCached(String randomArg, @CacheKeyParam String title){...} }

Wiring Up Spring

<jcache-spring:annotation-driven proxy-target-class="true"/> A full example is: <beans ...> <context:annotation-config/> <jcache-spring:annotation-driven proxy-target-class="true"/> <bean id="cacheManager" factory-method="getCacheManager" /> </beans>

Wiring Up CDI o  First create an implementation of

javax.cache.annotation.BeanProvider and then tell CDI where to find it declaring a resource named javax.cache.annotation.BeanProvider in the classpath at /META-INF/services/.

o  For an example using the Weld implementation of CDI, see the CdiBeanProvider in our CDI test harness.

Resin 4.0 jcache (distributed caching)

public class MyServlet extends GenericServlet { @Current Cache _cache; public void service(ServletRequest req, ServletResponse res) { PrintWriter out = res.getWriter(); String data = (String) _cache.get("my-data"); if (data != null) { out.println("cached data: " + data); } else { data = generateComplicatedData(); _cache.put("my-data", data); out.println("new data: " + data); } } }

configuration

<web-app xmlns="http://caucho.com/ns/resin" xmlns:cluster="urn:java:com.caucho.cluster"> <cluster:ClusterCache name="comment-cache"/> </web-app>

Recommended