火山引擎VeDI数据技术分享:两个步骤,为Parquet降本提效

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群

作者:王恩策、徐庆

火山引擎 LAS 团队

火山引擎数智平台 VeDI 是火山引擎推出的新一代企业数据智能平台,基于字节跳动数据平台多年的“数据驱动”实践经验,为企业提供端到端的数智产品、场景化的行业解决方案和专业的数智转型咨询。

Parquet 在字节跳动内部已广泛使用和深度优化,结合小文件合并、列级 TTL 两个应用场景,我们已经实现兼顾高查询性能下的存储成本优化。

基于 Parquet 的降本增效优化和应用,目前已经通过火山引擎数智平台 VeDI 旗下的湖仓一体 LAS 对外输出。

Parquet 在字节跳动的使用

字节跳动离线数仓默认使用 Parquet 格式进行数据存储。Parquet 作为一种列式存储的开源文件格式,在大数据领域被广泛应用,它所提供的一系列特性,如高压缩率、高查询性能等都非常契合大数据领域。

另外在数据安全方面,它提供的模块化加密功能在对数据进行保护的同时也兼顾了高查询性能。除了社区提供的一些基础能力,字节跳动也基于 Parquet 格式进行了深度优化和应用,其中包括 LocalSort/PreWhere 等功能,进一步提升了 Parquet 的存储和查询性能。另外在数据安全方面,也基于 Parquet 构建了透明加密系统,对底层数据进行加密保护的同时不影响用户的正常使用。

在实际的生产过程中,随着海量数据的持续增长,也遇到了一些问题。其中比较典型的就是小文件问题和存储成本问题。小文件问题指的是在存储系统中存在大量小文件,由于字节跳动离线存储采用的是 HDFS,大量小文件的存在会严重影响 HDFS 集群的稳定性以及数据访问的效率。

经过分析,我们发现 HDFS 中大部分数据来源于 Hive,因此治理的目标将主要针对于 Hive 数据。而在存储成本方面,海量数据带来了高额的存储成本,如何安全高效地控制存储成本也是降本增效的一大难点。

小文件合并

首先介绍在小文件治理方面的一些技术实践,主要包括小文件问题的产生原因以及小文件问题的技术解决方案。

小文件问题是怎么产生的

小文件问题的产生可能是由于数据源本身的问题,比如一些流式任务天然地就会按照一定时间周期产出一些小文件。

另外比较常见的是,用户在使用 Spark 等分布式引擎对数据进行处理的过程中使用了过高的并发,也会产出大量小文件,如果同时又用到了动态分区,还会进一步加剧文件数量的放大。

类似于下图中所示的例子,最终产出的文件数量是并发数乘上分区数,一个作业很容易就会产出上千甚至上万个小文件。

如何解决小文件问题

针对上文中提到的小文件问题,当下已经存在一些常见的解决方法,比如用 repartition 控制输出的并发;或者用 distribute by 控制数据的分布形式,每个分区只输出一个文件;一些情况下甚至还需要把作业拆成 2 个单独处理来应对不同的数据场景。

以上这些方法总的来说都不够灵活,对业务的侵入性较大,并且往往还涉及到繁琐的调参工作,影响工作效率。为此我们提出了一套自动化、声明式的小文件合并方案。用户只需要通过参数开启小文件合并,并设置目标文件大小,就能让作业自动输出合适的文件大小。

这种方式除了简单直接,而且合并效率也很高,这部分内容会在后文的原理中详细展开介绍。此外,该方案对静态分区和动态分区也都能很好地支持。

下面来介绍一下这个功能的实现原理。假设不考虑小文件问题,对于一个普通的 Spark ETL 作业来说,数据经过计算后会先写到目标表的各个分区目录下,然后 Spark 会触发 Hive 表元信息的更新,这时候数据就对下游正式可见了。

而当用户开启了小文件合并后,我们会在更新元数据,也就是数据可见之前插入小文件合并操作。具体来说,就是检查各个分区下的文件是否满足大小要求。如果发现文件太小,就会在这个分区下触发小文件合并。

对于那些已经满足要求的分区,则是直接跳过,不做任何操作。这种按需合并的方式是合并效率高的一个原因,而另一个原因则是我们采用了快速合并技术。

小文件合并的核心是如何把一个分区下的多个 Parquet 小文件合并成一个,由于 Parquet 格式具有特殊的编码规则,文件内部被划分为多个功能子模块,我们不能直接把 2 个 Parquet 文件首尾拼接进行合并。

