オープンソース化したCoherence（インメモリデータグリッド）で分散キャッシュを実現しよー

# Coherenceを使ってみよー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/c57f396b-8086-3bb1-9eca-b622555dde03.png)

* DBのデータをメモリ上にキャッシュ
* キャッシュデータは分散

オープンソース化したCoherenceを使って上記を実現する！
メモリからデータを取得してディスクIO失くしてアプリを爆速にしよー
使ってみた感想としては、キャッシュの分散が手軽にできるし、耐障害性も簡単に実現できて
べんりーですね
情報を本投稿に細かく記載しているので誰でもできると思います！

1個のjarを動かすだけで簡単に使えるので、既存のアプリに組み込んで、遅い画面だけ
Coherenceを使って、メモリにデータ持つとかもありかなーと思いました！

windows機でEclipseを使ってアプリケーションを作るので、実際の開発工程がなんとなく分かるし、
発展させて、自分流のアプリケーションを作ってみるのも楽しいかもですね

日本語の使い方の情報が少ないし、本があっても激古情報なので、有益なはず

なお、DBはderbyを使います

## Coherenceダウンロード

今回はmavenの設定はせず、mvnのセントラルレポジトリから直接jarを仕入れます！
依存関係がないので、このjarだけで動きます、シンプル！

※本格的なプロジェクト運用するなら、eclipseでmavenプロジェクトとかgradleプロジェクト作った方がよいですね

https://mvnrepository.com/artifact/com.oracle.coherence.ce/coherence/20.12
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/07159d64-af4f-6305-6274-dcc6fefe019d.png)

以下に配置してみた

```
C:\work\coherence\20.12\jar
```

ソースとREADMEをみたければ以下です
https://github.com/oracle/coherence

なんかカッコいいコミュニティサイトも立ち上がってる！
マイクロサービスでのCoherenceの使い方が紹介されてますね（英語）
https://coherence.community/

## Javaダウンロード

以下からダウンロード
https://www.oracle.com/java/technologies/javase-downloads.html
※オラクルアカウントの作成が必要です

現在（2021年2月）githubのREADMEには、JDK 8以上をサポートと記載。
JDK15は非対応っぽいので、JDK11を使用してみる

今回はEclipseを使った実装も行うので、Sierの開発機として一般的？？？な
windows環境に作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/fb3a1a7f-0cca-4d04-2072-f4a96e09a517.png)

以下に解凍して配置

```
C:\work\coherence\20.12\jdk-11.0.10_windows-x64_bin
```

ユーザー変数設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/23de582a-c3f0-4b8e-bdff-63d9da9cd148.png)

Pathに以下の追加も忘れずに

```
%JAVA_HOME%\bin
```

動作確認

```
java -version
```

以下のような画面でればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/fe59a7f2-73c3-48f0-f09d-00d490b8ffbc.png)


## Eclipseのダウンロード

以下からダウンロード
https://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/2020-12/R/eclipse-jee-2020-12-R-win32-x86_64.zip
※Oracle Enterprise PackのEclipseを使えると便利ですが、現在（2021年2月）、Java8までの対応っぽいし、Coherenceは商用版（～12系）までしかサポートしていなのであまり使う理由を思い当たらず。
※最近のエクリプスは、中二病っぽい名前（Luna、oxygen等）ではなく、2020-12とかになったんですね、ちょっと悲しい

以下に解凍して配置

```
C:\work\coherence\20.12\eclipse-jee-2020-12-R-win32-x86_64
```

eclipse.iniを編集してJDK11で動くようにしよー
※デフォルトはJava15でしたー

```
-vm
C:/work/coherence/20.12/jdk-11.0.10_windows-x64_bin/jdk-11.0.10/bin
```

起動してみる

```
eclipse.exe
```

ワークスペースは以下につくりました
※デフォルトのワークスペースの接頭辞に、"eclipse-"がつくようになったんですね

```
C:\work\coherence\20.12\eclipse-jee-2020-12-R-win32-x86_64\eclipse\eclipse-workspace
```

