CLOVER🍀

That was when it all began.

HazelcastのDistibuted Mapにおける、キーの分散状況を確認する

Hazelcastのように、データを分散配置するミドルウェアやライブラリは、キーに応じたエントリがどこにあるかパッとわからないことが多いと思うので、Hazelcastの場合の調べ方を。

ちなみに、Infinispanは前にやりました。

DistributionManagerを使って、キャッシュエントリの保持情報を確認する
http://d.hatena.ne.jp/Kazuhira/20130601/1370076661

確認のために、まずは浮いててもらうサーバを用意。
hazelcast_simple_server.clj

(require '[leiningen.exec :as exec])

(exec/deps '[[com.hazelcast/hazelcast "3.1.2"]])

(ns hazelcast-simple-server
  (:import (com.hazelcast.config Config)
           (com.hazelcast.core Hazelcast HazelcastInstance)))

(try
  ;; HazelcastInstanceの作成
  (let [^Config config (Config.)
        ^HazelcastInstance hazelcast (Hazelcast/newHazelcastInstance config)]
    ;; 浮いてるだけのサーバ
    (println "Start Simple Server.")
    (read-line)

    ;; HazelcastInstanceをシャットダウン
    (.. hazelcast getLifecycleService shutdown))

  ;; 全HazelcastInstanceをシャットダウン
  (finally (Hazelcast/shutdownAll)))

なんと、この前バージョンアップしたばかりなのに、もう3.1.2になっています。

これで、2つほどサーバを起動しておきましょう。

## Node1
$ lein exec hazelcast_simple_server.clj

## Node2
$ lein exec hazelcast_simple_server.clj

起動が終わると、クラスタの状態はこんな感じになります。
*上記の、Node1から見た状態です

Members [2] {
	Member [192.168.129.129]:5701 this
	Member [192.168.129.129]:5702
}

そして、確認用のプログラム。
hazelcast_partision_service.clj

(require '[leiningen.exec :as exec])

(exec/deps '[[com.hazelcast/hazelcast "3.1.2"]])

(ns hazelcast-partition-service
  (:import (com.hazelcast.config Config)
           (com.hazelcast.core Hazelcast HazelcastInstance IMap Member Partition PartitionService)))

(try
  (let [^Config config (Config.)
        ^HazelcastInstance hazelcast (Hazelcast/newHazelcastInstance config)
        ^IMap map (. hazelcast getMap "map")
        ^PartitionService ps (.. hazelcast getPartitionService)]

    ;; 適当にデータを登録
    (doseq [i (range 1 11)]
      (. map put (str "key" i) (str "value" i)))

    (doseq [i (range 1 11)]
      (let [^Partition partition (. ps getPartition (str "key" i))
            ^Member owner (.. partition getOwner)]
        (println (format "Key = %s, Owner = %s"
                         (str "key" i)
                         owner))))

    ;; HazelcastInstanceをシャットダウン
    (.. hazelcast getLifecycleService shutdown))

  ;; 全HazelcastInstanceをシャットダウン
  (finally (Hazelcast/shutdownAll)))

最初にIMapに対してデータを登録して、キーの分散状況を確認するプログラムです。

キーがどこにあるかを知るには、PartitionServiceを使えばよさそうです。

        ^PartitionService ps (.. hazelcast getPartitionService)]

ここで取得したPartitionServiceに対して、キーを指定してPartitionを取得することで、そのオーナーを知ることができます。

      (let [^Partition partition (. ps getPartition (str "key" i))
            ^Member owner (.. partition getOwner)]

というわけで、このプログラムを今の2つサーバ浮いているクラスタに対して実行します。

$ lein exec hazelcast_partision_service.clj

まずは、クラスタに参加します。

Members [3] {
	Member [192.168.129.129]:5701
	Member [192.168.129.129]:5702
	Member [192.168.129.129]:5703 this
}

ここで起動したNodeは、ポートが5703のものですね。「this」が付いているので、わかりますが。

その後、データを登録して、キーの分散状況を出力します。

Key = key1, Owner = Member [192.168.129.129]:5701
Key = key2, Owner = Member [192.168.129.129]:5702
Key = key3, Owner = Member [192.168.129.129]:5702
Key = key4, Owner = Member [192.168.129.129]:5702
Key = key5, Owner = Member [192.168.129.129]:5703 this
Key = key6, Owner = Member [192.168.129.129]:5703 this
Key = key7, Owner = Member [192.168.129.129]:5702
Key = key8, Owner = Member [192.168.129.129]:5701
Key = key9, Owner = Member [192.168.129.129]:5701
Key = key10, Owner = Member [192.168.129.129]:5701

こんな感じに分散されています。例えば、「key5」と「key6」に紐付いたデータについては、最後に起動したプログラムがオーナーとなっているということですね。

InfinispanやOracle Coherenceだと、バックアップの配置先までわかったのですが、Hazelcastの場合はここで使用しているPartitionServiceやPartitionの実体が、実はプロキシクラスになっているため、ちょっと簡単にはバックアップ位置を知ることはできなさそうです。

まあ、いいかぁ…。

あと、今回Distributed Mapに対して分散状況を確認しましたが、Hazelcastが提供するその他のデータ構造(Queue、MultiMap、Set、Listなど)については未確認です。

そもそも、Partitionを決めるのが「キー」なので、どうなんでしょうと…?それに、IMapとかってnameを指定して取得しますしね。

謎です。