kudu的读请求,同样首先根据主键范围定位到目标tablet,再定位到具体的rowset。然后分别加载baseData,deltaFile, 以及memrowset之后得到最终数据并返回。
baseData就是insert操作插入memRowset中,并且flush产生的数据。这个是作为基准数据。
接下来需要访问deltaStore。Delta数据部分包含REDO与UNDO两部分:这里的REDO与UNDO与关系型数据库中的REDO与UNDO日志不太相同。在关系型数据库中,REDO日志记录了更新后的数据,可以用来恢复尚未写入DataFile的已成功事务更新的数据。而UNDO日志用来记录事务更新之前的数据,可以用来在事务失败时进行回滚。
kudu中的REDO Delta Files包含了Base Data自上一次被Flush/Compaction之后的变更值。REDO Delta Files按照Timestamp顺序排列。而UNDO Delta Files包含了Base Data自上一次Flush/Compaction之前的变更值。这样才可以保障基于一个旧Timestamp的查询能够看到一个一致性视图。UNDO按照Timestamp倒序排列。根据用户查询的timestamp决定在base data的基础上apply redo file或者apply undo file,得到最终数据。
另外还要再查询一次memrowset,因为数据也有可能还在memrowset中尚未落盘。之后就可以将数据返回到client。
下面附上几个scan操作的可选配置项:
kudu::client::KuduScanner::ReadMode
READ_LATEST 默认该选项。总是当前时间戳读取最新数据。等效于read_committed 。性能较好,存在write skew问题。
READ_AT_SNAPSHOT 读取指定时间戳的数据。若未指定则取当前时间戳。由于需要等待时间戳小于指定时间戳的操作完成,因此可能会有很高延迟。等效于repeatable read。
READ_YOUR_WRITES 如果客户端A写入了最新的值,那么A的后续操作都会读取到最新值。但是其他用户(比如B或者C)可能要过一会才能看到。
kudu::client::KuduClient::ReplicaSelection
LEADER_ONLY 默认选项,只选leader
CLOSEST_REPLICA 选择最近副本
FIRST_REPLICA 选择第一个副本
这里我觉得如果读大量数据,应该选择最近副本,减少网络IO。如果只读少量数据,应该选择leader最快。因为需要读memrowset。
kudu::client::KuduScanner::OrderModeUnordered 默认模式,乱序返回数据,性能更快。但是一旦出现故障则必须重新scan
Ordered 按主键排序返回数据。性能较差,但是出现故障后可以续传。