2014-09-02 13 views
5

Ho implementato un servizio di nocciolo che memorizza i suoi dati in istanze mapdb locali tramite MapStoreFactory e newMapLoader. In questo modo i tasti possono essere caricati se un riavvio cluster è necessaria:Hazelcast e MapDB - implementazione di un semplice database distribuito

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

Il problema che sto ora di fronte è che il metodo loadAllKeys dell'interfaccia MapLoader da Hazelcast richiede di restituire tutti i tasti del intero cluster Ma ogni il nodo memorizza SOLO gli oggetti che possiede.

Esempio: ho due nodi e memorizzo 8 oggetti, quindi ad es. 5 oggetti sono memorizzati nel mapdb del nodo 1 e 3 nel mapdb del nodo2. Quale oggetto è di proprietà di quale nodo è deciso da Hazelcast, penso. Ora al riavvio node1 restituirà 5 chiavi per loadAllKeys e node2 restituirà 3. Hazelcast decide di ignorare i 3 elementi ei dati sono "persi".

Quale potrebbe essere una buona soluzione a questo?

Aggiornamento per taglie: Here ho chiesto questo sul hc mailing list di nota 2 opzioni (io aggiungo di più 1) e vorrei sapere se qualcosa di simile è già possibile con Hazelcast 3.2 o 3.3:

  1. Attualmente l'interfaccia MapStore riceve solo dati o aggiornamenti dal nodo locale. Sarebbe possibile notificare all'interfaccia MapStore ogni azione di archiviazione del cluster completo? O forse questo è già possibile con qualche magia da ascoltatore? Forse posso costringere il nocciola a mettere tutti gli oggetti in una partizione e avere 1 copia su ogni nodo.

  2. Se riprendo ad es. 2 nodi quindi l'interfaccia di MapStore viene chiamata correttamente con i miei database locali per node1 e quindi per node2. Ma quando entrambi i nodi si uniranno, i dati del nodo2 verranno rimossi poiché Hazelcast presume che solo il nodo principale possa essere corretto. Posso insegnare ai hazelcast ad accettare i dati da entrambi i nodi?

risposta

0

Sembra essere not easily possible: strato

La persistenza di Hazelcast impone di essere una sorta di archiviazione centrale. Come database o file condiviso.

o look here o here. Esaminerà OrientDB che utilizza Hazelcast e continua a disc.

1

Forse due opzioni:

1) scavare come il partizionamento lavora in Hazelcast. Penso che ci potrebbe essere un modo per avere MapLoader per partizione e forzare il nodo a caricare solo le sue partizioni, questo risolverebbe i conflitti.

2) quando il nodo ritorna online, interagire con il cluster Hazelcast prima di aggiungere il nodo. È possibile unire due set uno da HZ secondo da MapDB.

3) forzare Hazelcast a memorizzare tutti i dati su ogni nodo. Imposta il numero di partizione su 1 o su qualcosa

+0

Grazie - le opzioni sono buone idee, ma mi piacerebbe sapere come farei una cosa del genere e se ciò è possibile a tutti. – Karussell

+0

Hai visto anche il tuo progetto :) https://github.com/jankotek/mapdb-hz-offheap – Karussell

2

Secondo Hazelcast 3.3 documentazione flusso inizializzazione la MapLoader è la seguente:

Quando getMap() viene dapprima chiamato da qualsiasi nodo, inizializzazione inizierà seconda del valore di InitialLoadMode. Se è impostato come EAGER, inizia l'inizializzazione . Se è impostato come LAZY, l'inizializzazione in realtà non viene avviata, ma i dati vengono caricati ogni volta che il caricamento della partizione è completato.

  1. Hazelcast chiamerà MapLoader.loadAllKeys() per ottenere tutte le chiavi sulla ogni nodo
  2. Ogni nodo sarà capire la lista delle chiavi di sua proprietà
  3. Ogni nodo caricherà tutte le sue chiavi di proprietà chiamando MapLoader.loadAll (tasti)
  4. Ogni nodo mette le sue voci di proprietà della mappa chiamando IMap.putTransient (chiave, valore)

Quanto sopra implica che se i nodi si avviano in un ordine diverso, anche le chiavi verranno distribuite in modo diverso. Pertanto, ciascun nodo non troverà tutte/alcune delle chiavi assegnate nel suo archivio locale. Dovresti essere in grado di verificarlo impostando i punti di interruzione in HCMapStore.loadAllKeys e HCMapStore.loadAll e confrontare le chiavi che vengono recuperate con le chiavi.

A mio parere, quello che stai cercando di ottenere contraddice il concetto di cache distribuita con caratteristiche di resilienza come Hazelcast e quindi è impossibile. Cioè quando un nodo scompare (fallisce o si disconnette per qualsiasi motivo) il cluster si riequilibrerà spostando parti di dati in giro, lo stesso processo si verificherà ogni volta che un nodo entra in un cluster. Quindi, in caso di modifiche al cluster, il backstore locale del nodo perso diventa obsoleto.

Il cluster Hazelcast è dinamico per natura, quindi non può fare affidamento sul backstore con topologia distribuita statica. In sostanza, è necessario disporre di un backstore condiviso per farlo funzionare con il cluster di Hazelcast dinamico. Anche il backstore può essere distribuito, ad es. cassandra, ma la sua topologia deve essere indipendente dalla topologia del cluster di cache.

AGGIORNAMENTO: Mi sembra che quello che stai cercando di ottenere sia più logico sotto forma di un datastore distribuito (in cima a MapDB) con memorizzazione nella cache locale.

Spero che questo aiuti.

1

È possibile caricare i dati memorizzati su tutti i nodi ma al momento dovresti farlo manualmente.

In ogni nodo:

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 

Ma, come accennato nella mailing list MapStore non è realmente destinato ad essere utilizzato in questo modo. Inoltre, tenere presente che i backup non vengono mantenuti su disco in questo modo. Quindi, se si riavvia il cluster e il disco su un nodo muore, tali voci andranno perse.

+0

Grazie! Ciò significa che esiste un concetto di "shard" chiamato "partizioni", ma nessun concetto di replica? Se queste voci andranno perse, in che modo HC si assicura che non perda dati se un nodo muore? – Karussell

+0

@Karussell Le voci vengono salvate in memoria su più nodi. Se un nodo muore mentre il cluster sta funzionando correttamente. Ma con questo tipo di backup di persistenza locale non vengono memorizzati su disco. Quindi se spegnete il vostro cluster, provate ad avviarlo e un disco non parte perché è morto ... – Andrejs

+0

Vedo e non c'è modo di accedere in qualche modo a questo backup in memoria? – Karussell

Problemi correlati