X

An Oracle blog about Oracle Coherence

Spring Batchを用いた高パフォーマンス・データ・ローディング

筆者: Vijay Nair、原文はこちら

Spring Batchフレームワークと、データ・ロードのためのマルチスレッド化されたアプローチとの組合せによって、Coherenceベース・アプリケーションの管理性とパフォーマンスの向上を実現する方法

2011年12月公開

ますます多くの企業が大規模データ・セットに対応したインメモリ処理のメリットを追及するようになり、インメモリ処理を促進する製品への関心は急速に高まっています。 Oracle Coherenceは、シンプルなインタフェース、汎用プラットフォームに対する幅広いサポート(例: C++、Net、Hibernate、JPA)、およびわずかな構成の工夫でテラバイト級のデータに対応できるスケーラビリティによって、この領域にある多くの類似製品の中でもっとも優れた製品となっています。

さらに、企業環境内でのデータ・グリッド・キャッシュの重要性が増しているため、以下の条件を確保することが必須となっています。

  • 任意のソース(例:フラット・ファイル/データベース)からのデータをキャッシュにロードするための時間を、最小限にする必要があります
  • キャッシュへのデータ・ロードが、許容できる品質と信頼性で実行される必要があります
  • 適切な部署への通知を行う機能など、的確なエラー処理メカニズムを導入する必要があります
  • キャッシュのデータ・ロードに関するレポートを作成する機能が利用できる必要があります

データ・ロード・プロセスに関するこれらの条件を確保することで、データ・グリッド・キャッシュにおけるデータの信頼性が保証されます。 SpringSourceのポートフォリオを元にしたオープンソース・プロジェクトであるSpring Batchは、大規模データの処理に必要な上記の特性を持ったインフラストラクチャを提供するJavaバッチ処理フレームワークの一つです。

この記事では、Spring Batchを使用して、Oracle CoherenceキャッシュにCSVファイルをロードする方法について説明します。 説明を簡潔にするために、ここでは、Oracle Coherence 3.7.1用の配布サンプル・ファイルに含まれているcontacts.csvファイルに変更を加えて再利用しています(レコードを99,990件まで追加)。

なお、この記事は、Oracle Coherence、Spring Framework、Spring Batchについて中級レベルの知識を持つ読者を対象としています。

プロジェクトの設定

ここでは、Oracle Enterprise Pack for Eclipseを使用します。このOracle Enterprise Pack for Eclipseは、Oracle Fusion Middlewareテクノロジー(この例ではOracle Coherence)を使用してアプリケーションを実行およびデバッグする場合に必要となるプラグインの包括的なセットを、オラクルのIDEとして提供します。 また、Oracle Enterprise Pack for Eclipseは、Springをサポートする包括的なツールも提供します。したがって、Oracle Enterprise Pack for Eclipseは、私のように両方のテクノロジーを連携させる開発者にとって不可欠なものとなっています。

最初に、以下のフォルダ構造とファイル(サンプルをこちらからダウンロード)を使用して、Oracle Enterprise Pack for Eclipseで新規のSpringプロジェクトを作成します。 また、Spring Frameworkのコアjarファイル(ファイルの依存関係を含む)、Spring Batchのjarファイル、およびOracle Coherence jarファイル(<<COHERENCE_HOME>>/libの下にあります)をすべて追加する必要もあります。 Oracle Coherenceで提供されているサンプル・モデルの使用に加えて、Oracle Coherenceで提供されているexamples.zipファイルにあるすべてのJavaファイルをコンパイルし、jarファイル(例: examples.jar)としてエクスポートする必要があります。

nair-coherence-f1

図1:
新規のSpringプロジェクト

変更を加えたcontacts.csvファイルには、連絡先情報が格納されています。 このファイルの各行は、キーとなるContactldオブジェクトおよび値となるContactオブジェクトとともに、マップとしてキャッシュにロードされます。 Contactオブジェクトには、以下のものが含まれています。

  • 名の文字列表現
  • 姓の文字列表現
  • 2つの"アドレス"オブジェクト(HomeとWork)
  • "PhoneNumber"オブジェクトで表される2つの電話番号を含むマップ

ContactIdオブジェクトには、以下のものが含まれています。

  • 名の文字列表現
  • 姓の文字列表現

名と姓の組合せは、マップのキーとして、すべてのレコードに対して一意になるようにする必要があります。 サンプル・データの一部を、次に示します。

John,Loehe,1968-01-01,675 Beacon St.,,Dthaba,SC,91666,US,Yoyodyne Propulsion Systems,330 Lectroid Rd.,Grover's Mill,NM,41888,US,home,11,74,286,6864191,work,11,45,362,5379579,
John,Vadrypkwiy,1978-12-29,62 Beacon St.,,Zxnmgcw,OR,18083,US,Yoyodyne Propulsion Systems,330 Lectroid Rd.,Grover's Mill,DC,81140,US,home,11,82,98,4330491,work,11,56,422,7695959,

