《云原生一站式数据库技术与实践》——二、云原生数据仓库AnalyticDB MySQL高性能存储引擎(4) https://developer.aliyun.com/article/1231656?groupCode=aliyundb
数据版本管理与build 紧密联系,基本基于build 来实现。
实时数仓的一个典型使用场景为从TP 库同步数据到AP 库,用户希望TP 库的所有数据更新都能实时的在AP 库上得到体现。现在假设一个场景:用户在TP 库上执行了一条DDL,该DDL在TP 可能耗时数十分钟。其后立即更新了大量数据并期望AP侧能够立即对这些数据进行查询。在该场景下要求DDL能够在AP 侧做到准实时或毫秒级执行。
基于以上需求,我们首先进行了毫秒级的逻辑适配。逻辑适配完成之后,存储引擎可以接收新模式下的写入和查询请求,此时数据并没有得到物理上的修改。之后再通过build 过程,对数据文件依据DDL进行真实的物理变更。执行时,若将全量数据进行重建会消耗大量时间以及资源,因此仅对有修改的分区进行重建。同时,为了满足客户不同的业务场景,也支持用户通过force partition 指定重建区分区。分区管理主要包括生命周期管理以及冷热分区转化。
见上图右侧在shard1 的定义里,lifecycle=3表示有三个分区,hot window=2 表示有两个热分区。v100 里有7-31、7-30、7-29 三天的数据,其中7-29 的为冷数据。8-1 的实时数据写入后,执行build,将7-29 的数据淘汰,产生8-1 的新的历史数据。同时,要进行冷热转换,将7-30 的数据从热数据转换为冷数据。
转换完成之后,为了进一步保证主从副本的一致性,leader做完裁决之后会将裁决信息作为layout file 传到之上,从副本进行apply,在复用了build 的结果的同时也复用了整体分区管理的决策。
冷热的转化本质是分区的存储介质变化。本地存储介质一般为ESSD,上传后一般为OSS。数据从本地到DFS 并不是仅进行简单的上传即可进行高效的查询。针对远程数据文件的管理,我们也做了一系列的优化。
如上图左侧所示,上层为存储引擎,下层为DFS。从存储引擎到DFS,首先会经过SSD Buffer。DFS 对小文件的读写并不友好,比如常见的索引构建有很多类似于外排的操作涉及大量的随机读写。若此类操作直接打穿到DFS 上,则导致IOPS 非常高,对DFS 非常不友好。因此,我们实现了SSD Buffer,先在本地聚合,将需要预处理的数据在本地完构建。之后,将随机的小文件读写转换成流式的、批量的、高吞吐的顺序写上传到DFS。
写的过程中,会经过Tar FileSystem 进行打包并增加一个cache,该cache 为tar文件内子文件路径到该文件在tar 内的位置的映射。Index 置于文件尾部,一旦打开文件则会将Index 加载到cache中。cache的优势在于,在打开某个子文件时,可以少读一次元信息,同时,使得Meta 类的操作不需要再读远程,而是可以直接在本地处理,对文件的meta 类操作性能有显著提升。
下面的ADB FileSystem Interface 是统一的文件接口层,能够屏蔽下层存储的远程实现。存储引擎只感知通用文件接口,ADB FileSystem Interface会进行具体转换自适应的操作远程文件存储或对象存储。
读取时,经过Tar FileSystem 和ADB FileSystem Interface,会有SSD Cache,做了本地文件块到远程文件的映射,能够深度感知IO 模型,IO 模型可以分为三类:
第一类,Meta 类操作,比如获取block位置信息等导致的随机读。
第二类,Query,分为index search(随机读)和data cursor(高吞吐的数据扫描)。
第三类,build,高吞吐的顺序读。
SSD Cache针对以上三种类型分别分配了独立的cache,主要包括独立的磁盘空间管理、独立的淘汰队列、独立的block size,彼此互不干扰。引擎侧向下发query 时,会携带hint 信息,用于判断应该使用哪种cache。
如果发生了cache miss,会先经过Perfetch Service,它与IO 模型紧密相连,能够感知query 的plan,可以并发地进行预取,进一步加快对远程文件的读取性能。
内存控制主要防止query 过于复杂,导致查询负载较高,最终导致整体存储节点的
负载过高。