— hudi — 1 min read
最近专研Hudi,对于其两种存储类型感到迷惑,Copy on Write(COW)和Merge on Read(MOR),本篇文章用来简单总结一下两种方式的异同点。方便自己更好的理解。
先总结cow,这是一种较为普遍和通用的存储优化策略在Linux和jdk中都有使用,可以翻译为写时拷贝
。在wiki中的定义如下:
如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。
简单来说就是在程序运行阶段,所有线程(A,B,C)共享同一个内存数据,直到其中的一个线程B需要对数据进行修改时,那么系统将会复制一份当前的数据,此后线程B所做的数据修改都是在复制的数据段上进行的。这个过程对所有的线程都是透明的,也就是说AC两个线程使用的还是原来的内存数据,当线程B将数据更改后,系统将数据指针移向修改后的数据段上,这样在所有线程都不知情的情况下完成了数据的更新操作。
在hudi中支持cow,每个存储的文件分片只包含基本列文件(parquet),并且每次提交都会产生新的列文件副本。在新的副本上进行写入操作,这种方式带来的问题就是在每次数据写入时,都需要重写整列数据文件,哪怕只有一个字节的数据写入(也就是所谓的写放大
)。
每次新数据的写入,都会基于当前的数据文件产生一个带有提交时间戳的新副本文件,新数据会插入到当前的新副本文件中,直到整个操作没有完成前,所有的查询操作都不会看到这个新的文件副本。 在新文件数据写入提交后,新的查询将会获取到新的数据。因此,查询不受任何写入失败/部分写入的影响,仅运行在已提交数据上。
写时复制存储的目的是从根本上改善当前管理数据集的方式,通过以下方法来实现:
同样COW在提供了一些优秀的性能同时也存在一些缺点,在hudi中举例说:
当然COW不仅仅在hudi中出现,仔细了解后其在Linux、JDK都有体现:
mor可以称为读时合并,该方案应该说是hudi特有的属性,他算得上是cow的升级版,支持通过读优化表提供数据集的读取优化视图,也就是cow的功能。 此外又添加了基于行的增量日志文件(avro)插入功能,也就是说在当前数据文件更新前将对应的数据插入到日志中。 立即读取那么将会通过parquet和avro合并同时给出最新的读视图,而后其也会对两个文件的数据进行合并,通过文件id,将增量日志和最新版本的基本文件进行合并,从而提供近实时的数据查询。
这种方式可以平衡读写成本,以减少cow带来的数据时延,能够提供能一种近实时的查询。
读时合并存储上的目的是直接在DFS上启用近实时处理,而不是将数据复制到专用系统,后者可能无法处理大数据量。 该存储还有一些其他方面的好处,例如通过避免数据的同步合并来减少写放大,即批量数据中每1字节数据需要的写入数据量。