- 场景
- MetaServer是一个单独的服务,其管理了graphspce/partition的元信息(当然还有Host、Schema元信息)
- KVStore存储其负责的partition数据, 一个host上只有一个KVStore。KVStore中负责的graphspace和partition元信息存储在MetaServer中。KVStore实例化后会根据host从MetServer中获取其管理的Partition元信息。然后根据元数据信息为每个graph创建对应的Engine和Partition实例(KVStore为Storage的底层存储接口),用户对顶点和边的增删查改操作,到KVStore层都转换成对具体某个partition的操作(KVStore的对外方法中都有spaceid和partitionID两个参数),在每个操作中都需要先根据spaceid和partitionID两个参数找到对应Engine或Partition,然后在调用Engine或Partition实例执行具体的操作。所以当MetaServer中关于host的元信息变了,那么KVStore就应该对其影响到的Engine和Partition实例做修改。
- 比如,有5个graphspace,每个space有10个partition,每个partition 3副本,共6台机器(host), 那么host=125.45.124.201机器在MetaServer中负责的partition元信息可能为如下,但是经过一段时间后这个元信息可能会变化(用户通过MetaServer进行了修改),那么此时KVStore需要知道这个修改。
{
host1: 125.45.124.201
spaces : [
{ spaceid: 1, part: [ {id :2, peers: [host3, host6] }, {id :3, peers: [host5, host2] } ] },
{ spaceid: 2, part: [ {id :1, peers: [host1, host6] }, {id :5, peers: [host5, host2] } ] },
{ spaceid: 5, part: [ {id :7, peers: [host3, host6] } ] }
]
}
-
MetaServer和MetaClient是基于Thrift协议的服务端和客户端,KVStore是运行在Storage服务中的存储library,KVStore中通过MetaClient来和MetaServer服务做交互。
-
类设计
image.png
![](https://img.haomeiwen.com/i3458176/b71c9fd4cf70e562.png)
-
MetaChangedListener接口(观察者接口):将MetaServer中graphspace/partition变化产生的动作抽象成接口,实现该接口就可以处理相应的变化。
-
MetaClient类(被观察者):
-
对用户提供了createSpace、dropSpace操作(目前移动/删除某个space的Partition操作还没有),这几个操作会有graph层调用,其会影响graphspace/partition的变化。
-
MetaClient通过registerListener来注册监听者。
-
client从MetaServer获取到host上的Part元信息后会缓存在localcache_中,这样当KVStore中需要获取其元数据信息时可以从缓存中获取,缓存也会定期更新。
-
graphspace/partition的变化的获取,MetaClient采用pull的方式来实现,即其会开启一个线程定期的执行loadDataThreadFunc方法,该方法会获取MetaServer中listener所在host管理的最新garphspace/partition元信息,然后和client端之前缓存的旧的元信息做比较就可以得到此时该host上graphspace/partiton的变化情况,得到变化情况后就调用listener相应方法通知观察者,最后在将最新元信息的结果缓存在client端。
- push方式应该是:MetaServer层执行createSpace、dropSpace等操作后就主动去通知KVStore。
-
-
PartManager/Handler接口: 将对Partition的管理操作封装成一个接口,KVStore实现类通过PartManager接口实现对Part元信息的查询/判断操作,从而为每个graph创建对应的Engine和Partition实例 ,至于对Part元信息的变化的处理操作又单独封装成了一个Handler接口(包含了对Part和Space的增加/删除操作)。为什么单独抽象出一个Handler?答:PartManager可以有基于内存的实现,该实现中每个host管理的Part信息不是来自MetaServer的,而是程序启动时设置好的,不可修改,所以此时不存在对Part/graph的修改操作。(基于内存的实现后期会废弃掉)。
-
MetaServerBasedPartManager ( 具体的观察者): 基于MetaClient的PartManager接口实现类,同时也实现了MetaChangedListener接口。
-
对PartManager的实现:通过MetaClient提供的方法来实现,MetaClient提供的方法实现中是基于本地缓存数据。
-
对MetaChangedListener的实现:metaClient会通过registerListener方法注册观察者,MetaServerBasedPartManager没有通过自己来处理Part/Space的变化情况,而是通过registerHandler来处理,该Handler收到Part/Space的变化情况后可以对其受影响Engine/Partition实例做出相应改变。该handler的实现类之一是NebulaStore.
-
-
KVStore接口:封装了面向Storage层对graph的kv操作,这些操作都需要指定spaceID和parttitionID。
-
KVOptions类:对KVStore实例化所需参数的一个封装,包含host(KVStore实例的host信息)、dataPaths(KVStore数据存储路径)、partManager(KVStore依赖的PartManger类)
-
NebulaStore实现类:KVStore、Handler接口实现类,其依赖PartManager组件提供Part的元信息数据。
-
KVStore接口实现:基于RocksDb实现,通过PartManager获取host的Part元信息,然后为graph创建对应的Engine和Partition实例,比如:dataPaths中有两个目录,则NebulaStore会为每个Graph创建两个KVEngine实例,并将其Partition实例按照平均原则分配给这两个KVEngine,KVStore的KV操作实际就是先根据spaceid,partId找到对应KVEngine或Partition实例,然后在调用KVEngine或Partition的操作(增删改操作会调用Partition实例,因为需要先通过Raft在实现副本间的一致性,然后在调用KVEngine操作)
-
Handler接口实现:感知到Part元信息变化后,就对涉及到KVEngine/Part实例做出调整。
-
---待细化中
网友评论