Spring Batchの使用

Spring Batchは、項目の読み込み(リーダー、ItemReader)と項目の書き込み(ライター、ItemWriter)の概念に基づいています。 また、Spring Batchは、ファイル内にある各行のデータをモデル・ファイルにマッピングするカスタム・マッパー・クラスを作成する機能も提供します。 少し興味深い例とするために、シングルスレッドでのデータ・ロードの実行とマルチスレッドでのデータ・ロードの実行の比較について説明しましょう。

最初に、batchCoherenceという名前のジョブを定義します。このジョブには、Spring Batchによって提供されるリーダーのFlatFileItemReader、カスタム・マッパー(CoherenceSampleMapper.java)、およびカスタム・ライター(CoherenceBatchWriter.java)を使用するステップが含まれます。

nair-coherence-f2

図2:
batchCoherenceJob

"チャンク"のコミット間隔は、1,000に設定します。つまり、リーダーを1,000回起動して、1,000個の項目をリストに移入するようにします。 このチャンクの間に、ライターは1回だけ起動されます。これによって、非常にスケーラブルなアーキテクチャを実現しています。

リーダーに対しては、次のものを構成します。

  • ロードされるリソース(この事例ではcontacts.csv)
  • DelimitedLineTokenizer(デリミタとして","を使用)
  • 各行を目的のモデルに変換するカスタム・マッパーのFieldSetMapper(CoherenceSampleMapper.javaとして構成)

マッパーは、Spring Batchフレームワークによって提供されるFieldSetMapperを実装し、ファイルから読み取られたすべての行に対して起動されます。 その後、マッパーは、利用できるデータを、Spring Batchインフラストラクチャに戻されるContactモデルに変換します。

リーダーは、次のようになっています。

nair-coherence-f3

図3:
CoherenceSampleMapper.java

カスタム・ライターには、次の特徴があります。

  • Spring Batchフレームワークによって提供されるItemWriterインタフェースを実装、およびwrite()メソッドを実装するようにしています。 すでに説明したように、各チャンク処理の間にリーダーが1,000回起動され、モデルへのマッピングが実行されると、このモデルは項目のリストとしてライターで利用できるようになります。これによって、ライターは、リストに対してあらゆる種類の操作の実行を選択することが可能となります。この事例では、Coherenceキャッシュへの書込みを実行します。
  • Spring Batchフレームワークによって提供されるStepExecutionListenerインタフェースを実装、およびbeforeStep()メソッドとafterStep()メソッドを実装するようにしています。 その名前が示すように、これは、特定のイベントに基づいてメソッドをトリガーできるリスナー・クラスです。 そこで、この例では、beforeStep()メソッドで読取り/書込みを開始する前にCacheFactoryを開き、afterStep()メソッドでキャッシュへのプッシュが完了した後でCacheFactoryを正常に閉じるようにしています。
  • Spring Batchフレームワークによって提供されるChunkListenerインタフェースを実装、およびbeforeChunk()メソッドとafterChunk()メソッドを実装するようにしています。 これは、それぞれの"チャンク"の読取りまたは処理の前後に、特定のアクティビティを実行するのに役立ちます。 この事例では、キャッシュへのプッシュを実行するたびに、その後にマップ"mapBatch"を消去しています。

ライターは、次のようになっています。

nair-coherence-f4

図4: CoherenceBatchWriter.java

ご覧のように、Spring Batchは役割分担が非常に明確化された数多くの役に立つメソッドを提供しているため、コードを保守する際に役に立ちます。 さらに、これらのリスナー・メソッドのいずれかで、入力ファイルのロード中に障害が発生した場合、またはデータをキャッシュにプッシュしている最中に障害が発生した場合は、便利な通知/トリガー・メカニズムを実行できます(ただしこれは、この記事の対象範囲外ですが)。

マルチスレッド用サンプルの用意

次に、シングスレッドとマルチスレッドのアプローチを比較する準備をするために、batchCoherenceJobmtと言う名前の新規ジョブを定義します。このジョブには、シングルスレッドのサンプルと同じFlatFileItemReaderおよび同じカスタム・マッパー(CoherenceSampleMapper.java)を使用するステップが含まれます。 また、新しいカスタムのマルチスレッド・ライター(CoherenceMTBatchWriter.java)も用意します。

nair-coherence-f5

図5: batchCoherenceJobmt

今度は、Springが提供するタスク・エグゼキュータの実装である非同期タスク・エグゼキュータで実行するために、タスクレットを割り当て、スロットル制限を5に設定します(スレッド・リソースの再利用に役立つものであれば、Springのどのようなタスク・エグゼキュータ実装であっても割り当てることが可能)。

前述の手順と同じように、"チャンク"のコミット間隔は、1,000に設定します。つまり、リーダーを1,000回起動して、1,000個の項目をリストに移入するようにします。 ライターは、このチャンクの間に1回だけ起動されます。