とりあえず、Javaのソースした時にフォーマッターが適用されるように設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/a2bad7c2-cb87-c5f2-b280-b6129e0de39a.png)

xmlが間違ってもいないのにエラーが出てうざいので、チェックを全外し

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/68115983-f081-0eda-0ccf-9b7b1a6e005f.png)

スペルチェックもうざいので、チェックを外し

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/d5f1ac3c-cda3-0432-77e1-8eb8a0229c1d.png)

## Apache Derbyのダウンロード

JDK7までは、JDKに同梱されてたけど、JDK8以降はないので、自分でダウンロードしようー
http://db.apache.org/derby/releases/release-10_14_2_0.cgi

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/140e5f8c-4ba4-9d75-ed76-0f14d394a31f.png)

解凍して以下に配置

```
C:\work\coherence\20.12\db-derby-10.14.2.0-bin
```

起動してみますかー以下実行するだけ

```
startNetworkServer.bat
```

こんな感じの画面でるよ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/d4abea6c-c89e-43b8-295b-e80a18ddb5d9.png)

失敗した場合は以下を確認しましょー
※私はゾンビderby？がいて、ポート競合で失敗しましたー

```
derby.log
```

## ElipseからApache Derbyに接続

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/74a9b713-1b5f-474d-b9a1-48a6fb2ab10c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/24ca2504-3044-dd32-0106-be1dce4c0707.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/601898e1-cc4c-98e7-ce97-a8b56d839238.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/3093c5a1-1c2d-491a-0a50-847d4477a177.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/00301860-0cc3-3c0a-930a-3622e3dfbd9a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/a97f6977-59e3-0cee-99c7-f656a71a2e18.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/99a47560-ffa2-9270-ee65-227735d1972c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/3b75e71d-6f4a-922d-9145-6d98bf58f8ba.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/514aca3f-0a40-7924-808b-d89139d11fdc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/2f6144c7-7388-cb67-55e9-67e51ea7febf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/617aec40-6977-61b1-037a-5648820ba979.png)

## 表の作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/ce219f1e-b46b-d4b3-b488-3c6f35af1492.png)

```sql
create table person (id integer primary key, name varchar(128));
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/b25cc5ca-3cd0-b178-239a-582a98ecfb89.png)

リフレッシュしても、繁栄されなかったので、いったんDisconnectして、再connect
※connectする際に出力されるダイアログのパスワード保存にチェック入れると次回からダイアログが出なくなるので便利

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/3d0c7455-9378-5e16-ae4b-951aebfcc6ad.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/211bdaa4-4990-fc83-7f7d-4bb61b422a7a.png)

PERSONテーブルできてること確認できましたー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/27d842b0-a6c6-5944-f95c-709a51be9029.png)

## Eclipse上にプロジェクトを作ろう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/eb923a3d-8af2-4f99-4824-874d4119da00.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/f3dc6153-98a3-7963-67da-89c21b16b523.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/8e50addf-3f26-1fc7-8bdb-cd12fdd23bd1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/7db269ee-627c-c292-3f1a-8e079785df87.png)

## 設定ファイルを作成＆編集

coherence-20.12.jarを解凍しましょー
※7-zipというツールを使って私は解凍してます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/b19c6fce-6ad4-3591-80bb-f216db120891.png)

中に以下の三つのファイルがあります

```
coherence-cache-config.xml
pof-config.xml
tangosol-coherence-override-dev.xml
```

上記三つのファイルをsrc配下にコピペしましょー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/f3d181e7-55fd-4dcd-6f67-eadaeb4dde83.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/e6edecb0-84c1-6827-b0f8-8ccfffa668c8.png)

### coherence-cache-config.xml

キャッシュの設定
私はテキストエディタでの編集が好きなので、テキストエディタをオープン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/7bc338b4-df61-9a5b-8bb5-646921f5ed64.png)

こんな感じに編集しよー

```xml
<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">  
  <caching-scheme-mapping>
    <cache-mapping>
      <cache-name>Person</cache-name>
      <scheme-name>my-scheme</scheme-name>
    </cache-mapping>
  </caching-scheme-mapping>

  <caching-schemes>
    <!-- partitioned caching scheme for servers -->
    <distributed-scheme>
      <scheme-name>my-scheme</scheme-name>
      <service-name>my-service</service-name>
      <serializer>pof</serializer>
      <backing-map-scheme>
        <read-write-backing-map-scheme>
          <internal-cache-scheme>
            <local-scheme />
          </internal-cache-scheme>
          <cachestore-scheme>
            <class-scheme>
              <class-name>
                jp.coherence.PersonCache
              </class-name>
            </class-scheme>
          </cachestore-scheme>
        </read-write-backing-map-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
    </distributed-scheme>
  </caching-schemes>
