2014-09-02 4 views
5

Ich habe einen hazelcast-Dienst implementiert, der seine Daten über MapStoreFactory und newMapLoader in lokale mapdb-Instanzen speichert. Auf diese Weise die Schlüssel geladen werden kann, wenn ein Cluster-Neustart ist erforderlich:Hazelcast und MapDB - Implementieren einer einfachen verteilten Datenbank

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; 
}} 

Das Problem, das ich jetzt bin vor, dass die loadAllKeys Verfahren der MapLoader Schnittstelle von Hazelcast alle Tasten des gesamten Clusters zurückzukehren erfordert aber jeder Der Knoten speichert NUR die Objekte, die er besitzt.

Beispiel: Ich habe zwei Knoten und speichern 8 Objekte, dann z. 5 Objekte werden in der mapdb von node1 und 3 in der mapdb von node2 gespeichert. Welches Objekt welchem ​​Knoten gehört, wird von hazelcast entschieden. Nach dem Neustart gibt node1 5 Schlüssel für loadAllKeys zurück und node2 gibt 3 zurück. Hazelcast entscheidet sich, die 3 Elemente zu ignorieren und die Daten sind "verloren".

Was könnte eine gute Lösung sein?

Update für Bounty: Here Ich haben diese auf der Mailing-Liste hc Erwähnen 2 Optionen (I 1 weitere hinzufügen würde), und ich würde gerne wissen, ob so etwas wie dies bereits möglich ist, mit Hazelcast 3.2 oder 3.3:

  1. Momentan ruft das MapStore-Interface nur Daten oder Updates vom lokalen Knoten ab. Wäre es möglich, die MapStore-Schnittstelle für jede Speicheraktion des gesamten Clusters zu benachrichtigen? Oder ist das vielleicht schon mit etwas Zuhörerzauberei möglich? Vielleicht kann ich Haselnuss zwingen, alle Objekte in eine Partition zu legen und 1 Kopie auf jedem Knoten zu haben.

  2. Wenn ich z.B. 2 Knoten, dann wird die MapStore-Schnittstelle korrekt mit meinen lokalen Datenbanken für Knoten1 und dann für Knoten2 aufgerufen. Wenn jedoch beide Knoten zusammenkommen, werden die Daten von Knoten2 entfernt, da Hazelcast annimmt, dass nur der Hauptknoten korrekt sein kann. Kann ich Haselnuss unterrichten, die Daten von beiden Knoten zu akzeptieren?

Antwort

0

Es scheint not easily possible zu sein:

Die persistance Schicht für Hazelcast es erfordert eine Art von zentralen Speicher zu sein. Wie Datenbank oder freigegebene Datei.

oder suchen Sie here oder . Schaut sich in OrientDB an, das Hazelcast verwendet und auf Disc bleibt.

1

Vielleicht zwei Möglichkeiten:

1) Dig in, wie Partitionierung in Hazelcast funktioniert. Ich denke, es könnte einen Weg geben, MapLoader pro Partition zu haben, und den Knoten zwingen, nur seine eigenen Partitionen zu laden, dies würde Konflikte lösen.

2) Wenn der Knoten wieder online ist, interagieren Sie mit dem Hazelcast-Cluster, bevor der Knoten hinzugefügt wird. Sie könnten zwei Sätze eins von HZ Sekunde von MapDB zusammenführen.

3) zwingen Hazelcast, alle Daten auf jedem Knoten zu speichern. Stellen Sie die Partitionsnummer auf 1 oder etwas ein

+0

Danke - Optionen sind gute Ideen, aber ich würde gerne wissen, wie ich sowas machen würde und ob das überhaupt möglich ist. – Karussell

+0

Auch sah Ihr Projekt :) https://github.com/jankotek/mapdb-hz-offheap – Karussell

2

Laut Hazelcast 3.3 Dokumentation die MapLoader Initialisierung Fluss ist die folgende:

