美文网首页
Multi-Raft PlaceDriver

Multi-Raft PlaceDriver

作者: NazgulSun | 来源:发表于2021-09-06 19:10 被阅读0次

为什么需要pd(place driver)

在multiple-raft 里面 需要有一个中心化的机制,来协调多个raft-group的数据管理,比如parition 扩容split,merge;
数据routing等;以及一些监控和管理;ti-kv 中实现了multiple-raft,有一个 pd 的模块来管理整个集群的元素据;
他们使用的是etcd 这样一个分布式的存储,作为meta管理;etcd 由于被k8s使用,而变得越来越流行,在服务发现等元数据领域
被人大量使用,有点代替zookeep的趋势;etcd 分布式容错,也使用的raft协议,ti-kv使用etcd是自然而然的事情;

mutipl-raft在图数据中应用

目前c++生态的nebula被认为是开源里面速度最开的,各个大厂如美团等都在上面构建自己的应用;
在java 生态里面,主要是hugegraph,主要使用第三方外存,所以速度上没有nebula快,因为nebula 自己用rocksdb做kv,实现了自己的存储层,
同时做了很多的计算下推的优化,速度更快; nebula有一个meta service 的服务,来管理 raft 层的多个partition,起到的作用
类似于ti-kv 的pd;目前hugegraph 实现了single-raft 版本的 存储支持;
我学习mutple-raft的一个初衷就是想有机会使用hugegraph branch构建一个java 生态的,性能和nebula 一样的数据库,且能够支持gremlin;

我在github上search,java下的multiple-raft的项目很少;
https://github.com/PZXWHU/MultiRaft 貌似对ti-kv中的概念做了部分实现,先来学习一下他的思想;
万丈高楼平地起。

pd 主要的概念:

  • 存储,我们知道pd需要管理meta data,这些meta必须是要高可用的;在这个demo项目中,使用的是rocksdb,单机作为演示;
    我们看到ti-kv,nebula都是高可用版本的,我的打算未来集成etcd管理meta;

  • meta 信息。 主要包括store,region(partition)一个store 通常是一个机器,一个store 下面需要包含多个分区;
    一个region,是对一个分区的描述,比如 start-end_key; epoch, 等等;

  • RegionRouteTable: region的路由表; 就是会记录所有的region信息,当用户要查询一个 key的时候,那么会通过这个表获取
    到具体操作的region;并且随着集群的变更,动态的更新table的状态。

  • pdService: pd 和各个集群节点rpc通信的服务,比如和 store节点/region节点,比如heartbeat等;
    我们先看看pdservice主要的接口:

public interface PlaceDriverService {

    StoreHeartbeatResponse storeHeartbeat(StoreHeartbeatRequest request);

    RegionHeartbeatResponse regionHeartbeat(RegionHeartbeatRequest request);

    StoreInfo getStoreInfo(long storeId);

    void setStoreInfo(StoreInfo storeInfo);

    RegionInfo getRegionInfo(long regionId);

    void setRegionInfo(RegionInfo regionInfo);

    Long createRegionId();

    RegionInfo findRegionByKey(byte[] key);

    List<RegionInfo> findRegionsByKeyRange(byte[] startKey, byte[] endKey);

}

通常在HeartBeatResponse里面,会更具集群的状态下发命令给节点,比如某个分区达到了最大的size,就可能需要分裂split;
或者是集群扩容等时候,需要动态管理partition;这些都是很复杂的事情;
最后palceDriverService,通过Rpc框架发布出去,就可以和集群节点开始通信了;

集群初始化的时候,可以指定parition,store的个数,这样我们就有一个初始化的,RegionRoutable:
我们可以看看,如何实现一个基于 range-key 的routeTable;
核心的数据结构:

     private NavigableMap<byte[], Long> rangeTable = 
        new ConcurrentSkipListMap<>(ByteUtils.BYTES_LEXICO_COMPARATOR);

    public RegionInfo findRegionByKey(byte[] key) {
        if (key == null) return null;
        final Map.Entry<byte[], Long> entry = this.rangeTable.floorEntry(key);
        /*System.out.println(ByteUtils.compare(key,
                entry.getKey()));
        System.out.println(ByteUtils.bytesToInteger(key) + "  " +
                ByteUtils.bytesToInteger(entry.getKey()));*/
        return metaStorage.getRegionInfo(entry.getValue());
    }
    /**
     * Returns the list of regions covered by startKey and endKey.
     */
    public List<RegionInfo> findRegionsByKeyRange(byte[] startKey, byte[] endKey){

        final NavigableMap<byte[], Long> subRegionMap;
        if (endKey == null) {
            subRegionMap = this.rangeTable.tailMap(startKey, false);
        } else {
            subRegionMap = this.rangeTable.subMap(startKey, false, endKey, true);
        }
        List<RegionInfo> res = new ArrayList<>(subRegionMap.size() + 1);
        for(long regionId : subRegionMap.values())
            res.add(metaStorage.getRegionInfo(regionId));

        Map.Entry<byte[], Long> entry = this.rangeTable.floorEntry(startKey);
        res.add(metaStorage.getRegionInfo(entry.getValue()));

        return res;

    }

NavigableMap: 是 sortedMap的子接口;有很多个方法,可以查看一些 map-view; SkipListMAP 是sortedMap 多线程的一个
条约表的实现;他存储的是startKey-RegionId的一个映射;

我们查找 startKey对应的region的时候; floorEntry的方法;对应比 小于等Key 的最接近的 Entry;
tailMap, 为大于等于Key 的所有mapView;
navigableMap的方法可以参考: https://blog.csdn.net/cgsyck/article/details/108493266, 实现环一致hash还是很有用;

相关文章

  • Multi-Raft PlaceDriver

    为什么需要pd(place driver) 在multiple-raft 里面 需要有一个中心化的机制,来协调多个...

网友评论

      本文标题:Multi-Raft PlaceDriver

      本文链接:https://www.haomeiwen.com/subject/bqlywltx.html