2013年12月20日金曜日

キャッシュ層と永続化層、Oracle Coherence と Riak の連携(概要編)

前のブログが Riak Source Code Reading の記事だったのですが、気がつけば Basho に入社してました。

この記事はみんなでやる Riak Advent Calendar 2013 の 20日目の記事です。

今回は Riak と外部プロダクトの連携を考えてみます。
時間がなかったので、詳細はまた別途書きます。

Oracle Coherenceとの連携

Oracle Coherenceは 分散キャッシュ製品(オラクルの言い方だと分散データグリッド)です。キャッシュなので、一般的にRDBなどの前段に置いて、高速化目的で使われます。Coherenceは分散キャッシュであるためスケールアウトもできます。アプリの性能要件に対応しCoherenceを使って高速化。これはよくあるシナリオなのです。

ここで、OLTP系のシステムなどデータの更新が多いシステムの場合を考えてみましょう。Coherenceはさばいた更新量を、その下の永続化層であるDBがさばききれない可能性がありますね。もちろん本来ならここで、RDBのチューニングやら、Coherenceの永続化周りのオブジェクト設計をしっかり考えるのですが、ここで第3の選択肢を考えてみましょう。

今回はRiakのアドベントカレンダーなのでRiakを使ってみます。CoherenceもKVS、RiakもKVS、つまりCoherenceに格納されたデータを "そのまま" の形式でRiakに永続化できそうです。しかもRiakはスケールアウトが容易ですので、Coherenceの更新量に負けないだけのRiakサーバーを用意すればOKです。CoherenceとRiakは実は相性が良いのです。(Oracle RAC もスケールアウトするし!とか野暮な突っ込みは勘弁してください。)


というわけで試してみました。


Oracle Coherence の内部形式のままRiakに保存する

Coherenceのキャッシュにデータを格納する際、データすなわちKeyとValueはシリアライズされて格納されます。CoherenceではPOFと呼ばれるCoherenceが提供する方式でのシリアライズを推奨しています。アプリからCoherenceに格納する際はシリアライズして転送&格納、データを取り出す際は取り出したあとにデシリアライズといった具合になります。
本来CoherenceからRDBに永続化する際は、永続化のタイミングでもデシリアライズが必要です。しかしRiakに格納する場合はどうでしょうか?RiakはKeyとValueをバイナリで格納します。つまりデシリアライズなんて必要ないのです。Coherenceが使う内部形式であるPOFのままRiakに書き込むことが可能です。これはCoherenecで通常用いるCacheStoreではなく、BinaryEntryStoreと呼ばれるものを使えば実現できます。(なお、厳密な意味でCoherenceの内部形式はPOFをさらにラップした形式なのですが、ここでは内部形式=POFと表現しておきます。)


試しに作ったもの

というわけでさくっと作ってみました。
当然各製品はそれぞれ必要です。
・Oracle Coherence 12c 
・Riak 1.4.2 

さて、Riak側はデフォルトの設定のまま起動してもらっても構いません。そしてCoherenceですが、今回のサンプルアプリを作るのに用意したファイルはたったの3つ。
・Coherenceの設定ファイル(coherence-cache-config.xml
・CoherenceのデータをRiakに格納する処理(RiakCacheStore.java
・Coherenceにデータを読み書きするただのサンプル(TestClient.java


実行してみた

RiakとCoherenceを起動した後、サンプルアプリである、TestClientを実行してみます。 このアプリは、最初に50件データをputした後、Coherenceのキャッシュを一度クリアーします。その後最初に格納したデータと同じKeyでgetを行います。

TestClient.main() - put data to the TestCache
TestClient.main() - Clear TestCache
TestClient.main() - Get key=Testkey0, value=value0
TestClient.main() - Get key=Testkey1, value=value1
TestClient.main() - Get key=Testkey2, value=value2
・・・略
TestClient.main() - Get key=Testkey45, value=value45
TestClient.main() - Get key=Testkey46, value=value46
TestClient.main() - Get key=Testkey47, value=value47
TestClient.main() - Get key=Testkey48, value=value48
TestClient.main() - Get key=Testkey49, value=value49

裏では、Coherenceのputの際、CoherenceのBinaryEntryStoreを通じて、Riakにputが実行されています。またcacheをクリアーした後のgetでは、Coherence上でcache missした場合、やはりCoherenceのBinaryEntryStoreを通じて、Riakからのfetchが実行されています。


CoherenceでReadWriteBackingMapと呼ばれるキャッシュ設定を使った場合、Coherenceのputに対応してstoreメソッドが、get時cache missに対応してloadメソッドが実行されます。実質以下のコードが今回の全てです。
 public void load(BinaryEntry bEntry) {
  String riakKey = new String(bEntry.getBinaryKey().toByteArray());
  System.out.println("RiakCacheStore.load() - from Riak to Coherence [key=" + riakKey +"]");
  try {
   IRiakObject myData = myBucket.fetch(riakKey).execute();
   bEntry.updateBinaryValue(new Binary(myData.getValue()));
  } catch (RiakException e) {
   throw ensureRuntimeException(e);
  }
 }
 
 public void store(BinaryEntry bEntry){
  String riakKey = new String(bEntry.getBinaryKey().toByteArray());
  System.out.println("RiakCacheStore.store() - from Coherence to Riak [key=" + riakKey +"]");
  try {
   myBucket.store(riakKey, bEntry.getBinaryValue().toByteArray()).execute();
  } catch (RiakException e) {
   throw ensureRuntimeException(e);
  }
 }
ほら簡単ですよね。 今回は時間が無いのでこの辺りで。かなり端折って書いたので、次回は、CoherenceとRiakの説明を交えつつ詳細に書きたいと思います。

0 件のコメント:

コメントを投稿