リーダーとマッパーは、次のように、シングルスレッドのサンプルと同じように構成します。

nair-coherence-f6a

図6: CoherenceSampleMapper.java(マルチスレッド・バージョン)

nair-coherence-f7

図7:
CoherenceBatchWriter.java(マルチスレッド・バージョン)

ここでは、新しいMap<ContactId,Contact>を作成して、マルチスレッド実行の観点からwriteメソッド自体の中でこれを消去してスレッド・セーフにしました。

次は、テスト・フェーズへと進み、データ・ロードに関するシングルスレッドとマルチスレッドのアプローチを比較します。 すべてのテストは、インテルCore Duo CPU 2.4GHzと2GBのRAMを搭載したラップトップ上で実施しました。

実行: シングルスレッド

各ジョブの実行についての情報を格納するための、Spring Bacth のバッチ・リポジトリとしてOracle Databaseリポジトリを使用しています。つまり、通常のSpring Batchメタデータ表に関する場合と同じ必須要件が求められます(static.springsource.org/spring-batch/reference/html/metaDataSchema.htmlを参照)。 このサンプルでは、resourcesフォルダの下にあるjdbc.propertiesがテスト・データベースを指すように構成しました(実行の前に、クラスパスにojdbc.jarまたは適切なJDBCドライバを追加することが必要)。

最初に、<<COHERENCE_HOME>>/binの下にあるcach-server.cmdを使用して、通常のOracle Coherenceサーバーを起動します。

nair-coherence-f8

図8:
サーバーの起動

また、<<COHERENCE_HOME>>/binの下にあるcoherence.cmdを使用して別のCoherenceノードを起動し、次のように入力します。

Map <?>: cache CacheBatchTestNonMT

(シングルスレッドのシナリオで使用する名前付きキャッシュ)

これによって、名前付きキャッシュのプロンプトが表示されます。 sizeコマンドを使用したクイック・テストでは、次の図のように、この名前付きキャッシュが空であることが示されます。

nair-coherence-f9

図9:
サイズ・テストの実行

Eclipseに戻り、SpringのJUnitサポートを利用した簡単なテスト・ケース(OTNCoherenceBatchTest.java)を開きます。このテスト・ケースは、Springアプリケーション・コンテキストに必要なファイルをすべてロードするように記述されています。


nair-coherence-f10
図10: OTNCoherenceBatchTest.java


クラスを右クリックし、「Run as JUnit test」を選択します。 Eclipseコンソールで、既存のクラスタに接続し、キャッシュ・コネクション・ファクトリが取得されていることが、はっきりと確認できます。

nair-coherence-f11

図11:
JUnitテストの結果

メイン・サーバー(cache-server.cmdを使用して起動済み)では、転送されているデータを確認できます。

nair-coherence-f12

図12:
進行中のデータ転送

coherence.cmdを使用してCoherenceノードを起動し、sizeコマンドを入力すると、次のように、ファイルからロードされたデータがキャッシュに含まれていることが示されます。

">Map <CacheBatchTestNonMT): size
99990

バッチ・ステップ実行表への問合せによって、実行時間が53.297秒であることを確認しました。

次は、この結果を、マルチスレッドのアプローチにおける結果と比較します。

実行: マルチスレッド

前述と同じ手順を実行しますが、CacheBatchTestMT-2と呼ばれる新しい名前付きキャッシュを使用する点が異なります。

このテストのために作成された別のJUnitテスト・ケース(OTNCoherenceBatchMTTest.java)を実行して、次のようにサイズを確認します。

Map <CacheBatchTestMT-2>: size
99990


バッチ・ステップ実行表への問合せによって、実行時間が28.218秒であることを確認しました。この結果は、シングルスレッドのアプローチよりも実行時間がおおよそ45%短縮されていることを示しています。

結論

Oracle Coherenceは、バッチ処理にとっての必須条件であるインメモリ・データ・グリッドへの高速アクセスを実現することによって、世界中の金融機関でバッチ・ワークロードにおけるパフォーマンス向上に役立っています。 しかし、Oracle Coherenceのデータ・グリッドのサイズが大きくなると、パフォーマンスを維持する上で、データのロードおよびアクセスに必要な時間の最小化が極めて重要となってきます。 上記の結果から分かるように、マルチスレッドのアプローチは、ロードとアクセスの両面で、シングルスレッドのアプローチと比較してパフォーマンスがはるかに優れています。 Spring Batchインフラストラクチャを使用することで、このアプローチの構成を宣言的な方法で極めて簡単に実行できます(例: Springタスク・エグゼキュータの使用)。



Vijay Nair
は、オラクルのFinancial Services Global Business Unitで、テクニカル・アーキテクトとしてOracle FLEXCUBE Private Bankingを担当しています。 おもに、スケーラブル・コンピューティング関連、およびプライベート・バンキングの分野でこれらの原理を実践的なシナリオに適用するための作業に精力的に取り組んでいます。

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.