Delta Lake 和 Apache Hudi 两种数据湖产品全方面对比

本文涉及的产品
EMR Serverless StarRocks,5000CU*H 48000GB*H
简介: Delta Lake 是数砖公司在2017年10月推出来的一个项目,Hudi(Hoodie) 是 Uber 为了解决大数据生态系统中需要插入更新及增量消费原语的摄取管道和 ETL 管道的低效问题,本文以中立的态度从高层次简单对比一下这两个数据湖产品的优缺点。

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 还提供内置数据版本控制,以便轻松回滚。

Hudi(Hoodie) 是 Uber 为了解决大数据生态系统中需要插入更新及增量消费原语的摄取管道和 ETL 管道的低效问题,该项目在2016年开始开发,并于2017年开源,2019年1月进入 Apache 孵化器。

本文以中立的态度从高层次简单对比一下这两个数据湖产品的优缺点。

功能对比

这两款产品都支持对存储在 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
iteblogDeltaTable.update(
  condition = expr("id % 2 == 0"),
  set = Map("content" -> expr("concat(content, '-100')")))

而在 Hudi 中更新数据和插入数据类似,使用如下:

val tableName = "hudi_archive_test"
val basePath = "file:///tmp/hudi_archive_test"

val inserts = List(
    """{"id" : 1,  "name": "iteblog", "age" : 102, "ts" : 2, "dt" : "20191212"}""",
    """{"id" : 2, "name": "iteblog_hadoop", "age" : 103, "ts" : 2, "dt" : "20191213"}""",
    """{"id" : 3,  "name": "hudi", "age" : 104, "ts" : 2, "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)

需要将 mode 设置为 Append,在底层,Hudi 会根据 RECORDKEY_FIELD_OPT_KEY、PRECOMBINE_FIELD_OPT_KEY 以及 PARTITIONPATH_FIELD_OPT_KEY 三个字段对数据进行 Merge,也就是更新。如两条记录相同,取 PRECOMBINE_FIELD_OPT_KEY 参数配置的值最大的哪一行。

删除数据

在 Delta Lake 中,删除数据也很简单,可以指定删除数据的条件,如下:

import io.delta.tables._

val iteblogDeltaTable = DeltaTable.forPath(spark, path)

// 删除 id 小于 4 的数据
iteblogDeltaTable.delete("id <= '4'")

Hudi 的数据删除支持软删除(Soft Deletes)和硬删除(Hard Deletes)。使用软删除时,用户希望保留键,但仅使所有其他字段的值都为空;而硬删除是从数据集中彻底删除记录在存储上的任何痕迹。

deleteDF 
    .write().format("org.apache.hudi").
    option(...).
    option(PRECOMBINE_FIELD_OPT_KEY, "ts").
    option(RECORDKEY_FIELD_OPT_KEY, "id").
    option(PARTITIONPATH_FIELD_OPT_KEY, "dt").
    .option(DataSourceWriteOptions.PAYLOAD_CLASS_OPT_KEY, "org.apache.hudi.EmptyHoodieRecordPayload")
    

查询数据

两者的查询数据功能都很简单,具体如下:

// Delta Lake val df = spark.read.format("delta").load("/tmp/delta-table") df.show()

// Hudi val roViewDF = spark. read. format("org.apache.hudi"). load(basePath + "////") 

上面简单介绍了 Delta Lake 和 Hudi 两种数据湖的使用。

数据 Merge 策略

Delta Lake 支持对存储的数据进行更新,并且仅支持写入的时候进行数据合并(Write On Merge),它会获取需要更新的数据对应的文件,然后直接读取这些文件并使用 Spark 的 Join 进行计算产生新的文件。

同理,Hudi 也是支持写入数据的时候进行合并,但是相比 Delta Lake,Hudi 还支持 Read On Merge 模式,也就是将增量数据写入到一个 delta 文件,然后默认情况下在更新完数据后会启动一个作业进行 compaction 操作。当然,这个也是可以关闭的,也就是更新的时候值负责数据的写入,合并操作可以单独用一个作业来跑。

从功能上来说,这方面 Hudi 比 Delta Lake 设计的要好。在少写多读的情况下,Write On Merge 模式很不错;而在多写少读的情况下,Read On Merge 模式很不错,而 Delta Lake 目前还不支持 Read On Merge 模式。

另外,Hudi 提供了索引机制,在数据合并的时候,可以使用索引的信息快速定位到某行数据所在的文件,从而加快数据更新的速度。

和其他系统兼容性

Delta Lake 的源码大量使用了 Spark 的代码实现,而 Hudi 虽然也是 Spark 的一个类库,但是其读写底层文件时并不依赖 Spark 去实现,而是实现了自己独有的 InputFormat,比如 HoodieParquetInputFormat、HoodieParquetRealtimeInputFormat 等。所以从这个角度上看,Hudi 和其他系统去做兼容比 Delta Lake 要容易。

目前 Hudi 原生支持 Spark、Presto、MapReduce 以及 Hive 等大数据生态系统,Flink 的支持正在开发中,参见 HUDI-184。Delta Lake 作为一个数据湖的存储层,其实不应该和 Spark 进行深入的绑定,数砖肯定意识到这个问题,所以数砖的大佬们弄了一个新的项目,用于和其他大数据生态系统进行整合,参见 https://github.com/delta-io/connectors,相关的 ISSUE 参见 https://github.com/delta-io/delta/issues/245
在前几天发布的 Delta Lake 0.5.0 也支持 Hive、Presto 等常见的大数据查询引擎。

SQL 语法

SQL 的支持能够为用户提供极大的便利。从 0.4.0 版本开始,Delta Lake 已经开始支持一些命令的 SQL 语法了。由于 Delta Lake 是单独的一个项目,如果需要让它支持所有的 SQL 语法,需要从 Apache Spark 里面拷贝大量的代码到 Delta Lake 项目中,不便于维护,所以这个版本只支持 vacuum 和 history 简单命令的 SQL 语法。

其他的 delete、update 以及 merge 的 DML 操作支持可能得等到 Spark 3.0 版本才会支持的。目前社区也在 Spark 3.0 里面的 DataSource V2 API 里面添加了对 DELETE/UPDATE/MERGE 的支持,详情参见 SPARK-28303。

Hudi 目前还不支持使用 SQL 进行 DDL / DML 相关操作,不过社区已经有小伙伴提到这个东西了,具体参见 HUDI-388。

相信在未来版本,Delta Lake 以及 Hudi 应该都会支持使用 SQL 来读写底层的数据了。

多语言支持

Delta Lake 的多语言这块做的比较好,目前支持使用 Scala、Java 以及 Python(0.4.0 版本开始支持);而 Apache Hudi 目前只支持 Scala 以及 Java 语言。

并发控制

Delta Lake 原生提供了 ACID 事务的支持,每次写入都是一个事务,并且在事务日志中记录了写入的序列顺序。事务日志跟踪文件级别的写入并使用乐观并发控制。在存在冲突的情况下,Delta Lake 会抛出并发修改异常以便用户能够处理它们并重试其作业。Delta Lake 还提供强大的可序列化隔离级别,允许工程师持续写入目录或表,并允许消费者继续从同一目录或表中读取,读者将看到阅读开始时存在的最新快照。因为 ACID 的支持,Delta Lake 允许同一时刻多个用户同时写一张表。

Apache Hudi 每次修改也会生成一个事务提交,但是其不支持同一时刻多个用户同时写一张表,因为如果是这种情况最后的数据是不对的。

版本回退

Delta Lake 原生提供了一个叫做时间旅行(Time Travel)的功能,通过这个功能我们可以回退到任意版本的数据,具体如下:

val df = spark.read.format("delta").option("versionAsOf", 0).load("/tmp/delta-table")
df.show()

这个功能非常有用,比如我们发布新的系统时,然后发现了一个 Bug,这时候我们可以使用这个功能将数据回退到正确的状态。

Apache Hudi 也支持类似的概念,也就是增量视图(Incremental View),我们可以通过指定一个时间段,然后查询到这个时间段新增或者修改的数据,具体如下:

//incrementally query data
val incViewDF = spark.read.format("org.apache.hudi").
    option(VIEW_TYPE_OPT_KEY, VIEW_TYPE_INCREMENTAL_OPT_VAL).
    option(BEGIN_INSTANTTIME_OPT_KEY, beginTime).
    option(END_INSTANTTIME_OPT_KEY, endTime).
    load(basePath);
incViewDF.registerTempTable("hudi_incr_table")
spark.sql("select `_hoodie_commit_time`, fare, begin_lon, begin_lat, ts from  hudi_incr_table where fare > 20.0").show()

如果我们要回退到某一版本的数据,可以把 BEGIN_INSTANTTIME_OPT_KEY 参数对应的值设置为 0,然后 END_INSTANTTIME_OPT_KEY 对应的参数设置为需要回退的 commit 时间(_hoodie_commit_time)

小文件问题

Databricks Runtime 里面的 Delta Lake 是支持使用 OPTIMIZE 命令将小文件进行压缩的,但是据说该实现与 Databricks 中的某些特定逻辑相关,所以数砖目前并不打算开源这部分的代码,这就导致开源版本的 Delta Lake 需要我们自己处理小文件问题了,具体方法可以参见 https://github.com/delta-io/delta/issues/49

而 Hudi 可以通过将对该分区中的插入作为对现有小文件的更新来解决小文件的问题,可以通过 hoodie.parquet.small.file.limit 参数实现。

底层文件系统格式

Delta Lake 中的所有数据都是使用 Apache Parquet 格式存储,使 Delta Lake 能够利用 Parquet 原生的高效压缩和编码方案。

在 Hudi 中,如果我们使用 Write On Merge 存储类型(默认),那么底层也是使用 Apache Parquet 格式存储数据;而如果使用了 Read On Merge 存储类型,则同时使用 Avro 和 Parquet 来存储数据。其中 Avro 格式以行的形式存储增量的数据,而 Parquet 以列的形式存储已经 Merge 好的数据。

表模式管理

新增列

在 Delta Lake 中,默认情况下,如果插入的数据包含 Delta Lake 表中没有的列,会报错,如下:

scala> val df = spark.read.format("delta").load("/tmp/delta-table")
df1: org.apache.spark.sql.DataFrame = [age: bigint, dt: string ... 3 more fields]

scala> df.printSchema
root
 |-- age: long (nullable = true)
 |-- dt: string (nullable = true)
 |-- id: long (nullable = true)
 |-- name: string (nullable = true)
 |-- ts: long (nullable = true)

如果我们往上面的 Delta Lake 表中插入以下的数据,这会报错:

scala> val inserts = List("""{"id" : 1,  "name": "iteblog", "age" : 102, "ts" : 2, "email": "spark@iteblog.com", "dt" : "20191212"}""")
inserts: List[String] = List({"id" : 1,  "name": "iteblog", "age" : 102, "ts" : 2, "email": "spark@iteblog.com", "dt" : "20191212"})

scala> val df = spark.read.json(spark.sparkContext.parallelize(inserts, 2))
warning: there was one deprecation warning; re-run with -deprecation for details
df: org.apache.spark.sql.DataFrame = [age: bigint, dt: string ... 4 more fields]

scala> df.write.format("delta").mode("append").save("/tmp/delta-table")
org.apache.spark.sql.AnalysisException: A schema mismatch detected when writing to the Delta table.
To enable schema migration, please set:
'.option("mergeSchema", "true")'.

Table schema:
root
-- age: long (nullable = true)
-- dt: string (nullable = true)
-- id: long (nullable = true)
-- name: string (nullable = true)
-- ts: long (nullable = true)


Data schema:
root
-- age: long (nullable = true)
-- dt: string (nullable = true)
-- email: string (nullable = true)
-- id: long (nullable = true)
-- name: string (nullable = true)
-- ts: long (nullable = true)

上面我们在插入的数据加上了 email 这列,而这列在之前的 Delta Lake 表中是不存在的,默认情况下是会报错的。正如上面提示,我们在写入数据的时候加上 .option("mergeSchema", "true") 参数即可,这时候 Delta Lake 表就会增加新的一列。

在 Apache Hudi 中,新增加的列可以直接添加到已有的表中,如下:

val roViewDF = spark.
  read.format("org.apache.hudi").
  load(basePath + "/*/")
roViewDF.printSchema()

root
 |-- _hoodie_commit_time: string (nullable = true)
 |-- _hoodie_commit_seqno: string (nullable = true)
 |-- _hoodie_record_key: string (nullable = true)
 |-- _hoodie_partition_path: string (nullable = true)
 |-- _hoodie_file_name: string (nullable = true)
 |-- age: long (nullable = true)
 |-- id: long (nullable = true)
 |-- name: string (nullable = true)
 |-- ts: long (nullable = true)
 |-- type: string (nullable = true)

val inserts = List("""{"id" : 7, "type": "N", "name": "new spark", "age" : 103, "email" : "spark@iteblog.com", "ts" : 1}""")

val df = spark.read.json(spark.sparkContext.parallelize(inserts))
df.write.format("org.apache.hudi").
  option(PRECOMBINE_FIELD_OPT_KEY, "ts").
  option(RECORDKEY_FIELD_OPT_KEY, "id").
  option(TABLE_NAME, tableName).
  mode(Append).
  save(basePath)

val roViewDF1 = spark.
  read.
  format("org.apache.hudi").
  load(basePath + "/*/")
roViewDF1.printSchema()

root
 |-- _hoodie_commit_time: string (nullable = true)
 |-- _hoodie_commit_seqno: string (nullable = true)
 |-- _hoodie_record_key: string (nullable = true)
 |-- _hoodie_partition_path: string (nullable = true)
 |-- _hoodie_file_name: string (nullable = true)
 |-- age: long (nullable = true)
 |-- email: string (nullable = true)
 |-- id: long (nullable = true)
 |-- name: string (nullable = true)
 |-- ts: long (nullable = true)
 |-- type: string (nullable = true)

从上可见新增加的字段已经加到 Hudi 的对应表中了。

缺省列处理

在 Delta Lake 中,如果我们插入的数据不包含对应表的全部字段,是可以插入进去的,并且缺少的列对应的数据为 null。但是在 Hudi 中,插入数据必须指定表的全部字段,否则会报错。

列字段类型修改

目前 Delta Lake 和 Hudi 都不支持修改表中已有字段的类型。

表类型

在 Delta Lake 中,数据存储到 Delta Lake 和读出来的类型是一致的,如下:

scala> val df = spark.read.schema(schema).json(spark.sparkContext.parallelize(inserts))
warning: there was one deprecation warning; re-run with -deprecation for details
df: org.apache.spark.sql.DataFrame = [id: int, create_time: timestamp ... 4 more fields]

scala> df.printSchema
root
 |-- id: integer (nullable = false)
 |-- create_time: timestamp (nullable = false)
 |-- name: string (nullable = false)
 |-- ts: long (nullable = false)
 |-- dt: string (nullable = false)
 |-- is_vip: boolean (nullable = false)

scala> df.write.format("delta").save("/tmp/delta-table")

scala> val r = spark.read.format("delta").load("/tmp/delta-table")
df: org.apache.spark.sql.DataFrame = [id: int, create_time: timestamp ... 4 more fields]

scala> r.printSchema
root
 |-- id: integer (nullable = true)
 |-- create_time: timestamp (nullable = true)
 |-- name: string (nullable = true)
 |-- ts: long (nullable = true)
 |-- dt: string (nullable = true)
 |-- is_vip: boolean (nullable = true)

这是因为 Delta Lake 在每次 commit 的文件里面存储了 DataFrame 的 StructType。但是在 Apache Hudi 中,存储到数据湖里面的数据类型会发生变化,如下:

scala> val df = spark.read.schema(schema).json(spark.sparkContext.parallelize(inserts))
warning: there was one deprecation warning; re-run with -deprecation for details
df: org.apache.spark.sql.DataFrame = [id: int, create_time: timestamp ... 4 more fields]

scala> df.printSchema
root
 |-- id: integer (nullable = false)
 |-- create_time: timestamp (nullable = false)
 |-- name: string (nullable = false)
 |-- ts: long (nullable = false)
 |-- dt: string (nullable = false)
 |-- is_vip: boolean (nullable = false)

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)


val roViewDF = spark.
  read.format("org.apache.hudi").
  load(basePath + "/*")

scala> roViewDF.printSchema()

root
 |-- _hoodie_commit_time: string (nullable = true)
 |-- _hoodie_commit_seqno: string (nullable = true)
 |-- _hoodie_record_key: string (nullable = true)
 |-- _hoodie_partition_path: string (nullable = true)
 |-- _hoodie_file_name: string (nullable = true)
 |-- id: integer (nullable = true)
 |-- create_time: long (nullable = true)
 |-- name: string (nullable = true)
 |-- ts: long (nullable = true)
 |-- dt: string (nullable = true)
 |-- is_vip: boolean (nullable = true)

可以看出,create_time 已经由 timestamp 类型变成 long 类型了。这是因为 Apache Hudi 在每次提交生成的 commit 文件里面存储的是 Avro 的 Schema,这个过程需要将 DataFrame 的 StructType 转换成 Avro 支持的类型,而 Avro 支持的类型有 ECORD, ENUM, ARRAY, MAP, UNION, FIXED, STRING, BYTES, INT, LONG, FLOAT, DOUBLE, BOOLEAN, NULL。所以读取的时候也就只能读取到 Avro 支持的数据类型。

关于为什么 Apache Hudi 存储的是 Avro 支持的类型而不支持存储 Spark 的 StructType,我猜想应该是 Apache Hudi 把 Spark 只是当做其一个框架。使用 Spark 写入 Hudi 的数据可以使用 Apache Hive/Presto 读出来,如果存储的是 Spark StructType,那么在 Hive/Presto 里面是会报错的。

总结

Delta Lake 和 Hudi 两个都是数据湖的两款产品,各有优缺点。Hudi 的产生背景就是为了解决 Uber 的增量更新的问题,所以如果你对 Delta Lake 的数据 Merge 不是很满意,那么 Hudi 可能会适合你。如果你对多客户端同时写一张表很在意,那么 Delta Lake 可能会更适合你。


本文转载自过往记忆
原文链接


阿里巴巴开源大数据技术团队成立Apache Spark中国技术社区,定期推送精彩案例,技术专家直播,问答区近万人Spark技术同学在线提问答疑,只为营造纯粹的Spark氛围,欢迎钉钉扫码加入!
image.png
对开源大数据和感兴趣的同学可以加小编微信(下图二维码,备注“进群”)进入技术交流微信群。

image.png

相关实践学习
基于EMR Serverless StarRocks一键玩转世界杯
基于StarRocks构建极速统一OLAP平台
快速掌握阿里云 E-MapReduce
E-MapReduce 是构建于阿里云 ECS 弹性虚拟机之上,利用开源大数据生态系统,包括 Hadoop、Spark、HBase,为用户提供集群、作业、数据等管理的一站式大数据处理分析服务。 本课程主要介绍阿里云 E-MapReduce 的使用方法。
相关文章
|
5月前
|
消息中间件 安全 API
《阿里云产品四月刊》—Apache RocketMQ ACL 2.0 全新升级(1)
阿里云瑶池数据库云原生化和一体化产品能力升级,多款产品更新迭代
295 1
《阿里云产品四月刊》—Apache RocketMQ ACL 2.0 全新升级(1)
|
5月前
|
消息中间件 安全 Apache
《阿里云产品四月刊》—Apache RocketMQ ACL 2.0 全新升级(4)
阿里云瑶池数据库云原生化和一体化产品能力升级,多款产品更新迭代
182 1
《阿里云产品四月刊》—Apache RocketMQ ACL 2.0 全新升级(4)
|
5月前
|
消息中间件 安全 Apache
《阿里云产品四月刊》—Apache RocketMQ ACL 2.0 全新升级(2)
阿里云瑶池数据库云原生化和一体化产品能力升级,多款产品更新迭代
243 0
《阿里云产品四月刊》—Apache RocketMQ ACL 2.0 全新升级(2)
|
19天前
|
消息中间件 canal 分布式计算
类似apache nifi的产品还有哪些?
【10月更文挑战第23天】类似apache nifi的产品还有哪些?
34 3
|
1月前
|
存储 数据挖掘 数据处理
Apache Paimon 是一款高性能的数据湖框架,支持流式和批处理,适用于实时数据分析
【10月更文挑战第8天】随着数据湖技术的发展,越来越多企业开始利用这一技术优化数据处理。Apache Paimon 是一款高性能的数据湖框架,支持流式和批处理,适用于实时数据分析。本文分享了巴别时代在构建基于 Paimon 的 Streaming Lakehouse 的探索和实践经验,包括示例代码和实际应用中的优势与挑战。
63 1
|
1月前
|
SQL 存储 监控
大数据-161 Apache Kylin 构建Cube 按照日期、区域、产品、渠道 与 Cube 优化
大数据-161 Apache Kylin 构建Cube 按照日期、区域、产品、渠道 与 Cube 优化
49 0
|
3月前
|
安全 数据管理 大数据
数据湖的未来已来:EMR DeltaLake携手阿里云DLF,重塑企业级数据处理格局
【8月更文挑战第26天】在大数据处理领域,阿里云EMR与DeltaLake的集成增强了数据处理能力。进一步结合阿里云DLF服务,实现了数据湖的一站式管理,自动化处理元数据及权限控制,简化管理流程。集成后的方案提升了数据安全性、可靠性和性能优化水平,让用户更专注业务价值。这一集成标志着数据湖技术向着自动化、安全和高效的未来迈出重要一步。
74 2
|
3月前
|
存储 大数据 数据处理
Delta Lake革新浪潮:EMR中的数据湖守护者,如何重塑大数据生态?
【8月更文挑战第26天】Delta Lake是一款开源大数据处理框架,以数据版本控制和ACID事务特性著称,在大数据领域崭露头角。在阿里云EMR平台上,它为用户提供高效可靠的数据处理方式,通过结构化的存储、事务日志实现数据版本控制和回滚。Delta Lake在EMR中实现了ACID事务,简化数据湖操作流程,支持时间旅行查询历史数据版本,优化存储格式提高读取速度,这些优势使其在开源社区和企业界获得广泛认可。
49 2
|
3月前
|
分布式计算 大数据 数据处理
【大数据管理新纪元】EMR Delta Lake 与 DLF 深度集成:解锁企业级数据湖的无限潜能!
【8月更文挑战第26天】随着大数据技术的发展,Apache Spark已成为处理大规模数据集的首选工具。亚马逊的EMR服务简化了Spark集群的搭建和运行流程。结合使用Delta Lake(提供ACID事务保证和数据版本控制)与DLF(加强数据访问控制及管理),可以显著提升数据湖的可靠性和性能。本文通过一个电商公司的具体案例展示了如何在EMR上部署集成Delta Lake和DLF的环境,以及这一集成方案带来的几大优势:增强的可靠性、细粒度访问控制、性能优化以及易于管理的特性。这为数据工程师提供了一个高效且灵活的数据湖平台,简化了数据湖的建设和维护工作。
59 1
|
3月前
|
消息中间件 人工智能 监控

推荐镜像

更多