改版通知

巨人肩膀网站已全新改版。若您仍依赖旧站功能或数据,欢迎联系我们,我们会协助处理。联系我们

cowmor与mow

ckckck2025年1月10日5 浏览

COW、MOR、MOW

COW

COWCopy On Write,写时拷贝。在COW表中,只有数据文件/基本文件(.parquet),没有增量文件(.log)。
COW 在数据写入的时候,复制一份原来的拷贝,在其基础上添加新数据,创建数据文件的新版本(新的FileSlice)。
新版本文件包括旧版本文件的记录以及来自传入批次的记录(全量最新)。
正在读数据的请求,读取的是最近的完整副本,这类似MySQL的MVCC思想。

流程示例

设我们有3个文件组,其中包含如下数据文件。

我们进行一批新的写入,在索引后,我们发现这些记录与File group 1和File group 2匹配,然后有新的插入,我们将为其创建一个新的文件组(File group 4)。


MOR

MORMerge On Read,读时合并。在MOR表中,可能包含列式存储的基本文件(.parquet)和行存的增量日志文件(一定会有)(基于行的avro格式,.log.*)。
新插入的数据存储在delta log中,定期再将delta log合并进行parquet数据文件。读取数据时,会将delta log跟老的数据文件做merge。
合并成本从写入端转移到读取端。因此在写入期间我们不会合并或创建较新的数据文件版本。标记/索引完成后,对于具有要更新记录的现有数据文件,Hudi创建增量日志文件并适当命名它们,以便它们都属于一个文件组。

读取端将实时合并基本文件及其各自的增量日志文件。你可能会想到这种方式,每次的读取延迟都比较高(因为查询时进行合并),所以Hudi使用压缩机制来将数据文件和日志文件合并在一起并创建更新版本的数据文件。(文件合并时产生parquet)


MOW

MOWMerge On Write,写时合并。处理流程是:

  • 对于每一条Key,查找它在Base数据中的位置(rowsetid + segmentid + 行号)
  • 如果Key存在,则将该行数据标记删除。标记删除的信息记录在Delete Bitmap中,其中每个Segment都有一个对应的Delete Bitmap
  • 将更新的数据写入新的Rowset中,完成事务,让新数据可见(能够被查询到)
  • 查询时,读取Delete Bitmap,将被标记删除的行过滤掉,只返回有效的数据

查询流程

当我们查询某一版本数据时,Doris会从LRU Cache Delete Bitmap中查找该版本对应的缓存。
如果缓存不存在,再去RowSet中读取对应的Bitmap。
使用Delete Bitmap对RowSet中的数据进行过滤,将结果返回。

引入了一个LRUCache,每个版本的Bitmap只需要做一次合并操作。

优缺点和应用场景


COW

  • 优点:读取时,只读取对应分区的一个数据文件即可,较为高效。
  • 缺点:数据写入的时候,需要复制一个先前的副本再在其基础上生成新的数据文件,这个过程比较耗时。
  • 适用场景:对于一些读多写少的数据,写入时复制的做法就很不错,例如配置、黑名单、物流地址等变化非常少的数据,这是一种无锁的实现。可以帮我们实现程序更高的并发。

COW缺陷

  • 数据一致性问题:COW这种实现只是保证数据的最终一致性,在添加到拷贝数据但还没进行替换的时候,读到的仍然是旧数据。
  • 内存占用问题:如果对象比较大,频繁地进行替换会消耗内存,从而引发Java的GC问题,这个时候,我们应该考虑其他的容器,例如ConcurrentHashMap

MOR

  • 优点:由于写入数据先写delta log,且delta log较小,所以写入成本较低。
  • 缺点:需要定期合并整理compact,否则碎片文件较多。读取性能较差,因为需要将delta log和老数据文件合并。
    Merge-on-Read的特点是写入速度比较快,但是在数据读取过程中由于需要进行多路归并排序,存在着大量非必要的CPU计算资源消耗和IO开销。

MOW

  • 优点:兼顾了写入和查询性能。该模式不需要在读取的时候通过归并排序来对主键进行去重,这对于高频写入的场景来说,大大减少了查询执行时的额外消耗。此外还能够支持谓词下推,并能够很好利用Doris丰富的索引,在数据IO层面就能够进行充分的数据裁剪,大大减少数据的读取量和计算量,因此在很多场景的查询中都有非常明显的性能提升。




总结

  • Hudi/Delta Lake: COW/MOR
  • Kudu: Delta Store
  • Doris: MOR/MOW
  • Redis: COW
  • StarRocks: Full Row Upsert/Delete /COW/MOR/MOW


Merge-On-Write 付出中等的写入代价,换取了较低的读取成本,对谓词下推、非key列索引过滤均能友好支持,并对查询性能优化有较好的效果。

end