Wenn getMap() zuerst von einem beliebigen Knoten aufgerufen wird, wird eine Initialisierung je nach dem Wert von InitialLoadMode beginnt. Wenn es als EAGER eingestellt ist, startet die Initialisierung . Wenn es als LAZY gesetzt ist, startet die Initialisierung tatsächlich nicht , aber die Daten werden jedes Mal geladen, wenn eine Partitionsladung abgeschlossen ist.

  1. Hazelcast wird MapLoader.loadAllKeys() aufrufen, auf jedem Knoten alle Ihre Schlüssel zu erhalten
  2. Jeder Knoten wird die Liste der Schlüssel herauszufinden es
  3. Jeder Knoten durch den Aufruf von all seinen Besitz Schlüssel besitzt lädt MapLoader.loadAll (Schlüssel)
  4. Jeder Knoten stellt seinen Besitz Einträge in die Karte durch den Aufruf IMap.putTransient (Schlüssel, Wert)

Obiges bedeutet, dass wenn die Knoten in einer anderen Reihenfolge starten, die Schlüssel auch anders verteilt werden. Somit findet jeder Knoten nicht alle/einige der zugewiesenen Schlüssel in seinem lokalen Speicher. Sie sollten dies überprüfen können, indem Sie in HCMapStore.loadAllKeys und HCMapStore.loadAll Haltepunkte setzen und die Schlüssel, die Sie mit den Schlüsseln abrufen, vergleichen.

Meiner Meinung nach widerspricht das, was Sie erreichen möchten, dem Konzept des verteilten Caches mit Ausfallsicherheitseigenschaften wie Hazelcast und ist daher unmöglich. I.e. Wenn ein Knoten ausfällt (aus irgendeinem Grund ausfällt oder die Verbindung getrennt wird), wird der Cluster neu ausgerichtet, indem Teile der Daten verschoben werden. Der gleiche Prozess wird jedes Mal ausgeführt, wenn ein Knoten einem Cluster beitritt. Im Falle von Cluster-Änderungen wird der lokale Backstore des verlorenen Knotens nicht mehr aktuell.

Hazelcast-Cluster ist von Natur aus dynamisch und kann daher nicht auf Backstore mit statischer verteilter Topologie zurückgreifen. Im Wesentlichen benötigen Sie einen gemeinsamen Backstore, damit er mit dem dynamischen Hascast-Cluster funktioniert. Der Backstore kann ebenfalls verteilt werden, z. Cassandra, aber seine Topologie muss unabhängig von der Cache-Cluster-Topologie sein.

UPDATE: Es scheint mir, dass das, was Sie erreichen möchten, logischer in Form eines verteilten Datenspeichers (über MapDB) mit lokalem Caching ist.

Ich hoffe, das hilft.

1

Es ist möglich, Daten auf allen Knoten zu laden, aber im Moment müssen Sie es manuell tun.

auf jedem Knoten:

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 

Aber wie MapStore in der Mailing-Liste erwähnt wird, nicht wirklich soll auf diese Weise verwendet werden. Beachten Sie auch, dass Backups auf diese Weise nicht auf dem Datenträger gespeichert werden. Wenn Sie also Ihren Cluster neu starten und die Festplatte eines Knotens stirbt, gehen diese Einträge verloren.

+0

Vielen Dank! Dies bedeutet, dass es ein "Scherben" -Konzept namens "Partitionen" gibt, aber kein Replikat-Konzept? Wenn diese Einträge verloren gehen, wie stellt HC sicher, dass es keine Daten verliert, wenn ein Knoten stirbt? – Karussell

+0

@Karussell Einträge werden im Speicher auf mehreren Knoten gesichert. Wenn ein Knoten stirbt, während der Cluster in Ordnung ist. Aber mit dieser Art von lokaler Persistenz werden Backups nicht auf der Festplatte gespeichert. Also, wenn Sie Ihren Cluster herunterfahren, dann versuchen Sie es zu starten und ein Datenträger startet nicht, weil sein tot ... – Andrejs

+0

Ich sehe und es gibt keine Möglichkeit, auf diese In-Memory-Backup irgendwie zuzugreifen? – Karussell