Java Hazelcast和MapDB—实现一个简单的分布式数据库

Java Hazelcast和MapDB—实现一个简单的分布式数据库,java,hazelcast,mapdb,nosql,Java,Hazelcast,Mapdb,Nosql,我已经实现了一个hazelcast服务,它通过MapStoreFactory和newMapLoader将数据存储到本地mapdb实例中。这样,如果需要重新启动群集,可以加载密钥: public class HCMapStore<V> implements MapStore<String, V> { Map<String, V> map; /** specify the mapdb e.g. via * DBMaker.newFileDB(new Fi

我已经实现了一个hazelcast服务,它通过MapStoreFactory和newMapLoader将数据存储到本地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;
}}
公共类HCMapStore实现MapStore{
地图;
/**指定mapdb,例如通过
*DBMaker.newFileDB(新文件(“mapdb”)).closeOnJvmShutdown().make()
*/
公共HCMapStore(数据库){
这个.db=db;
this.map=db.createHashMap(“someMapName”).makerGet();
}
//省略了其他一些存储方法
@凌驾
公共无效删除(字符串k){
logger.info(“删除,”+k);
地图。删除(k);
db.commit();
}
//地图加载器方法
@凌驾
公共V加载(字符串键){
logger.info(“加载,”+键);
返回map.get(key);
}
@凌驾
公共集合loadAllKeys(){
logger.info(“loadAllKeys”);
返回map.keySet();
}
@凌驾
公共地图加载全部(集合键){
logger.info(“loadAll,”+键);
Map partialMap=newhashmap();
用于(字符串k:键){
partialMap.put(k,map.get(k));
}
返回partialMap;
}}
我现在面临的问题是来自hazelcast的MapLoader接口的loadAllKeys方法需要返回整个集群的所有键,但每个节点只存储它拥有的对象

示例:我有两个节点,存储了8个对象,例如,5个对象存储在node1的mapdb中,3个存储在node2的mapdb中。我认为哪个节点拥有哪个对象是由hazelcast决定的。现在重新启动时,node1将为loadAllKeys返回5个键,node2将返回3个键。Hazelcast决定忽略这3项,数据“丢失”

有什么好的解决方案吗?

赏金更新:我在hc邮件列表中询问了这个问题,提到了2个选项(我将再添加1个),我想知道类似的内容是否已经在hazelcast 3.2或3.3中实现:

  • 当前,MapStore接口仅从本地节点获取数据或更新。是否可以将整个集群的每个存储操作通知MapStore接口?或者,也许这已经是可能的一些听众魔术?也许我可以强制hazelcast将所有对象放在一个分区中,每个节点上有一个副本

  • 如果我重新启动(例如2个节点),则会使用我的本地数据库为node1和node2正确调用MapStore接口。但当两个节点都加入时,节点2的数据将被删除,因为Hazelcast假定只有主节点是正确的。我可以教hazelcast接受来自两个节点的数据吗

  • 似乎是:

    Hazelcast的持久层要求它是某种 中央存储器。比如数据库,或者共享文件

    或看或看。将查看OrientDB,它正在使用Hazelcast并一直保存到光盘

    也许有两种选择:

    1) 深入了解Hazelcast中分区是如何工作的。我认为有一种方法可以让每个分区都有MapLoader,并强制节点只加载自己的分区,这将解决冲突

    2) 当节点恢复联机时,在添加节点之前与Hazelcast群集交互。您可以合并两个集合,一个来自HZ,另一个来自MapDB


    3) 强制Hazelcast在每个节点上存储所有数据。根据Hazelcast 3.3文档,将分区号设置为1或其他值 MapLoader初始化流程如下所示:

    当第一次从任何节点调用getMap()时,初始化将开始 取决于InitialLoadMode的值。如果设置为渴望, 初始化开始。如果设置为LAZY,初始化实际上 不会启动,但每次加载分区时都会加载数据 完成

  • Hazelcast将调用MapLoader.loadAllKeys()以获取所有密钥 每个节点
  • 每个节点将计算出它拥有的密钥列表
  • 每个节点将通过调用 MapLoader.loadAll(键)
  • 每个节点通过调用 IMap.putTransient(键、值)
  • 上述情况意味着,如果节点以不同的顺序启动,那么密钥的分布也将不同。因此,每个节点不会在其本地存储中找到所有/部分分配的密钥。您应该能够通过在HCMapStore.loadAllKeys和HCMapStore.loadAll中设置断点来验证它,并将检索到的密钥与所访问的密钥进行比较

    在我看来,您试图实现的目标与具有Hazelcast等弹性特征的分布式缓存的概念相矛盾,因此是不可能的。也就是说,当一个节点离开(由于任何原因发生故障或断开连接)时,集群将通过移动部分数据来重新平衡,每次节点加入集群时都会发生相同的过程。因此,在集群发生变化的情况下,丢失节点的本地后台将过时

    Hazelcast集群本质上是动态的,因此它不能依赖于静态分布式拓扑的backstore。本质上,您需要有一个共享的后台,以使其与DynamicHazelcast集群一起工作。backstore也可以是分布式的,例如cassandra,但其拓扑必须独立于缓存集群拓扑

    更新:在我看来,您试图实现的是一个具有本地缓存的分布式数据存储(位于MapDB之上)形式的逻辑性更强


    我希望这会有所帮助。

    可以加载存储在所有节点上的数据,但目前必须手动加载

    在每个节点上:

    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
    中提到的那样,并不是真正打算这样使用的。还要注意,备份不会以这种方式持久化到磁盘。因此,如果重新启动群集,一个节点上的磁盘死亡,这些条目将丢失。

    谢谢-选项是好主意,但我想知道我将如何做这样的事情,以及这是否可能。谢谢!这意味着有一个“嘘”