レベル: 中級 Jonathan Marshall (marshalj@uk.ibm.com), Senior IT Specialist, Federated Integration Test team, IBM China Development Lab
2006年 5月 22日 この記事は、グリッド・コンピューティングとデータ処理により優れたパフォーマンスを実現可能にするために、WebSphere Extended DeploymentのコンポーネントであるObject Gridによるインフラの作成手順を紹介します。
当記事はDeveloperWorks記事の翻訳です。原典「Highly scalable grid-style computing and data processing with the ObjectGrid component of WebSphere Extended Deployment」はこちらから参照可能です。
はじめに
XDのObjectGridコンポーネントは一般的に分散キャッシュ技術として考えられており、その技術によってキャッシュ分割を利用したスケーラビリティ、パーティショニング・レプリカによる自動修復、トランザクション処理およびセキュリティーといったサービス品質(qualities of service - QoS)の向上を実現します。また、QoSによって提供されたインフラは、グリッド・コンピューティングやデータ処理といった優れたパフォーマンスも提供するプラットフォームとなります。
仮に大きなサイズのデータを保管する必要があると仮定します。その場合、非常に大規模なデータセットを可能とするスケーラビリティと自動修復のために、多くのJVMに渡ってデータを分散させることが考えられます。ObjectGridでは、ハッシュアルゴリズムを利用してデータを複数のJVMに分割することにデータを分散させることができます。大規模データを使用する場合に処理性能には、計算処理ではなく、むしろデータ処理するためのデータ移動(シリアライズ)処理が一番影響するようになります。さらに、単なる必要なデータの結果を得るようなデータ検索にもパフォーマンスに多くの影響を与えます。これはアプリケーションとデータとの連携の問題となりますが、並列処理にすることで劇的にパフォーマンスを得ることができます。それこそ、まさしくDataGridのAPIを提供しているObjectGridを利用することで実施可能となります。
この記事では、データのインメモリー・グリッドの設定方法、および複数グリッド環境にわたる分散・並列処理の手法による計算とデータ処理の実行方法を紹介します。これを実践することにより、データを保管・検索するための単純なmap APIとEntityManager APIについても学ぶことができます。(EntityManager APIの概要とメリットについて紹介しますが、ここでは詳細については省略いたします。)
この記事は、基礎的なObjectGridの知識と分散環境における簡単なアプリケーション作成方法を理解していることを前提とします。Resourceに、基礎的なObjectGridの紹介がありますのでご参照ください。
ObjectGridは、XDのData Gridコンポーネントの一部として購入できます。ObjectGridは、WebSphere Application ServerやXDと連携して使用することができ、また他のjavaアプリケーションサーバーやスタンドアローンのjavaでも使用することができます。
この記事の手順を実施する上で、以下が必要となります。
- WebSphere Extended Deployment Data Grid V6.1(trial版がResourceにあります)
- JVM at JDK 1.4.2 or higher; この記事ではJava SDK 1.5.0を利用しております。
サンプルシナリオ
この課題のために、私たちの気持ちに近いテーマということで給料と昇給についてのサンプルのテーマを見てみましょう。例として、あなたはある会社の従業員の給料を分析し、平均の給料を算出する仕事をしているとします。もし会社の業績がよければ、すべての社員に対して昇給可能にしたいと考えるでしょう。最後に、会社の従業員の情報を保管するレポジトリーを作成するでしょう。
あなたが、各従業員の情報を含んだ多くの従業員のオブジェクトをObjectGridで作成するとします。その場合、メモリに保持するデータは一つのJVMでは多すぎるサイズになり、それがまさに分散グリッド環境でセットアップすることで、多くのJVMでデータが分散されることになります。図1.で示します。
図1. Overview of Employee ObjectGrid
クライアントからこのデータのすべてにアクセスし何かしらの変更処理を実施しようとすると、ネットワーク帯域やシリアライズといった処理という点でとてもコストのかかる処理となります。ObjectGridを利用することで、その処理をグリッド化された各々のパーティションでエージェントが実施するため、パーティションごとでは小さな処理で実施することが可能となります。エージェントはデータを直接操作するおかげで、シリアライズやデータ転送のコストすべてを削除し、並列処理の利益を得ることができます。
この課題で、2つのエージェントの作成方法を紹介します。
- 計算の実行(平均値の計算)
- データすべての更新の実行(パーセンテージにより、各給料を増やす)
図1では、ObjectGridで提供されている部分は紫色、今からこの課題を通して作成する部分を白色で表しています。
- Data: Employee Java objectは、下に記載します。
- Agents: 実際に処理を実施するコード
- Client code: Agentを制御するため、Agent Manager APIを利用します
最後に、リスト1にEmployee Java objectを記載します。ObjectGridに保管情報として4つのフィールドがあり、付け加えてどのようにフィールドを使用するかアノテーションで記載しています。例えば、@IdはEmployee objectのkeyフィールドを示します。
リスト1. Employee object
@Entity
public class Employee {
@Id String ssn;
String firstName;
String surname;
int salary;
}
|
EntityManager APIを使用したグリッドの作成・データアクセスの実行
このセクションでは、分散ObjectGridの作成方法・EntityManager API.を利用してグリッドからEmployee objectを保管、読み込みの実施方法を紹介します。
A)ObjectGridの作成
-
ObjectGridについて
まず、使用するためのObjectGridを作成します。リスト2で定義ファイルを示します。それは、オブジェクトをどこに保管するか指定したBacking Mapを定義するのと同様にシンプルです。定義ファイルは、以下の2つを記載しています。
- 保管されるJava object(本記事ではEmployee object)
- Java objectの属性を記載したエンティティ・メタデータ記述ファイル
Descriptorは、さまざまなトランザクションやアクセス、プラグインの設定を記載しています
リスト2. ObjectGrid definition XML file
<?xml version="1.0" encoding="UTF-8"?>
<objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
xmlns="http://ibm.com/ws/objectgrid/config">
<objectGrids>
<objectGrid name="EmployeeStoreObjectGrid"
entityMetadataXMLFile="entity.xml">
<backingMap name="Employee"/>
</objectGrid>
</objectGrids>
</objectGridConfig>
|
-
Entity について
EntityManager APIを利用して、ObjectGrid内のEmployee Objectを保管や検索します。EntityManager APIによって、自身でソースにオブジェクトの保管・検索のコードを書くことなく、その方法が提供されています。以前は、Java MapからObjectをputやgetするためにコードを書く必要がありましたが、これはすべて管理され、開発者は保管する必要のあるJava Objectを単純に記載すればよくなりました。これらの記載は、コードでアノテーションやXML定義ファイル(entity schema descriptor)を使用して記述することができます。
-
アノテーションを使う場合
Employee Object(リスト1)は、シンプルな2つのアノテーションのみを使用します。
- @Entity: そのJava Objectが、Entityであることを明示します
- @Id: そのJava変数がプライマリーkeyであることを明示します
他にアノテーションではオブジェクトとの関係や振る舞いを記載します。
-
entity schema descriptorを使う場合
もし単にローカルのObjectGridを使用する(すなわち同じプロセス内でObjectGridを使用する場合)のであれば、entity schema descriptorを使う必要はなく、アノテーションだけで十分です。プログラムの中で使用するEntityを登録することができます。しかし、分散環境ではどのEntityを期待するか定義しておく必要があります。Entityを登録することで、この記事ではObjectGrid 内でEmployee Objectを使用することを明示します。
リスト3は、必要最小限の情報を記載した単純なdescriptorを記載しています。以下の3つの情報を提供しています。
- Entity名
- Entityのクラス名
- SchemaRootとしてのEmployee Entity:複数のオブジェクトになる場合、Employee objectの親またはRoot Objectを明示する必要があります。
リスト3. Entity schema descriptor for the Employee object
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://ibm.com/ws/projector/config/emd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ibm.com/ws/projector/config/emd ./emd.xsd">
<entity class-name="com.ibm.websphere.samples.datagrid.Employee"
name="Employee" schemaRoot="true"/>
</entity-mappings>
|
Descriptor でも、プライマリーkey field やObject間のマッピングといったアノテーションと同様の情報を定義することができます。これによって、コードと定義を区別することが可能です、ただしこれは個々の設定項目についてとなります。
(分散環境ではそのグリッドがパーティションに格納するか決定するためにどのObjectがハッシュ化されたか知る必要がありますので、Schema Root属性は分散ObjectGrid環境では必須項目となります。複数関連するObjectを格納することを考える時、直感的に認識できます。ObjectGridは1フェーズコミットのみサポートするため、どの更新処理も単一のパーティションで実行されます。このため、単一のパーティションですべての関連するObjectを保管する必要があります。したがって、SchemaRootにはそのObject群のRoot Objectを指定します。)
-
デプロイする環境の記述について
今までの手順では、ObjectGridについてとどのObjectを保管するかについて述べました。次に、どのように実行して欲しいかを決定する必要があります。例:
- いくつのパーティションを必要とするか
- いくつのレプリカを必要とするか、それらは同期か非同期か
この記事では、フェールオーバーの機能は必要ありませんので、レプリカは作成しません。(しかし、簡単な構成変更でフェールオーバーの機能を確認できます)
ここのサンプルでは、5つのパーティションを定義します。(この値は、グリッドのそれぞれのパーティションで処理が実行されるのを確認するための幾分適当な値です。)
リスト4. ObjectGrid deployment policy file
<?xml version="1.0" encoding="UTF-8"?>
<deploymentPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ibm.com/ws/objectgrid/deploymentPolicy
../deploymentPolicy.xsd"
xmlns="http://ibm.com/ws/objectgrid/deploymentPolicy">
<objectgridDeployment objectgridName="EmployeeStoreObjectGrid">
<mapSet name="EMPLOYEE_MAPSET" numberOfPartitions="5"
minSyncReplicas="0" maxSyncReplicas="0" maxAsyncReplicas="0>
<map ref="Employee" />
</mapSet>
</objectgridDeployment>
</deploymentPolicy>
|
Deployment Policyは、とても直感的です。概要として:mapsetでは、クラスタリングやレプリカの基準の標準設定を含んだmapグループについて定義します。このシナリオでは、1つのmapsetに1つのmapのみを定義しています。
(実際には、パーティションの数は考えて設計するべきです。どのくらいデータが必要か、データを保管するために何台のサーバーが必要かを考える必要があります。パーティションの数は少なくともトータルのサーバー台数と同じにするべきで、おおよそ2か3倍程度に抑えるべきです。この値は、フェールオーバーや新しいキャパシティーの追加の時に、パーティションを分散させる柔軟性に大きく影響します。)
図2. Fully configured ObjectGrid
図2で表示している部分までObjectGridの構成は終了しました。以下の項目が定義されています。
- ObjectGrid名の構成
- ObjectGridに保管されるEntityの記述
- ObjectGridで使用されるパーティション数の構成
今から、データをグリッドに配置しその中で計算を実施する準備を始めます。
B)EntityManager APIによりグリッドの配置
ObjectGridを使う前に、一般的にカタログサーバーのbootstrapアドレスを使用してObjectGridに接続する必要があります。そして、クライアントアプリーションで一連の更新や検索を実施することができます。
-
EntityManager APIを利用したデータの追加
まずは、EntityManager APIの主なコンセプトについて紹介します。リスト5にあるように、これは基本的に以下の5つのステップで構成されます。
- ObjectGrid sessionを取得します
- sessionから、EntityManagerを取得します
- EntityManager内で、トランザクションを開始します
- Java Entityを作成し(この手順では単一のEmployee object)、EntityManagerに追加(persist)します
- Java Objectを作成・編集し終わったら、トランザクションをコミットします
リスト5. Using the EntityManager API to store data
Session session = objectGrid.getSession();
EntityManager em = session.getEntityManager();
em.getTransaction().begin();
Employee e = new Employee();
e.firstName = "Jonathan";
e.surname = "Marshall";
e.ssn = "1234";
e.salary = 100000;
em.persist(e);
em.getTransaction().commit();
|
EntityManager APIのメリットの1つは、ObjectGridに対して一度persistすると、そのトランザクションのスコープでどんなに変更があってもトランザクションの終了時にObjectGridが自動で更新される事です。
この記事で提供されているサンプルコードで、5つのEmployee objectをObjectGridに追加することによりさまざまなパーティションにObjectが配置されることが分かります。
-
EntityManager APIを利用したデータの読み込み
ObjectGridからデータを読むために、再度トランザクションを取得したEntityManagerを利用しデータにアクセスします。Objectを検索する一番簡単な方法は、Findメソッドを利用する方法です。以下に示します。
em.find(Employee.class, "1234");
|
これが@Idアノテーションで設計されたJava Objectのkey fieldに基づいた検索です。EntityManager APIも同様に、グリッド環境の多くのObjectから検索するためにクエリを実行することできます。これは、SQLやJPAのクエリと多少似ています。
ObjectGridの検索(リスト6)
- ObjectGrid sessionを取得します
- sessionから、EntityManagerを取得します
- EntityManager内で、トランザクションを開始します
- EntityManagerを利用して検索を実行します
- 検索結果を繰り返し取得します(この手順では検索結果は1つです)
- 読み取りや編集を終了し、トランザクションをコミットします
リスト6. Using the EntityManager API to query data
Session session = objectGrid.getSession();
EntityManager em = session.getEntityManager();
em.getTransaction().begin();
String queryString = "select e from Employee e where e.ssn = '1234'";
Query query = em.createQuery(queryString);
Iterator<Employee> results = query.getResultIterator();
while (results.hasNext()) {
Employee e = results.next();
System.out.println(e.firstName);
System.out.println(e.surname);
System.out.println(e.ssn);
System.out.println(e.salary);
}
em.getTransaction().commit();
|
トランザクションが最後にコミットされるまでに、Objectは「managed」の状態となります。すなわち、コミットするまでのObjectに対するどんな変更も、コミット時に保管されます。トランザクションの外では、ObjectはObjectGridに追加することはできず、どんな変更もObjectGridに反映されません。(この時、Objectは「disconnect」の状態となります)
興味深いことに、リスト6にあるクエリは、単一のObjectGridパーティションのみで実行されます。これは、ObjectGridは1フェーズコミットのみをサポートしているためです(2フェーズコミットより高速で処理可能)、そのためクエリは単一のパーティションのみ実行されます。グリッドにまたがってクエリを実行するためには、それぞれのパーティションで実行する必要があります。PartitionManagerからパーティションの数を取得し、以下のようにクエリを実行したいパーティションを選択します。
リスト7.で示します。
リスト7. Performing a query across multiple partitions
BackingMap bm = objectGrid.getMap("Employee");
PartitionManager pm = bm.getPartitionManager();
int numPartitions = pm.getNumOfPartitions();
for (int i = 0; i < numPartitions; ++i) {
em.getTransaction().begin();
Query query = em.createQuery("select e from Employee e");
query.setPartition(i);
Iterator<Employee> results = query.getResultIterator();
//use the results
em.getTransaction().commit();
}
|
ここまでで、分散ObjectGrid環境を作成し、EntityManager APIにより読み込み・書き込みが可能となりました。これで、実際にやりたいグリッド処理の基礎が出来ました。

 |
