KVStore-MetaServer中的观察者模式

  • 场景
    • MetaServer是一个单独的服务,其管理了graphspce/partition的元信息(当然还有Host、Schema元信息)
    • KVStore存储其负责的partition数据, 一个host上只有一个KVStore。KVStore中负责的graphspace和partition元信息存储在MetaServer中。KVStore实例化后会根据host从MetServer中获取其管理的Partition元信息。然后根据元数据信息为每个graph创建对应的KVEngine和RaftPart实例(KVStore为Storage的底层存储接口)。
      • 用户对顶点和边的增删查改操作,到KVStore层都转换成对具体某个RaftPart或KVEngine的操作(KVStore的对外方法中都有spaceId和partitionID两个参数),在每个操作中都需要先根据spaceid和partitionID两个参数找到对应KVEngine或RaftPart,然后在调用KVEngine或RaftPart实例执行具体的操作。所以当MetaServer中关于某个host的Partition元信息变了,那么该host上的KVStore就应该对Partition元信息影响到的KVEngine和RaftPart实例做修改。
      • 比如,有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服务做交互。

  • 类设计


    KVStore-MetaServer中的观察者模式_第1张图片
    image.png
KVStore-MetaServer中的观察者模式_第2张图片
image.png
  • MetaChangedListener接口(观察者接口):将MetaServer中graphspace/partition变化产生的动作抽象成接口,实现该接口就可以感知到相应的变化。

  • MetaClient类(被观察者):

    • 对用户提供了createSpace、dropSpace操作(目前移动/删除某个space的Partition操作还没有),这几个操作会有graph层调用,其会影响graphspace/partition的变化。

    • MetaClient通过registerListener来注册观察者。

    • client从MetaServer获取到host上的Partition元信息后会缓存在本地,这样当KVStore中需要获取Partition元数据信息时可以从缓存中获取,缓存也会定期更新。

    • graphspace/partition的变化的感知,MetaClient采用pull的方式来实现,即其会开启一个线程定期的执行loadDataThreadFunc方法,该方法会获取MetaServer中Metaclient所在host管理的最新garphspace/partition元信息,然后和client端之前缓存的旧的元信息做比较就可以得到此时该host上graphspace/partiton的变化情况,得到变化情况后MetaClient就调用listener(注册的观察者)相应方法实现partition元信息变化的通知,接着会将最新partition元信息的结果缓存在client端。

      • push方式应该是:MetaServer层执行createSpace、dropSpace等操作后就主动去通知KVStore。
  • PartManager接口: 将对Partition的管理操作封装成一个接口,KVStore实现类通过PartManager接口实现对Partition元信息的查询/判断操作。(为什么不将PartManager中的方法直接放到KVStore中,而是单独封装成一个接口,然后KVStore依赖该接口来获取Partition元数据信息?答:遵循设计模式中的单一职责原则), KVStore通过PartManager组件可以得到自己负责的Partition元信息,从而为每个graph创建对应的KVEngine和RaftPart实例 。

  • Handler接口:实现MetaChangedListener可以让我们知道host上Partition元信息的变化情况,知道变化就要处理:即根据Partition元信息修改KVStore的KVEngine和RaftPart实例,那么这个处理动作有谁来做呢?答:有能力对KVEngine和RaftPart实例做出修改的类,即KVStore的实现类NebulaStore。 至于对Partition元信息的变化的处理操作又单独封装成了一个Handler接口, 实现这个Handler就可以对Partition元信息的变化做出处理了。总结:listener可以知道metaclient中partition元信息的变化,变化的处理交给handler来处理。

  • 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组件提供Partition的元信息数据。

    • KVStore接口实现:通过PartManager获取host的Partition元信息,然后为graph创建对应的KVEngine和Partition实例,比如:dataPaths中有两个目录,则NebulaStore会为每个Graph创建两个KVEngine实例,并将其RaftPart实例按照平均原则分配给这两个KVEngine,KVStore的KV操作实际就是先根据spaceid,partId找到对应KVEngine或RaftPart实例,然后在调用KVEngine或RaftPart的操作(增删改操作会调用RaftPart实例,因为需要先通过Raft实现副本间的一致性,然后在调用KVEngine操作,如果是查询操作则直接调用KVEngine操作)
      • KVEngine是一个接口,封装了KV操作,其中一个实现类是基于RocksDb的RocksEngine。

---待细化中

你可能感兴趣的:(KVStore-MetaServer中的观察者模式)