一问读懂Apache Kudu( 二 )


为了实现external consistency,Kudu提供了两种方式:

  1. 在client之间传播timestamp token 。在一个client完成一次写入后,会得到一个timestamp token,然后这个client把这个token传播到其他client,这样其他client就可以通过token取到最新数据了 。不过这个方式的复杂度很高 。
  2. 通过commit-wait方式,这有些类似于google的Spanner 。但是目前基于NTP的commit-wait方式延迟实在有点高 。不过Kudu相信,随着Spanner的出现,未来几年内基于real-time clock的技术将会逐渐成熟 。
三、Kudu的架构
与HDFS和HBase相似,Kudu使用单个的Master节点,用来管理集群的元数据,并且使用任意数量的Tablet Server节点用来存储实际数据 。可以部署多个Master节点来提高容错性 。
一问读懂Apache Kudu

文章插图
 
【一问读懂Apache Kudu】Kudu架构图,图片来源于官网
Master
Kudu的master节点负责整个集群的元数据管理和服务协调 。它承担着以下功能:
  1. 作为catalog manager,master节点管理着集群中所有table和tablet的schema及一些其他的元数据 。
  2. 作为cluster coordinator,master节点追踪着所有server节点是否存活,并且当server节点挂掉后协调数据的重新分布 。
  3. 作为tablet directory,master跟踪每个tablet的位置 。
Catalog Manager
Kudu的master节点会持有一个单tablet的table——catalog table,但是用户是不能直接访问的 。master将内部的catalog信息写入该tablet,并且将整个catalog的信息缓存到内存中 。随着现在商用服务器上的内存越来越大,并且元数据信息占用的空间其实并不大,所以master不容易存在性能瓶颈 。catalog table保存了所有table的schema的版本以及table的状态(创建、运行、删除等) 。
Cluster Coordination
Kudu集群中的每个tablet server都需要配置master的主机名列表 。当集群启动时,tablet server会向master注册,并发送所有tablet的信息 。tablet server第一次向master发送信息时会发送所有tablet的全量信息,后续每次发送则只会发送增量信息,仅包含新创建、删除或修改的tablet的信息 。
作为cluster coordination,master只是集群状态的观察者 。对于tablet server中tablet的副本位置、Raft配置和schema版本等信息的控制和修改由tablet server自身完成 。master只需要下发命令,tablet server执行成功后会自动上报处理的结果 。
Tablet Directory
因为master上缓存了集群的元数据,所以client读写数据的时候,肯定是要通过master才能获取到tablet的位置等信息 。但是如果每次读写都要通过master节点的话,那master就会变成这个集群的性能瓶颈,所以client会在本地缓存一份它需要访问的tablet的位置信息,这样就不用每次读写都从master中获取 。
因为tablet的位置可能也会发生变化(比如某个tablet server节点crash掉了),所以当tablet的位置发生变化的时候,client会收到相应的通知,然后再去master上获取一份新的元数据信息 。
Tablet存储
在数据存储方面,Kudu选择完全由自己实现,而没有借助于已有的开源方案 。tablet存储主要想要实现的目标为:
  1. 快速的列扫描 。
  2. 低延迟的随机读写 。
  3. 一致性的性能 。
RowSets
在Kudu中,tablet被细分为更小的单元,叫做RowSets 。一些RowSet仅存在于内存中,被称为MemRowSets,而另一些则同时使用内存和硬盘,被称为DiskRowSets 。任何一行未被删除的数据都只能存在于一个RowSet中 。
无论任何时候,一个tablet仅有一个MemRowSet用来保存最新插入的数据,并且有一个后台线程会定期把内存中的数据flush到硬盘上 。
当一个MemRowSet被flush到硬盘上以后,一个新的MemRowSet会替代它 。而原有的MemRowSet会变成一到多个DiskRowSet 。flush操作是完全同步进行的,在进行flush时,client同样可以进行读写操作 。
MemRowSet
MemRowSets是一个可以被并发访问并进行过锁优化的B-tree,主要是基于MassTree来设计的,但存在几点不同:
  1. Kudu并不支持直接删除操作,由于使用了MVCC,所以在Kudu中删除操作其实是插入一条标志着删除的数据,这样就可以推迟删除操作 。
  2. 类似删除操作,Kudu也不支持原地更新操作 。
  3. 将tree的leaf链接起来,就像B+-tree 。这一步关键的操作可以明显地提升scan操作的性能 。
  4. 没有实现字典树(trie树),而是只用了单个tree,因为Kudu并不适用于极高的随机读写的场景 。


    推荐阅读