グリッド環境における計算と更新の実行
今、ObjectGridの機能を使用した計算・更新処理を実行する環境が整いました。この機能はAgentの作成と実行により実現します。
Agentは、ObjectGrid内のデータと連携するアプリケーションの一部として作成できます。定義した各Agentは、すべてのパーティションに配置されます。ObjectGrid client(図1)にあるAgent Managerをコールすることにより、Agentがパラレルで実行されます。Agent内で、グリッドデータのいかなる計算や操作を実行することが出来ます。
Grid Agentには以下の2つのタイプがあり、クライアントに返す情報に大きな違いがあります。
- MapGridAgent:パーティションからmapを返します。例えば、MapGridAgentは実行された計算のサブセットを検索するのに役立ちます。
- ReduceGridAgent:パーティションから1つの結果を返します。例えば、ReduceGridAgentはパーティションの中から最大値・最小値を出力するのに役立ちます。
A)グリッド環境における計算の実行
シナリオを振り返りましょう:すべての従業員の平均の給料を算出します。これをそれぞれのパーティションで実行する方法は、以下のようになります。
- そのパーティションの従業員の給料を合計
- そのパーティションの従業員数
そして、このグリッド環境に渡った給料の平均値を算出するために、この情報がクライアントに戻されます。
データが存在するそれぞれのパーティションで計算がパラレルで実行されます。そのパーティションで計算が完了すると、クライアントに値が戻され少しの集約計算を実行します。
この計算ではReduceGridAgentを使用します。このAgentは、それぞれのパーティションから「1つの結果」を返します。リスト8で、Agentで実装する必要のあるinterfaceをざっと見てみましょう。
リスト8. ReduceGridAgent interface
public interface ReduceGridAgent {
/**
* Provides the logic to be run on each partition.
* @return Object containing the result of the processing
*/
public Object reduce(Session s, ObjectMap map);
/**
* Provides the logic to be run on each partition.
* In this case, the entries for the partition are constrained
* further by the entity keys in the collection
* @return Object containing the result of the processing
*/
public Object reduce(Session s, ObjectMap map, Collection keys);
/**
* Run once for the whole grid.
* It is run after the reduce methods have been run.
* @param A Collection of Java Objects, which is the results from
* each reduce method.
*/
public Object reduceResults(Collection results);
}
|
以下の実装を行います。
- reduce():あるパーティションの平均の給料を計算します。これは、それぞれのパーティションのサーバーサイドで実行されます。
- reduceResults():パーティションからの戻り値を集約計算します。これはクライアントで実行されます。
この手順である2番目のreduceメソッドは使用しませんが、このメソッドの考えはkeyを指定することよってあるパーティションのサブセットを操作可能となります。例えば、このシナリオでは、あるマネージャーのためにデータのサブセットで給料の平均値を計算することもできます。
図3では、分散環境でどのようになっているかを表します。
図3. Salary average grid agent overview
最後に、ReduceGridAgent interfaceを実装することに加えて、EntityAgentMixin interfaceを実装する必要があります。これはEntityを保管するために仕様上必要で、getClassForEntity()メソッドを実装するのみとなります。(このメソッドでは、扱うEntityのJava Class Typeを返します)。
-
Reduce Agentコード
リスト9は、各パーティションで実行されるReduce Agentコードとなります。そのロジックはとても直感的です。
- そのパーティションからすべての従業員を検索します
- その検索結果から、そのパーティションの従業員の数と給料の合計値を計算します
リスト9. Salary average reduce agent code
public Object reduce(Session s, ObjectMap map) {
EntityManager em = s.getEntityManager();
Query q = em.createQuery("select e from Employee e");
Iterator<Employee> employees = q.getResultIterator();
int sum = 0;
int count = 0;
while (employees.hasNext()) {
Employee e = employees.next();
sum += e.salary;
count++;
}
WeightedSalary partitionTotal = new WeightedSalary();
partitionTotal.employeeCount = count;
partitionTotal.salaryTotal = sum;
return partitionTotal;
}
|
-
グリッドにわたったデータの集約
グリッドにわたって答えを一堂に集めるには、単純にパーティションから結果を繰り返し取得するだけです。グリッドにわたった給料の合計値を計算し、従業員の総数で割ります(リスト10)。このコードはクライアント側で実施されます。
リスト10. Salary average reduce agent aggregation code
public Object reduceResults(Collection results) {
System.out.println("Calculate salary total across the grid");
Iterator<WeightedSalary> salaries = results.iterator();
int sum = 0;
int count = 0;
while (salaries.hasNext()) {
WeightedSalary sc = (WeightedSalary) salaries.next();
sum += sc.salaryTotal;
count += sc.employeeCount;
}
return sum / count;
}
|
ここまででAgentが定義されましたので、アプリケーションからキックして実行する必要があります。(リスト11)
- ObjectGrid内のEmployee ObjectMapを取得し、それからAgentManagerを取得します
- 先ほど記述したAgentのインスタンスを作成します
- AgentManagerのcallReduceAgentメソッドにAgentを渡し、結果を得ます。この場合では、給料の平均値がIntegerで得られます。
リスト11. Salary average reduce agent client code
AgentManager amgr = map.getAgentManager();
AverageSalaryReduceAgent agent = new AverageSalaryReduceAgent();
Integer aveSalary = (Integer) amgr.callReduceAgent(agent);
|
これで分かるように、この手法はとても簡単で、このアプローチがグリッド環境でデータ操作するために大変効果のある方法だと分かります。この簡単なシナリオでは、図3で記述した以下のことを実装しています。
- (メインのプログラムから)クライアントが呼び出し
- (Reduce Agent コード内)Agentのメソッドが各パーティションで実行
- (Reduce Agent コード内)再度クライアントに戻され、集約計算の実行
B)グリッド環境の更新処理の実行
先ほどは、グリッド環境から1つの戻り値を得るためにReduceGridAgentを利用しました。DataGrid APIでは、MapGridAgentを提供しています。これもまた、各パーティションのすべてのデータやサブセットのデータを操作しObjectGridパーティションに対して出力することが可能です。違いとしては、MapGridAgentはmapをベースとした戻り値となることです。このことによりパーティションで各Objectに対して操作し、クライアントにまとまった結果を返すことが可能となります。
このケースでは、実際よりシンプルなケースを想定し、ObjectGrid上でMapGridAgentを利用した更新処理を実施します。この処理はReduceGridAgentとMapGridAgentのどちらでも実施することができます。ここでは、後者をデモの目的で利用します。
MapGridAgent interface.を簡単に紹介しましょう。ReduceGridAgentのものと比べて少しシンプルで、サーバーサイドで動く2つのメソッドのみ持ちます。(リスト12)
リスト12. Increase salary map agent code
public interface MapGridAgent {
/**
* Process a single entity in the partition we are working within
* as designated by the key parameter passed to the method.
* @return Object containing processed data
*/
public Object process(Session s, ObjectMap map, Object key);
/**
* Select all or some of the entities for this partition
* @return Map containing results for client
*/
public Map processAllEntries(Session s, ObjectMap map);
}
|
従業員の給料の管理をするこのシナリオの中で、会社全体で10%の昇給をすることを想定します。これを実施するには、ObjectGrid内にあるデータ全てに対して処理するという分かりやすい方法です。図4ではこれを実行する順序を表しています。
- クライアントからAgent Manager.を呼び出しの実行
- 各Agentに対してprocessAllEntriesメソッドを実行
- processAllEntriesメソッドにより、そのパーティションに含まれる全てのEmployee Objectを検索
- 全てのEmployee Objectに対して、昇給の更新処理をするprocessメソッドを実行
図4. MapGridAgent overview
拡大図
MapGridAgent interfaceで、両方のメソッドを実装します。(リスト13)
- processAllEntriesメソッドによりそのパーティションにある全てのEntityを選択し、processメソッドを通して各Entityを操作します
- processメソッドでは、key変数で定義されたEmployee ObjectのSalaryに対して単純な更新処理を実施します
- またこのAgentに対して従業員の昇給のパーセンテージをパラメータとして渡す必要があり、Objectのコンストラクタでこのパラメータを設定します
この例では、戻り値は必要としませんので、空のハッシュマップを使用します。
リスト13. Increase salary map agent client code
public class IncreaseSalaryMapAgent implements MapGridAgent, EntityAgentMixin {
private float increasePercentage;
public IncreaseSalaryMapAgent(float increasePercentage){
super();
this.increasePercentage = increasePercentage;
}
public Map processAllEntries(Session s, ObjectMap map) {
EntityManager em = s.getEntityManager();
Query q = em.createQuery("select p from Employee p");
Iterator iter = q.getResultIterator();
while (iter.hasNext()) {
Employee p = (Employee) iter.next();
process(s,map,p);
}
return new HashMap(); //just empty hashmap
}
public Object process(Session s, ObjectMap map, Object key) {
Employee p = (Employee)key;
p.salary *= 1 + increasePercentage;
return p;
}
public Class getClassForEntity() {
return Employee.class;
}
}
|
Agentは、ReduceGridAgentとまったく同じ方法でグリッド環境内で実行することができます。リスト14で確認できます。取得したAgentManagerからmap agentを呼び出します。今回は、昇給といった更新処理を実施するためにIncreaseSalaryMapAgentを渡します。
リスト14. Sample output from demonstration application
AgentManager amgr = map.getAgentManager();
IncreaseSalaryMapAgent agent = new IncreaseSalaryMapAgent(increase);
Map m = amgr.callMapAgent(agent);
|
これはAgentをキックする一番簡単な方法です。しかしながら、ReduceGridAgentと同様の方法も用いて、callMapAgentメソッドに対してEntityのkeyのリストを渡すことにより拡張することもできます。このことにより、Agent内のprocessAllEntriesメソッドをバイパスし、特定のEntityに対して直接processメソッドを実行することができます。
これで、分散アプリケーションとGrid Agentの設計は終了です。次にこれを実際にテストしてみます。
デモアプリケーションの実行
-
ObjectGridを準備します
前述を通して構成したObjectGridを起動します。(もしもObjectGridを持って無ければ、Resourceからtrial版を取得してください)この記事に含まれるデモアプリケーションをDownloadします。以下が使用する重要なディレクトリーとなります。
- DEMO_HOME:デモアプリケーションのzipファイルを解凍した場所
- JAVA_HOME:Java SDKの場所(環境変数として定義する必要があります)
- OG_HOME:ObjectGrid V6.1.の場所
-
Catalog serverを始動します
ObjectGridのbinディレクトリーから、Catalog serverと2つのObjectGrid serverを始動します。
OG_HOME/bin から実行します
startOgServer.bat/.sh catalogServer -listenerHost localhost
-
ObjectGrid serverを始動します
以下の始動スクリプトは、同じOS上で全てのObjectGrid server(Catalog server)が稼働することを想定しています。したがって、Catalog serverのロケーションをこのスクリプトに記述する必要はありません。
OG_HOME/bin から実行します
startOgServer.bat/.sh server1
-objectgridFile <DEMO_HOME>/META-INF/ObjectGrid_Definition.xml
-deploymentPolicyFile <DEMO_HOME>/META-INF/ObjectGrid_Deployment.xml
-jvmArgs -cp <DEMO_HOME>
startOgServer.bat/.sh server2
-objectgridFile <DEMO_HOME>/META-INF/ObjectGrid_Definition.xml
-deploymentPolicyFile <DEMO_HOME>/META-INF/ObjectGrid_Deployment.xml
-jvmArgs -cp <DEMO_HOME>
|
このデモは1台のObjectGrid serverで実行できますが、2台以上のObjectGrid serverで分散実行の状況が確認できます。ここでは2台ですが違う名前をつけて自由にサーバーを始動してください。
ObjectGrid serverが始動するまでお待ちください、始動すると下記のメッセージが表示されます。
CWOBJ1001I: ObjectGrid Server server1 is ready to process requests.
ObjectGrid serverのログはlogsディレクトリーの下に作成されます。
server1とserver2のSystemOut.logで下記でアプリケーション実行している間、確認してみてください。
-
アプリケーションを実行します
DEMO_HOMEディレクトリーからコマンドでクライアントコードを実行します。
java -cp <OG_HOME>/lib/ogclient.jar;.
com.ibm.websphere.samples.datagrid.SalaryApp
|
リスト15. Sample output from demonstration application
Populating grid with Employee entities
Calculate salary average across the grid
Average salary across grid: 44000
Processing salary increase across grid
Calculate salary average across the grid
Average salary across grid: 48400
Reading from partition: 0
Jonathan
Marshall
0
110000
Reading from partition: 1
Alan
Chambers
1
55000
Reading from partition: 2
Matt
Perrins
2
22000
Reading from partition: 3
Joe
Bloggs
3
22000
Reading from partition: 4
Fred
Smith
4
33000
|
この出力は以下のことを示します。
- 2つのAgentの実行結果
- 昇給Agentを実行する前の平均値
- 昇給Agentの実行
- 10%昇給した後の給料の平均値
- ObjectGridに保管された各Employeeレコードの出力。再度10%昇給させ、違うパーティションからEmployee Objectを読み込むことで、分散実行の状況を確認できます。
server1とserver2のSystemOut.logファイルを見ると、以下のメッセージに似た5つのメッセージが確認できます。
[10/10/07 14:04:10:046 BST] 21722172 SystemOut O Calculating salary total for partition: 0
|
このログはAgentが実行されたとき生成するので、5つ別々の場所で5回Agentが実行されているのが確認できます。クライアントを何回も実行すると、そのたびに給料の平均値がだんだん増加することが確認できます。
結論
この記事では、ObjectGridの2つの強力な機能を紹介しました。1つは、ObjectGrid内でObjectを追加・検索のためにEntityManager APIを利用することで、2つ目はDataGrid APIを利用して計算と更新処理をグリッド化する方法です。
これらのツールを利用することで、グリッドデータを使用やグリッド・コンピューティングの実行インフラを簡単に設計できます。この記事で紹介した簡単な例は、非常に難しい複雑なシナリオでもObjectGridを使用できることを説明しています。さらに、このアプローチは、特別なハードウェアを必要としないため、著しくパフォーマンスを向上させる可能性があります。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Code sample | ObjectGrid-computation-demo.zip | 16 KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
著者について  | |  | Jonathan Marshall is a Senior IT Specialist working for IBM WebSphere Technical Sales in the UK. He has been working with WebSphere Application Server and related products for six years as a technical consultant and recently been focussing on IBM's Process Integration products. |
記事の評価
|