</cache-config>
```
### pof-config.xml

シリアライズの対象設定
こんな感じに編集しよー

```xml
<?xml version="1.0"?>
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">        
  <user-type-list>
    <!-- by default just include coherence POF user types -->
    <include>coherence-pof-config.xml</include>    
    <user-type>
      <type-id>1001</type-id>
      <class-name>jp.coherence.Person</class-name>
    </user-type>
  </user-type-list>
  <enable-type-discovery>true</enable-type-discovery>
</pof-config>
```

### tangosol-coherence-override-dev.xml

コヒーレンスの設定（上書き分）

まず名前を編集。以下へ

```
tangosol-coherence-override.xml
```

あとは、こんな感じに編集しよー

```xml
<?xml version="1.0"?>
<coherence  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
            xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">
  <cluster-config>
    <multicast-listener>
      <time-to-live system-property="coherence.ttl">0</time-to-live>
    </multicast-listener>
  </cluster-config>
  <management-config>
    <managed-nodes system-property="coherence.management">all</managed-nodes>
    <reporter>
      <autostart system-property="coherence.management.report.autostart">true</autostart>
    </reporter>
  </management-config>
</coherence>
```

## ビルドパスの設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/a28a391c-edc9-1d38-b0f3-3a7d072ba5e3.png)

まずは、作成したxml君たちを読み込む設定をしよー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/8c6ef308-f202-ee96-a0c0-c5c95ea3dd1e.png)

以下を指定

```
C:\work\coherence\20.12\eclipse-jee-2020-12-R-win32-x86_64\eclipse\eclipse-workspace\CoherenceTest\bin
```

次に、coherenceのjarを参照する設定をしよー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/262f301d-38c1-a52a-c6da-29d524d15f45.png)

以下を指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/67791dad-18e2-e6c1-aefc-c2307c31f16e.png)

こんな感じになってればＯＫ
※順番大切なので、xmlの読み込み先にくるようにー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/f6b92c79-019f-1e0f-44e0-57c4fff93e7b.png)

## キャッシュのプログラミングしよー

### Personクラス

xmlにpath記載してあるので、パッケージ名とクラス名の変更はしないように

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/8a638b5e-8a6c-5b53-4baf-d040ab3bdb00.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/107b1968-7ec6-8983-aee2-6a856a755106.png)

ソースはこんな感じで

```java
package jp.coherence;

import java.io.IOException;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

public class Person implements PortableObject, Comparable<Person> {

	private static final long serialVersionUID = 1L;

	private int id;

	private String name;

	public Person() {
	}

	public Person(String name) {
		this.name = name;
	}

	public Person(int id, String name) {
		this.id = id;
		this.name = name;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public int compareTo(Person person) {
		return Integer.valueOf(id).compareTo(Integer.valueOf(person.getId()));
	}

	@Override
	public void readExternal(PofReader reader) throws IOException {
		this.id = reader.readInt(0);
		this.name = reader.readString(1);
	}

	@Override
	public void writeExternal(PofWriter writer) throws IOException {
		writer.writeInt(0, this.id);
		writer.writeString(1, this.name);
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + "]";
	}
}
```

### PersonCacheクラス

xmlにpath記載してあるので、パッケージ名とクラス名の変更はしないように

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/23a029e3-a281-4f67-af82-359e746a70ac.png)

ソースはこんな感じで

```java
package jp.coherence;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Map.Entry;

import com.tangosol.net.cache.CacheStore;

public class PersonCache implements CacheStore {

