Apache Hudi 官网地址 https://hudi.apache.org/
Apache Hudi 官网文档 https://hudi.apache.org/docs/overview
Apache Hudi GitHub源码地址 https://github.com/apache/hudi
Apache Hudi是可以在数据库层上使用增量数据管道构建流数据湖,满足记录级更新/删除和更改流,并实现自我管理,支持流批一体并在此基础上持续优化。最新版本为0.12.1
Apache Hudi(发音为“hoodie”)是下一代流数据湖平台,将核心仓库和数据库功能引入数据湖中。Hudi提供了表、事务、高效的upsert /delete、高级索引、流摄入服务、数据集群/压缩优化和并发性,同时将数据保持为开源文件格式,在分布式文件存储(云存储,HDFS或任何Hadoop文件系统兼容的存储)上管理大型分析数据集的存储;不仅非常适合于流工作负载,还允许创建高效的增量处理管道;得益于其高级性能优化,使得分析工作能否较好的支持流行的查询引擎如Spark、Flink、Presto、Trino、Hive。总体框架及周边关系如下:
Apache Hudi是一个快速发展的多元化社区,下面为使用和贡献Hudi的小部分公司示例:
组件版本
准备编译环境Maven
# 可以在github中下载
wget https://github.com/apache/hudi/archive/refs/tags/release-0.12.1.tar.gz
# 解压
tar -xvf release-0.12.1.tar.gz
# 进入根目录
cd hudi-release-0.12.1/
3.3.4
3.1.3
nexus-aliyun
nexus-aliyun
http://maven.aliyun.com/nexus/content/groups/public/
true
false
mvn clean package -DskipTests -Dspark3.3 -Dflink1.15 -Dscala-2.12 -Dhadoop.version=3.3.4 -Pflink-bundle-shade-hive3
编译报错
try (FSDataOutputStream outputStream = new FSDataOutputStream(baos,null)) {
由于kafka-schema-registry-client-5.3.4.jar、common-utils-5.3.4.jar、common-config-5.3.4.jar、kafka-avro-serializer-5.3.4.jar这四个包一直没有安装成功,因此我们手动下载安装到本地maven仓库
# 下载confluent包
wget https://packages.confluent.io/archive/5.3/confluent-5.3.4-2.12.zip
# 解压
unzip confluent-5.3.4-2.12.zip
# 通过find命令找到存储位置
find share/ -name kafka-schema-registry-client-5.3.4.jar
# 安装到本地maven仓库
mvn install:install-file -DgroupId=io.confluent -DartifactId=common-config -Dversion=5.3.4 -Dpackaging=jar -Dfile=./share/java/confluent-common/common-config-5.3.4.jar
mvn install:install-file -DgroupId=io.confluent -DartifactId=common-utils -Dversion=5.3.4 -Dpackaging=jar -Dfile=./share/java/confluent-common/common-utils-5.3.4.jar
mvn install:install-file -DgroupId=io.confluent -DartifactId=kafka-schema-registry-client -Dversion=5.3.4 -Dpackaging=jar -Dfile=./share/java/confluent-control-center/kafka-schema-registry-client-5.3.4.jar
mvn install:install-file -DgroupId=io.confluent -DartifactId=kafka-avro-serialize -Dversion=5.3.4 -Dpackaging=jar -Dfile=./share/java/confluent-control-center/kafka-avro-serializer-5.3.4.jar
解决spark模块依赖冲突(修改了Hive版本为3.1.2,其携带的jetty是0.9.3,hudi本身用的0.9.4)存在依赖冲突
在hive-service中376行之后增加如下内容
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.pentaho</groupId>
<artifactId>*</artifactId>
</exclusion>
在hive-jdbc中排除下面依赖
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet.jsp</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
在hive-metastore中排除下面依赖
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-core</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet.jsp</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
在hive-commons中排除下面依赖
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>javax.servlet</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
增加Hudi依赖的jetty版本
<!-- 增加hudi配置版本的jetty -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${jetty.version}</version>
</dependency>
在hive-service中396行之后增加如下内容
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.pentaho</groupId>
<artifactId>*</artifactId>
</exclusion>
在hive-jdbc中排除下面依赖
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet.jsp</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
在hive-metastore中排除下面依赖
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-core</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet.jsp</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
在hive-commons中排除下面依赖
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>javax.servlet</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
增加Hudi依赖的jetty版本
<!-- 增加hudi配置版本的jetty -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${jetty.version}</version>
</dependency>
重新执行编译命令,等待5~10分钟时间
Hudi的核心是维护表上在不同时刻执行的所有操作的时间轴,这有助于提供表的瞬时视图,同时还有效地支持按到达顺序检索数据。TimeLine是Hudi实现管理事务和其他表服务,一个Hudi瞬间由以下几个部分组成:
Apache Hudi 文件在存储上的总体布局方式如下:
原理:Hudi通过索引机制提供高效的upserts,具体是将hoodie key(record key+partition path)与文件id(文件组)建立唯一映射,映射的文件组包含一组记录的所有版本。
下图中黄色块为更新文件,白色块为基本文件
索引的类型
全局索引/非全局索引
hoodie.index.type=GLOBAL_BLOOM
hoodie.index.type=GLOBAL_SIMPLE
索引的选择策略
Hudi表类型定义了如何在DFS上对数据进行索引和布局,以及如何在这种组织之上实现上述原语和时间轴活动(即如何写入数据)。反过来,查询类型定义了如何向查询公开底层数据(即如何读取数据)。Hudi表类型分为COPY_ON_WRITE(写时复制)和MERGE_ON_READ(读时合并)。
Copy On Write
当数据写入写入即写复制表并在其上运行两个查询时
在读表上合并的目的是支持直接在DFS上进行接近实时的处理,而不是将数据复制到可能无法处理数据量的专门系统。这个表还有一些次要的好处,比如通过避免数据的同步合并减少了写量的增加,即在批处理中每1个字节的数据写入的数据量。下面为两种类型的查询—快照查询和读取优化查询的图说明
CopyOnWrite | MergeOnRead | |
---|---|---|
数据延迟 | 高 | 低 |
查询延迟 | 低 | 高 |
更新 (I/O)成本 | 高(重写整个 parquet文件) | 低 (追加到增量日志) |
Parquet 文件大小 | 小 | 较大 |
写扩大 | 高 | 低(依赖合并或压缩策略) |
查询类型:支持快照查询、增量查询、读优化查询三种查询类型。
快照查询:提供对实时数据的快照查询,使用基于列和基于行的存储的组合(例如Parquet + Avro)。针对全量最新数据COW表直接查最新的parquet文件,而MOR表需要做一个合并(最新全量数据)。
增量查询:提供一个更改流,其中包含在某个时间点之后插入或更新的记录。可以查询给定commit/delta commit即时操作以来新写入的数据。有效的提供变更流来启用增量数据管道(最新增量数据)。
读优化查询:通过纯列存储(例如Parquet)提供出色的快照查询性能。可查看给定的commit/compact即时操作的表的最新快照。仅将最新文件片的基本/列文件暴露给查询,并保证与非Hudi表相同的列查询性能(并不是全量最新),只是合并时文件。
不同表支持查询类型
Table Type | Supported Query types |
---|---|
Copy On Write | Snapshot Queries + Incremental Queries |
Merge On Read | Snapshot Queries + Incremental Queries + Read Optimized Queries |
不同查询类型之间的权衡
快照 | 读优化 | |
---|---|---|
数据延迟 | 低 | 高 |
查询延迟 | 高 (合并基本文件/列式文件 + 基于行的 delta 日志文件) | 低(行原始 / 列式文件性能) |
本人博客网站IT小神 www.itxiaoshen.com