2014-09-02 137 views
5

我已經實現了一個hazelcast服務,它通過MapStoreFactory和newMapLoader將其數據存儲到本地mapdb實例中。這樣的鍵就可以,如果集羣需要重新啓動時加載:Hazelcast和MapDB - 實現簡單的分佈式數據庫

public class HCMapStore<V> implements MapStore<String, V> { 

Map<String, V> map; 

/** specify the mapdb e.g. via 
    * DBMaker.newFileDB(new File("mapdb")).closeOnJvmShutdown().make() 
    */ 
public HCMapStore(DB db) { 
    this.db = db; 
    this.map = db.createHashMap("someMapName").<String, Object>makeOrGet(); 
} 

// some other store methods are omitted 
@Override 
public void delete(String k) { 
    logger.info("delete, " + k); 
    map.remove(k); 
    db.commit(); 
} 

// MapLoader methods 
@Override 
public V load(String key) { 
    logger.info("load, " + key); 
    return map.get(key); 
} 

@Override 
public Set<String> loadAllKeys() { 
    logger.info("loadAllKeys"); 
    return map.keySet(); 
} 

@Override 
public Map<String, V> loadAll(Collection<String> keys) { 
    logger.info("loadAll, " + keys); 
    Map<String, V> partialMap = new HashMap<>(); 
    for (String k : keys) { 
     partialMap.put(k, map.get(k)); 
    } 
    return partialMap; 
}} 

我現在面臨的問題是,從hazelcast的MapLoader接口的loadAllKeys方法需要返回整個集羣但每次的所有鍵節點只存儲它擁有的對象。

示例:我有兩個節點並存儲8個對象,然後例如5個對象存儲在node1的mapdb中,3存儲在node2的mapdb中。我認爲哪個節點由哪個節點擁有是由hazelcast決定的。現在重新啓動節點1將爲loadAllKeys返回5個鍵,並且node2將返回3. Hazelcast決定忽略這3個項目並且數據「丟失」。

什麼可能是一個很好的解決方案呢?

更新賞金Here我問這個慧聰郵件列表提2個選項上(我將添加1更多),我想知道,如果這樣的事情已經是可能的hazelcast 3.2或3.3:

  1. 當前MapStore接口只從本地節點獲取數據或更新。是否可以通知MapStore接口完整集羣的每個存儲操作?或者,這對一些聽衆來說已經是可能的了。也許我可以強制hazelcast將所有對象放入一個分區,並在每個節點上都有1個副本。

  2. 如果我重新啓動例如2節點,然後使用我的本地數據庫爲節點1和節點2正確調用MapStore接口。但是,當兩個節點加入節點2的數據將被刪除,因爲Hazelcast假定只有主節點可以是正確的。我可以教榛樹接受來自兩個節點的數據嗎?

回答

0

這似乎是not easily possible:對Hazelcast

的持久化層需要它是某種 中央存儲。像數據庫或共享文件一樣。

或外觀herehere。將調查使用Hazelcast的OrientDB並持續播放。

1

也許有兩種選擇:

1)深入分析Hazelcast中的分區是如何工作的。我認爲每個分區都可以有MapLoader,強制節點只加載自己的分區,這可以解決衝突。 2)當節點恢復在線時,在添加節點之前與Hazelcast羣集進行交互。您可以從MapDB合併HZ第二臺。 3)迫使Hazelcast存儲每個節點上的所有數據。設置分區號爲1或者其他

+0

謝謝 - 選項是好主意,但我想知道我將如何做這樣的事情,如果這是可能的。 – Karussell 2014-09-09 08:36:57

+0

也看到了你的項目:) https://github.com/jankotek/mapdb-hz-offheap – Karussell 2017-05-09 11:47:25

2

根據Hazelcast 3。3文檔 的MapLoader初始化流程如下:

當的GetMap()首先從任何節點調用,初始化將根據InitialLoadMode的值開始 。如果它設置爲EAGER,則啓動 初始化。如果設置爲LAZY,則初始化實際上 不會啓動,而是在每次分區加載完成時加載數據 。

  1. Hazelcast將調用MapLoader.loadAllKeys()來獲得在 所有你的鑰匙每個節點
  2. 每個節點都會找出它擁有
  3. 每個節點將通過調用加載其擁有的所有密鑰的密鑰列表 MapLoader.loadAll(鍵)
  4. 每個節點通過調用 IMap.putTransient(鍵,值)
把它的擁有條目到地圖

以上意味着如果節點以不同的順序啓動,那麼密鑰也將得到不同的分配。因此,每個節點都不會在其本地存儲中找到全部/部分指定的密鑰。您應該可以通過在HCMapStore.loadAllKeys和HCMapStore.loadAll中設置斷點來驗證它,並將您獲取的密鑰與密鑰進行比較。

在我看來,你正試圖實現與分佈式緩存的概念相抵觸的概念,像Hazelcast這樣的彈性特性,因此是不可能的。即當一個節點消失(出於任何原因失敗或斷開連接)時,集羣將通過移動部分數據來重新平衡,每次節點加入集羣時都會發生相同的過程。因此,如果集羣發生更改,丟失節點的本地後端存儲會變得過時。

Hazelcast集羣本質上是動態的,因此它不能依賴於具有靜態分佈式拓撲的backstore。實質上,您需要有一個共享的後臺存儲來使其與動態hazelcast羣集一起工作。還可以分發後臺,例如, cassandra,但其拓撲結構必須獨立於緩存集羣拓撲。

更新:在我看來,你試圖實現的是更具邏輯性的分佈式數據存儲(在MapDB之上)的形式與本地緩存。

我希望這會有所幫助。

1

可以加載存儲在所有節點上的數據,但此時您必須手動執行此操作。

在每個節點上:

HCMapStore store = createMapDbStore(); 
HazelcastInstance hz = createHz(store); // use store in MapStoreConfig as implementation 
IMap imap = hz.getMap("map"); 
Map diskMap = store.loadAll(store.loadAllKeys()); // load all entries on disk 
imap.putAll(diskMap); // put into distributed map 

但在郵件列表MapStore提到的是不是真的打算使用這種方式。另外請注意,備份不會以這種方式保存到磁盤。因此,如果您重新啓動集羣並且某個節點上的磁盤死亡,則這些條目將丟失。

+0

謝謝!這意味着有一個'碎片'概念被稱爲'分區',但沒有複製概念?如果這些條目將會丟失,那麼HC如何確保它在節點死亡時不會丟失數據? – Karussell 2014-09-11 12:41:03

+0

@Karussell條目在多個節點的內存中備份。如果一個節點在集羣運行良好的情況下死亡。但是這種本地持久性備份不存儲在磁盤上。因此,如果你關閉你的集羣,然後嘗試啓動它,並且一個磁盤無法啓動,因爲它的死亡... – Andrejs 2014-09-11 12:50:47

+0

我看到並且無法以某種方式訪問​​這個內存中的備份? – Karussell 2014-09-11 13:25:41