	private static ThreadLocal<Connection> tcon = new ThreadLocal<>();

	private Connection getConnection() throws ClassNotFoundException, SQLException {
		Connection con = tcon.get();
		if (con == null || con.isClosed()) {
			Class.forName("org.apache.derby.jdbc.ClientDriver");
			con = DriverManager.getConnection("jdbc:derby://127.0.0.1:1527/sample", "test", "test");
			con.setAutoCommit(false);
			tcon.set(con);
		}
		return con;
	}

	private Person findPerson(int personId, Connection con) throws SQLException {
		String sql = "SELECT * FROM PERSON WHERE ID = ?";
		try (PreparedStatement pstmt = con.prepareStatement(sql)) {
			pstmt.setInt(1, personId);
			ResultSet rs = pstmt.executeQuery();
			if (rs.next()) {
				return new Person(rs.getInt("ID"), rs.getString("NAME"));
			}
		}
		return null;
	}

	private void storePerson(int personId, Person person, Connection con) throws SQLException {
		if (findPerson(personId, con) != null) {
			String sql = "UPDATE PERSON SET NAME = ? WHERE ID = ?";
			try (PreparedStatement pstmt = con.prepareStatement(sql)) {
				pstmt.setString(1, person.getName());
				pstmt.setInt(2, personId);
				pstmt.executeUpdate();
			}
		} else {
			String sql = "INSERT INTO PERSON VALUES (?,?)";
			try (PreparedStatement pstmt = con.prepareStatement(sql)) {
				pstmt.setInt(1, personId);
				pstmt.setString(2, person.getName());
				pstmt.executeUpdate();
			}
		}
	}

	@Override
	public Object load(Object key) {
		try {
			Connection con = getConnection();
			int personId = Integer.parseInt(key.toString());
			return findPerson(personId, con);
		} catch (SQLException | ClassNotFoundException ex) {
			throw new RuntimeException(ex);
		}
	}

	@Override
	public void erase(Object key) {
		int id = Integer.parseInt(key.toString());
		String sql = "DELETE FROM PERSON WHERE ID = ?";
		try {
			Connection con = getConnection();
			try (PreparedStatement pstmt = con.prepareStatement(sql)) {
				pstmt.setInt(1, id);
				pstmt.executeUpdate();
				con.commit();
			} catch (SQLException ex) {
				con.rollback();
			}
		} catch (SQLException | ClassNotFoundException ex) {
			throw new RuntimeException(ex);
		}
	}

	@Override
	public void store(Object key, Object value) {
		Person person = (Person) value;
		int personId = Integer.parseInt(key.toString());
		try {
			Connection con = getConnection();
			try {
				storePerson(personId, person, con);
				con.commit();
			} catch (SQLException ex) {
				con.rollback();
				throw ex;
			}
		} catch (SQLException | ClassNotFoundException ex) {
			throw new RuntimeException(ex);
		}
	}

