Delta Lake 是数砖公司在2017年10月推出来的一个项目,并于2019年4月24日在美国旧金山召开的 Spark+AI Summit 2019 会上开源的一个存储层。它是 Databricks Runtime 重要组成部分。为 Apache Spark 和大数据 workloads 提供 ACID 事务能力,其通过写和快照隔离之间的乐观并发控制(optimistic concurrency control),在写入数据期间提供一致性的读取,从而为构建在 HDFS 和云存储上的数据湖(data lakes)带来可靠性。Delta Lake 还提供内置数据版本控制,以便轻松回滚。更多关于 Delta Lake 的介绍可以参见过往记忆大数据的 《Apache Spark 社区期待的 Delta Lake 开源了》 以及 《深入理解 Apache Spark Delta Lake 的事务日志》的介绍。
Hudi(Hoodie) 是 Uber 为了解决大数据生态系统中需要插入更新及增量消费原语的摄取管道和 ETL 管道的低效问题,该项目在2016年开始开发,并于2017年开源,2019年1月进入 Apache 孵化器。更多关于 Apache Hudi 的介绍可以参见过往记忆大数据的 《Apache Hudi: Uber 开源的大数据增量处理框架》 以及 《Uber 大数据平台的演进(2014~2019)》的介绍。
本文以中立的态度从高层次简单对比一下这两个数据湖产品的优缺点。
功能对比
这两款产品都支持对存储在 HDFS 上的数据进行增删改查,当然不只是支持 HDFS,其他兼容 HDFS 的存储系统也是支持的,比如 S3 等。下面我们简单介绍如何使用 Scala 来使用 Delta Lake 以及 Hudi。
添加数据
如果你之前在 Spark 里面写过 Parquet 文件,那么你可以很轻松的换成 Delta Lake 存储引擎,具体如下:
val data = spark.range(0, 5)
data.write.format("delta").save("/tmp/delta-table")
而如果你要往 Hudi 写入数据,会稍微麻烦一些,具体如下:
val tableName = "hudi_archive_test"
val basePath = "file:///tmp/hudi_archive_test"
val inserts = List(
"""{"id" : 1, "name": "iteblog", "age" : 101, "ts" : 1, "dt" : "20191212"}""",
"""{"id" : 2, "name": "iteblog_hadoop", "age" : 102, "ts" : 1, "dt" : "20191213"}""",
"""{"id" : 3, "name": "hudi", "age" : 103, "ts" : 1, "dt" : "20191212"}""")
val df = spark.read.json(spark.sparkContext.parallelize(inserts, 2))
df.write.format("org.apache.hudi").
option(PRECOMBINE_FIELD_OPT_KEY, "ts").
option(RECORDKEY_FIELD_OPT_KEY, "id").
option(PARTITIONPATH_FIELD_OPT_KEY, "dt").
option(TABLE_NAME, tableName).
mode(Append).
save(basePath)
Hudi 写数据的时候需要指定 PRECOMBINE_FIELD_OPT_KEY,RECORDKEY_FIELD_OPT_KEY 以及 PARTITIONPATH_FIELD_OPT_KEY。RECORDKEY_FIELD_OPT_KEY 是每条记录的唯一 id,支持多个字段;PRECOMBINE_FIELD_OPT_KEY 在数据合并的时候使用到,当 RECORDKEY_FIELD_OPT_KEY 相同时,默认取 PRECOMBINE_FIELD_OPT_KEY 属性配置的字段最大值所对应的行;PARTITIONPATH_FIELD_OPT_KEY 用于存放数据的分区。
更新数据
在 Delta Lake 中更新数据可以指定条件,满足条件的数据将会被更新,使用如下:
import io.delta.tables._
import org.apache.spark.sql.functions._
val iteblogDeltaTable = DeltaTable.forPath(path)
// 对 id 为偶数的行 content 字段后面加上 -100
iteblogDelt