常规的做法是需要用 Spark 读取这些小文件,提取出文件中的一行行记录,然后再写成新的文件。在这个一读一写的过程中,会涉及到大量的压缩反压缩、编码反编码等等操作,这些操作消耗了大量的计算资源。

为了提高合并速度,我们采用了一种快速合并的方式,这种方式借鉴了 Parquet 社区所提供的 merge 工具,能够快速地将多个 Parquet 文件合并成一个,下面介绍一下它的实现原理。

Parquet 文件的内部有很多内容,例如 Footer、RowGroup 等等。这些内容可以分为 2 类,一类是被压缩和编码后的实际数据,而另一类则是记录了数据是如何被编码和排列的元数据。快速合并的基本思路就是:直接 copy 实际数据所对应的原始二进制 Data(跳过编解码流程),再基于数据在新文件中的位置构建出新的元信息。

元信息构建过程非常快速,因此整体开销近似于直接 copy 整个文件。值得注意的是,这种合并方式并不会合并 RowGroup,因此对压缩率和查询性能并不会有明显提升,但是却极大地提升了合并效率,而文件数量的减少最终有效降低了 HDFS 集群的压力。

经过性能测试, 快速合并上相比于普通合并有 14 倍左右的提升。根据线上任务的实际运行情况,作业在开启快速小文件合并后,平均运行时长只增加了 3.5% 左右,可以看到对业务的影响很小。

另外,在实际生产环境中,为了数据安全,Parquet 文件是被加密存储的,并且为了保证高查询性能,加密存储采用的是模块化加密的方式,也就是对文件中的各个模块分别加密。

这种加密方式保留了 Parquet 文件的基本结构,从而保留了 Parquet 高性能查询的能力。但在小文件合并过程中,这也带来了新的挑战。

我们无法像之前的模式那样直接 copy 二进制数据,因为各个文件的数据是基于不同密钥加密的结果,密钥信息保存在每个文件的 Footer 中,直接 copy 二进制模块到目标文件后,无法用新文件中的统一密钥进行解密。

为此需要在原有快速合并的基础上,在 copy 二进制模块的同时加上解密和再加密操作,用原文件中的密钥解密,然后再用新文件的密钥进行加密。整体流程上还是以 copy 二进制数据为主,跳过了编码反编码之类的多余操作,实现快速合并。

以上介绍了如何在数据产出的同时合并小文件,在实际情况中,HDFS 集群上会存在着大量历史小文件,为此我们提供了存量小文件合并工具进行处理,其使用方法也是非常简单:用户提交一个 SQL,在 SQL 中制定合并的那张表、分区、合并的目标文件大小。SQL 提交后,系统就会启动一个 Spark 作业,再结合刚刚提到的工具和流程对存量数据进行快速合并。

小结:我们在增量和存量场景都提供了对应的小文件合并能力,以一种简单高效的方式对小文件进行综合治理,提升了整个集群的健康度和稳定性,最终有效降低了机器成本和人力运维成本。

列级 TTL

上文介绍了在解决小文件问题时的相关实践。接下来将介绍 Parquet 格式在字节跳动另一降本增效实践——列级 TTL 相关的内容。

列级 TTL 产生的背景

  1. 随着业务发展,海量数据的存储成本逐渐成为离线数仓的一大痛点。而目前离线数仓清理存储只有分区级的行级 TTL 方案,类似于使用 alter table drop partition 的 DDL 来完成分区数据的整体删除。对于具有时间跨度较大汇总需求的表,则需要保留较长时间的历史分区,而这些历史分区中很多明细数据在汇总任务中并不会使用,也就是历史分区中存在很多低频访问字段。如果想删除这些不再使用的字段数据,目前已有的方式就是通过 Spark 等引擎将数据读取出来,并将需要删除的字段设置为 NULL 的覆写方式来完成。这种方式有两个缺点:海量数据的覆写计算资源开销很大;

  2. 对于字段较多的大宽表,用户需要在 select 中罗列出所有字段,并对需要删除的字段逐个置空,TTL 任务运维成本高。

轻量级列级 TTL 方案

针对以上业务存在的痛点,结合 Parquet 列存的特性,提出了一种如下图所示的轻量级的列级 TTL 方案。

该方案按照 Column chunck 直接 Copy 每个 RowGroup 中需要保留的列的二进制数据,跳过编解码流程。举一个例子,假如表有 1、2、3 列,现在需要删除第 2 列数据。