	@Override
	public void storeAll(Map entries) {
		Map<Integer, Person> persons = (Map<Integer, Person>) entries;
		try {
			Connection con = getConnection();
			try {
				for (Entry<Integer, Person> entry : persons.entrySet()) {
					int playerId = entry.getKey();
					Person player = entry.getValue();
					storePerson(playerId, player, con);
				}
				con.commit();
			} catch (SQLException ex) {
				con.rollback();
				throw ex;
			}
		} catch (SQLException | ClassNotFoundException ex) {
			throw new RuntimeException(ex);
		}
	}
}
```

## クライアントのプログラミングして行こー

ここからは適当な名前でつくってOK

### ClientGet

データ取得用のクラス
キャッシュにあれば、キャッシュからデータとるし、
キャッシュになければ、データベースからデータ取得するよ

ソースはこんな感じで

```java
package jp.coherence;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class ClientGet {
	public static void main(String[] args) {
		NamedCache person = CacheFactory.getCache("Person");
		System.out.println("size: " + person.size());
		System.out.println(person.get(1));
		System.out.println(person.get(2));
		System.out.println(person.get(3));
		System.out.println(person.get(4));
		System.out.println(person.get(5));
		System.out.println("size: " + person.size());
	}
}
```
### ClientPut

データ挿入する用のクラス

ソースはこんな感じで

```java
package jp.coherence;

import java.util.Iterator;
import java.util.Map;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class ClientPut {
	public static void main(String[] args) {
		NamedCache person = CacheFactory.getCache("Person");
		person.put(1, new Person(1, "aaaa"));
		person.put(2, new Person(2, "bbbb"));
		person.put(3, new Person(3, "cccc"));
		person.put(4, new Person(4, "dddd"));
		Iterator<Map.Entry<Integer, Person>> pi = person.entrySet().iterator();
		System.out.println("size:" + person.size());
		while (pi.hasNext()) {
			Map.Entry entry = pi.next();
			Person p = (Person) entry.getValue();
			System.out.println(p.toString());
		}
	}
}
```

## さあ、動作確認だー①

まずは、キャッシュ用のサーバーを立ち上げよう
コマンドプロンプトで以下を入力してね

```winbatch
set memory=1g
set java_opts=-Xms%memory% -Xmx%memory%

java -server -showversion %java_opts% -cp "C:\work\coherence\20.12\db-derby-10.14.2.0-bin\lib\derbyclient.jar;C:\work\coherence\20.12\eclipse-jee-2020-12-R-win32-x86_64\eclipse\eclipse-workspace\CoherenceTest\bin;C:\work\coherence\20.12\jar\coherence-20.12.jar" com.tangosol.net.DefaultCacheServer %*
```

クラスパスに以下が指定してあるよー

* C:\work\coherence\20.12\db-derby-10.14.2.0-bin\lib\derbyclient.jar
* C:\work\coherence\20.12\eclipse-jee-2020-12-R-win32-x86_64\eclipse\eclipse-workspace\CoherenceTest\bin
* C:\work\coherence\20.12\jar\coherence-20.12.jar"

分散してデータを持ちたいので、2台たちあげよー
※カレントディレクトリにレポートが出力される設定になっています
　同じディレクトリで立ち上げると、レポート内容が重複するので、
　2台は別々のディレクトリで起動しよー
　なお、設定の変更は可能です

ちゃんとスタートしたようですね

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/8dd4234e-5596-7473-d4a9-662848b9eb57.png)

## さあ、動作確認だー②

データ（キャッシュ＆DBへ）を入れまーす
※derby立ち上げておいてね

ClientPutを実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/6619b08c-b279-2256-f169-1ba9d9ba3e51.png)

以下が表示されれば成功！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/c3f63351-f939-1f80-e5d9-f2d6fdd444e0.png)

DBにデータが入ったか確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/34758edd-3ed7-69f9-9b09-a88ca1a7a9ee.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/84deec85-1f49-9d9f-b4c4-190cda7b993e.png)

DBにデータ入っているので、キャッシュ上にデータがあるか、それからデータが2台で分散してるか確認

jconsole（jdkに同梱されてるよ）で確認しよー
コマンドプロンプトで以下を実行

```
jconsole
```

あとで1号機を落とすので、2号機を選択
※情報はどっちでもみれるよー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/5ccc3bc5-b737-b9ad-4737-a490cfbf5049.png)

1号機には、3つデータ入ってる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/b0b05254-e8e1-c07f-6d0c-ba381e7f668e.png)

2号機には、1つデータ入ってる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/16934325-256b-f65b-52e8-0aef36b35c25.png)

データあるし、一応分散できてるね

次に1号機落としてみよー（コマンドプロンプト上でctrl+cとかで停止させてください）
2号機にデータうつるはず

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/1face0fe-f6ca-5cab-cc4d-35063a50e378.png)

お、成功しましたねー

アプリからもゲット（ClientGetを実行）してみよー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103334/5d558990-b10d-369f-4b19-2586464974b2.png)

どうやらうまくいっているようですね

あとは各自色々なことして遊んでみてください