首先要做的是构造新的 schema,从原文件 schema 中删除需要 TTL 的列(第 2 列)并作为新文件的 schema,然后从原文件中按照 Column Chunk copy 第 1 列和第 3 列的数据到新文件中。在进行列级 TTL 时,因为删除了部分列数据,会导致新文件 size 变小,容易出现小文件问题,所以我们支持将原来多个文件的数据合并到同一个文件中。

这种列级 TTL 的方式,相比于 insert overwrite 覆写的方式,速度能够实现提升 14 倍 +。前文还提到 insert overwrite 方式需要在 select 中枚举所有列,为了方便业务方使用这个列级 TTL 功能,我们定义了一种新的语法来支持列级 TTL 功能:alter table ${db.table} partition(${part_name}) drop columns(xxx)。

用户只需指定需要执行列级 TTL 的库表分区以及需要删除的列即可,不用再把其他不需要删除的列也一一列举,然后往数据引擎提交这个 SQL,就能触发列级 TTL 任务的执行。

列级 TTL 功能实现到落地还涉及到一个问题,就是如何高效的发现哪些分区下的哪些列能够进行列级 TTL。

LAS 团队开发了一个列级血缘的分析工具,支持快速分析表历史分区查询情况,然后自动推荐能够进行列级 TTL 的 columns 及对应的 TTL 时间,比如某张表 column A 90 天前基本无用户查询,那么 90 天前的历史分区中 column A 可以进行 TTL;Column B 120 天前的数据无用户查询,可以进行列级 TTL 等。

列级 TTL 在字节跳动主要应用于历史低优数据的清理,大 JSON、大 MAP 类型字段的清理或者明细日志的数据清理。该功能上线后已经为公司清理了大量的无用历史数据,释放了较大的存储空间。

结合字节跳动自身经验,火山引擎数智平台 VeDI 不断对 Parquet 这项开源技术进行优化和重构,进一步提升性能,并兼顾存储成本。未来,火山引擎数智平台 VeDI 也将凭借卓越的技术能力和丰富的行业经验,持续为更多用户提供了优质的数据技术服务,助力企业实现数字化转型。

点击跳转 火山引擎VeDI 了解更多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/386828.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Javascript】前端面试基础3【每日学习并更新10】

Web开发中会话跟踪的方法有那些 cookiesessionurl重写隐藏inputip地址 JS基本数据类型 String:用于表示文本数据。Number:用于表示数值,包括整数和浮点数。BigInt:用于表示任意精度的整数。Boolean:用于表示逻辑值…

认证授权概述和SpringSecurity安全框架快速入门

1. 认证授权的概述 1.1 什么是认证 进入移动互联网时代,大家每天都在刷手机,常用的软件有微信、支付宝、头条、抖音等 以微信为例说明认证的相关基本概念。在初次使用微信前需要注册成为微信用户,然后输入账号和密码即可登录微信&#xff0c…

git 推送时出现错误 Locking support detected on remote “origin“

背景:代码托管是局域网搭建的gitlab 按照提示配置 lfs.locksverify true 还是没有用。 网上搜索了一番,其中有人提到可能时服务器磁盘满了,连到服务器上 df -h 查看, 发现根目录已经写满了: 使用命令行: d…

scipy.fft.fft函数与scipy.fft.rfft函数的异同

import numpy as np from scipy import signal import matplotlib.pyplot as plt思路:1)先利用fft计算得出其幅频值2)在利用rfft计算得出其幅频值,看1)和2)那个能还原出信号的原始幅值# 生成一个示例信号 n…

c#实际开发长到的知识

基础科普: 个人建议先把rotion的库导入进来再操作,具体需要导入的库有,helper库包含了modbus通讯封装好的模块,而mvvm则可以用来做设计mvvm模块,你可以使用里面封装好的实现方法,用起来特别简单更容易实现其中的操作,但是我担心那天被卡脖子了啊啊啊,要是我罗工把库下…

【CTFHub】文件上传漏洞详解!

Webshell: 又称一句话木马。WebShell就是以网页文件形式存在的一种代码执行环境,主要用于网站管理、服务器管理、权限管理等操作。 WebShell根据不同的语言分为:ASP木马、PHP木马、JSP木马(上传解析类型取决于网站服务端编写语言类),该类木马…

(二)延时任务篇——通过redis的key监听,实现延迟任务实战

前言 本节内容是关于使用redis的过期key,通过开启其监听失效策略,模拟订单延迟任务的执行流程。其核心原理是通过使用redis订阅与发布的方式,将过期失效的key通过广播的方式,发布给客户端,客户端可以监听此消息进而消…

LNMP动态网站环境部署

1、LINUX部署 stop firewallddisable selinux 2、Nginx部署 ​ vim /etc/yum.repos.d/nginx.repo [nginx-stable] namenginx stable repo baseurlhttp://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck1 enabled1 gpgkeyhttps://nginx.org/keys/nginx_signing.…

【前端 · 面试 】JavaScript 之你不一定会的基础题(一)

最近我在做前端面试题总结系列,感兴趣的朋友可以添加关注,欢迎指正、交流。 争取每个知识点能够多总结一些,至少要做到在面试时,针对每个知识点都可以侃起来,不至于哑火。 JavaScript 之你不一定会的基础题 前言 面试往…

Windows蓝屏问题解决(电脑只要安装了VPN_SV独立客户端)必蓝屏

一、SERNEL_SECURITY_CHECK_FAILURE (139) 蓝屏分析 官方介绍蓝屏现象,官方Windows为了保护电脑,出现故障,自动蓝屏,避免损坏电脑的一种现象,别名buckcheck、蓝屏。 100%复现软件:天融信VPN,同事…

为了方便写CURD代码,我在UTools写了个插件SqlConvert来生成代码!

-1. 前言 为了方便摸鱼,我之前写过一个通过sql生成代码的工具,但是服务器到期了,也就懒得重新部署了。 技术框架是 SpringBoot MybatisPlus Velocity Vue ElementUI Sql-ParseeSql-Parser-ui 0. Utools应用安装 官网地址: https://u.too…

【HZHY-AI300G智能盒试用连载体验】使用YOLOv8进行车辆流量监测

目录 YOLOv8的RKNN模型 程序的部署 流量统计 本文首发于电子发烧友论坛:【新提醒】【HZHY-AI300G智能盒试用连载体验】 智能工业互联网网关 - 北京合众恒跃科技有限公司 - 电子技术论坛 - 广受欢迎的专业电子论坛! (elecfans.com) 环境准备好之后,接…

福建聚鼎:现在装饰画好做吗

在当今社会,随着人们审美情趣的提升和生活品质的改善,家居装饰画已经成为了一种流行的墙面装饰方式。许多人都在思考,现在做装饰画是否是一个好时机? “逆水行舟,不进则退。”在日新月异的市场中,装饰画行业的竞争愈发…

商用密码测评之对HTTPS(TLS)协议中各个参数解释

1、TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 是一个广泛使用的TLS(传输层安全协议)加密套件,它结合了多种技术和算法来确保网络通信的安全。下面是对该加密套件中各个参数的详细解释: 1. TLS 定义:TLS(传…

JMeter 使用

1.JMeter 是什么? JMeter 是一款广泛使用的开源性能测试工具,由 Apache 软件基金会维护。它主要用于测试 Web 应用程序的负载能力和性能,但也支持其他类型的测试,如数据库、FTP、JMS、LDAP、SOAP web services 等。 2.特点&#x…

Infuse Pro for Mac全能视频播放器

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件,将其从左侧拖入右侧文件夹中,等待安装完毕2、应用程序显示软件图标,表示安装成功 三、运行测试安装完成!!! 效果 一、下载软件 下载软件…

Qt系统机制

Qt系统 Qt文件概述输入输出设备类QFileQFileInfoQt多线程Qt多线程常用API使用Qt多线程 线程安全互斥锁读写锁条件变量信号量 Qt网络QUdpSocketQNetworkDatagram设计一个UDP回显服务器QTcpServerQTcpSocketTcp版本的回显服务器HttpClient核心API Qt 音频Qt视频 Qt文件概述 ⽂件操…

【C++BFS】1020. 飞地的数量

本文涉及知识点 CBFS算法 LeetCode1020. 飞地的数量 给你一个大小为 m x n 的二进制矩阵 grid ,其中 0 表示一个海洋单元格、1 表示一个陆地单元格。 一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 gr…

【C++初阶】string类

【C初阶】string类 🥕个人主页:开敲🍉 🔥所属专栏:C🥭 🌼文章目录🌼 1. 为什么学习string类? 1.1 C语言中的字符串 1.2 实际中 2. 标准库中的string类 2.1 string类 2.…

前缀表达式(波兰式)和后缀表达式(逆波兰式)的计算方式

缀是指操作符。 1. 前缀表达式(波兰式) (1)不需用括号; (2)不用考虑运算符的优先级; (3)操作符置于操作数的前面。(如 3 2 ) 1.1 中…