导读 本篇文章介绍了知乎大数据在降本增效方面的实践。
主要分为以下四个方面:1. 背景介绍
2. FinOps 驱动降本
3. 技术驱动降本
4. 总结与展望
分享嘉宾|贾承昆 知乎 数据平台负责人
编辑整理|赵晗羽
内容校对|李瑶
出品社区|DataFun
01
背景介绍首先对知乎做一个简要介绍。1. 高质量的在线问答社区
用户可以在知乎上进行提问、回答、点赞和评论,获取有特色且高质量的内容。2. 混合云架构使用了多个云厂商的服务,包括 LaaS、SaaS、PaaS 平台等,这也提高了降本的难度。3. FinOps知乎内部 2022 年开始建设一套经济化计费体系——FinOps,以此系统为抓手推动公司内部降本实践。FinOps 的运用强调了降本增效不仅是研发侧的问题,更多的是与组织相关的,是需要团队之间共同合作才能达成的目标。02FinOps 驱动降本
1. 企业内降本的挑战
(1)供应商众多:需要多个云厂商,会采购不同的资源,比如物理机、虚拟机等一些基础资源,同时也会采购 SaaS 服务使用的资源,资源种类和供应商众多都为管理成本带来了困扰。(2)组织架构:为不断提高组织效率,公司组织架构会在一定周期内进行调整。但是在统计计费成本时,计费对象通常就是一些团队和组织,若企业组织架构发生调整,计费对象就可能消失了。此时,我们需要一种妥善的手段去应对组织架构调整,保证计费体系的连续性。(3)难以持续降本增效虽然在过去已经有无数人进行了实践,但是对于运动式的降本增效,虽然在半年或三个月有了收益,但是一段时间后,组织结构成本又逐渐提高。也就是说,整个降本增效并不是一个可持续的过程,根据 Gartner 的统计,只有 11% 的企业能够在三年的时间粒度上实现持续的成本降低。我们在执行降本增效的过程中不仅要考虑如何通过运动式的降本增效把成本降低,还要考虑细水长流,实现可持续的降本。2. FinOps FinOps 是通过财务来驱动研发,两个部门进行协同,共同实现组织降本增效的一种文化。它提出了六个原则:团队协作、成本节省人人有责、中心化团队驱动 FinOps、实时报表助力决策、业务价值驱动决策、灵活利用云上成本模型。这些原则可以浓缩成三个重要的方面:技术驱动降本
在大数据领域,从 2022 年到 2024 年,我们采取了多项措施,逐步降低了整体成本,主要分为存储优化和计算优化两大部分。其中,有四项措施在成本收益比方面表现尤为突出,存储优化方面包括 EC(Erasure Coding),Zstd 压缩。计算优化方面包括 Spark 自动调参,Remote Shuffle Service。下面对这些优化做详细介绍。1. EC(Erasure Coding) EC(Erasure Coding)技术起源于舟山,最早应用于通信行业。当信息在传输过程中,信道可能会受到干扰,导致数据的损坏或丢失。为了确保数据的可靠传输,舟山码策略问世,用于在数据传输时添加适量的冗余,从而提高数据的可靠性。EC 正是基于这一原理的算法,其常见实现方式之一是 RS(Reed-Solomon)编码。EC 的基本原理是将数据分成多个块,并通过矩阵运算为每个数据块生成相应的校验块。如上图所示,数据块包括 d0、d1、d2、d3,经过 EC 的计算后生成了两个校验块 c0 和 c1,最终形成六个数据块。这意味着,原来的数据冗余了 0.5 倍,但系统可以容忍任意一个数据块的丢失,并可以通过矩阵运算将数据还原回来。在大数据存储领域,EC 的降本效果显著。传统的分布式存储通常为了保证数据的可靠性,采用三副本冗余策略,也就是说,写入 1GB 的数据时,底层会存储 3GB 的数据量。而通过 EC 算法,仅需 1.5 倍的冗余即可提供相同的可靠性,这不仅大幅减少了存储需求,还降低了存储成本,特别是在大规模数据存储环境中效果尤为突出。 然而,使用 EC(Erasure Coding)技术也存在一定的代价。首先,EC 的计算需要额外的 CPU 资源,因此对特别高频访问的数据(即“热数据”)并不适合进行 EC 转码。为了有效利用 EC,必须对数据进行评估,判断哪些数据适合进行 EC 转码,哪些不适合。比如,刚写入的数据和频繁读取的数据由于可能带来额外的 CPU 消耗,通常不适合立即进行 EC 转码。因此,EC 主要适用于“温数据”和“冷数据”。在实际应用中,我们对 EC 的性能进行了测试,使用了 DFSIO 读写工具来模拟操作。测试结果如右图所示,蓝色线代表传统的 HDFS,橙色线代表使用 EC 的 HDFS。我们采用了 RS-6-3 算法,将一个数据分成九块,其中六块为数据块,三块为校验块,这意味着即使有两个块(或两块磁盘或两台机器)发生故障,数据仍能恢复。随着客户端读写并发性的增加,EC 的读写性能出现了延迟,这是因为在更高的并发度下,需要更多的机器参与读写操作。相比之下,传统 HDFS 可能只需一两台机器来完成读写,但 EC 能够将 I/O 负载均摊到更多节点上。对于新写入的数据或即将过期的数据,不建议使用 EC,因为 EC 编码需要消耗大量算力,而这些数据的转码并不划算。另外,EC 转码还可能导致小文件问题,因块数量的增加(如从六块增加到九块)而给 NameNode 增加压力。因此,优先选择相对较大的文件进行 EC 转码,以减少对系统的负担和资源消耗。 在引入 EC 方法后,为了有效管理和执行 EC 转码任务,必须构建一个专门的 EC 服务来自动化完成这项复杂的工作。由于数据量庞大且数据状态不断变化,仅依靠人工是无法完成的,尤其是在新数据不断生成和旧数据逐渐过期的动态环境下。因此,全自动服务是必不可少的。整个 EC 服务体系分为两个主要部分:首先是元数据仓库,它负责为整个 Hive 表建立详细的元数据画像。这个画像包含了诸如 Hive 表的分区大小、文件数、平均文件大小、访问热度,以及分区是否已经过 EC 处理等关键信息。通过这些维度的综合评估,系统可以筛选出最适合进行 EC 转码的分区。筛选出来的分区随后会被交由 EC Worker 服务进行处理。EC Worker 是一个自研的专门执行 EC 转码的服务。这个服务的设计考虑了数据的可靠性,确保数据在转码过程中不会丢失,并具备严格的事务性保障。这意味着对一个目录进行转码时,要么所有数据成功转码,要么如果出现问题则整个任务回滚,以避免中间状态或数据丢失的情况。此外,EC Worker 服务还需要具备幂等性,即在文件已经过一次 EC 转码后,系统需要能够判断并跳过已处理过的目录,避免重复转码。特别是在目录内容因底层重写而发生变化的情况下,系统必须能够准确识别这种变化,并根据当前状态决定是否再次执行 EC 转码。总之,EC 服务的成功运行依赖于其自动化、事务性和幂等性的特性。这些关键因素确保了整个 EC 过程的可靠性和高效性,使得大规模数据环境下的 EC 转码任务得以顺利完成。整体收益来看,EC 方法显著优化了存储资源的使用效率。通过将三副本降低为 1.5 副本的方式,在确保数据可靠性的前提下,没有因 EC 而产生任何数据损失。在 2023 年初,该项目已节省了 25PB 的存储容量,并将在未来继续产生效益。然而,在实践过程中也遇到了一些挑战。例如,使用的 Hadoop 3.1.x 版本存在一个 bug,具体表现为在 EC 块丢失并重建时,可能会导致重建的块出现脏数据或乱码,而带来数据丢失的风险。2. ZSTD 压缩 ZSTD 是 Meta 开源的一种压缩算法,相较于传统的压缩算法如 Snappy 和 LZ4,它在压缩率和压缩速度方面取得了很好的平衡。如上图中的官方性能测试结果所示,ZSTD 的压缩率比 Snappy 提升了 30%,而压缩性能保持不变。常用的压缩方法是 ZSTD 1.5.6 版本中的 ‘fast=3’ 的参数设置。在知乎的数据处理中,主要采用 Parquet 的存储格式。然而,由于部分早期的表未在 Parquet 格式上进行压缩,而较新的表则使用了 Snappy 压缩算法。经过测试,将这些表从 Snappy 压缩算法转换为 ZSTD 压缩后,整体存储将减少约 30%;如果原来的 Parquet 表未进行压缩,整体存储将减少 50%~60%,收益是非常可观的。 在对表的新产生数据更换压缩算法时,需要考虑 ZSTD 的兼容性问题。因为此压缩算法较新,许多早期版本的 Hive 和 Spark 可能并不支持,因此需要将一些支持的补丁回移到 Spark 2 和 Hive 2.1 版本中,确保表可以被下游消费和读取。此外,对于历史数据的压缩算法处理,有两种方案可以考虑。方案一是对表进行一次 ETL 处理,通过 INSERT OVERWRITE 对表进行重写。然而,这种方法存在处理速度慢的问题,因为它需要将所有数据读取出来,进行反序列化和计算,然后再重新序列化回去。这个过程还存在一定的风险,例如在业务演化过程中表的 schema 可能发生变化,重写可能改变底层的数据结构,导致预期之外的风险;除此之外,重新 ETL 可能会改变数据的分布,导致压缩率下降。因此,更为理想的方案是采用一种能够绕过 SQL 对文件直接进行处理的算法。Parquet 文件的存储结构本质上是一种行列混存的格式,具体来说,对于一个大的表格,先按行进行切分(例如每一万行切一块),每个块称为一个行组。每个行组内部包含多个列,这些列数据按照列存的方式进行组织和存储。因此,一个 Parquet 文件可能包含多个 row group,每个 row group 是按行组织的数据组,而每列数据在具体存储时是通过 page 的方式进行压缩。压缩操作发生在 page 层次上,而非对整个 Parquet 文件进行压缩。我们希望将旧的 page 读取出来,用老压缩算法解压缩后,再用新的压缩算法重新压缩,这在官方的 Parquet 实现中是可行的,并且官方提供了名为 parquet-tools 的工具,其中定义了一部分对底层 page 进行操作的 API,我们基于这些 API 开发了 ZSTD 转化工具,该工具能够非常高效地对底层文件进行重写,而不涉及到 schema 的变更,也无需对数据进行任何反序列化,只是单纯地将数据取出并重新压缩。这种方式显著提高了处理效率,能够在较短时间内完成对历史数据的处理,同时还可以在转码过程中对一些小文件进行合并。根据整体估算,ZSTD 每分钟可以处理 30GB 的数据,在一个月中节省了 10PB 的存储,新的作业已默认采用 ZSTD 压缩算法。同时,ZSTD 和 EC 是可以并存的,它们在不同层次上进行存储,收益是可以乘算的。3. Spark 自动调参Spark 自动调参是许多公司面临的一个难题,主要难点在于如何合理定义 Spark 作业所需的资源。对于业务数据人员,自动调参可以帮助他们将大数据调参过程自动化。该系统基于作业的历史执行数据,包括真实的内存和 CPU 消耗,来计算出最适合作业的参数配置。 整个自动调参系统分为两部分,作业画像系统和自动调参服务。作业画像系统负责收集并保存每个作业运行的各项指标数据;自动调参服务基于这些历史指标数据和预先设定的调参规则,来决定每个作业的提交参数。作业画像系统的关键指标采集包括 CPU 和内存使用率、GC 耗时、Shuffle 数据量、HDFS 读写统计值。系统采用了 jvm-profile 和 sparklens 开源组件,分别从 JVM 和 Spark 端采集数据,这些数据汇总后为自动调参提供基础支持。在提交 Spark 作业时,通常会过多申请内存资源,实际使用的峰值可能低于预期。通过这种自动化的采集与分析,系统能根据历史数据自动调整内存分配,避免资源浪费,提高资源利用率。 作业调参系统通过对 Spark 作业的 spark-launcher 进行劫持,在提交作业前先请求调参服务。调参服务会根据作业历史的执行数据,推测最佳的 CPU 与内存比以及执行器数量,并将优化后的参数返回给长字符。整个过程采用启发式算法,逐步逼近最佳内存配置。例如,作业最初申请了 30GB 内存,但实际峰值仅为 16GB,系统会先将内存下调至 24GB,观察执行耗时和 GC 情况,如果没有显著变化,则继续调整,直到找到最优参数。这个渐进式的调优过程能够逐步优化资源配置,提升作业效率。 在公司实践中,经过 3 个月的优化,整体作业资源节省了约 30%。上图中右侧图中红色和蓝色曲线分别显示了 CPU 和内存的优化量,以核时和 GB 时为统计单位。这种调参服务现已覆盖所有 Spark 作业,显著提升了资源利用效率。4. Remote Shuffle Service在 Spark 中,Shuffle 是数据处理的重要环节。默认情况下,Spark 提供了三种 Shuffle 方式,其中的 Start Shuffle 在实际使用中较少被采用,因为一旦出现故障重启,Shuffle 数据会丢失,必须重新计算。一般情况下,External Shuffle Service (ESS)是更常用的方式。ESS 的工作原理是:在 NodeManager 上启动一个 Shuffle 服务,Spark 的 Executor 将 Shuffle 数据写入本地磁盘,然后下一个计算任务的 Reducer 通过 NodeManager 读取这些数据。ESS 的优势在于,即使 Executor 关闭,数据仍然保存在磁盘上,不需要重新计算,只需恢复数据,极大地提升了稳定性。然而,ESS 也存在一些问题。比如 Spark Shuffle 可能涉及大量分区,每个分区在 Shuffle 时都会生成一个文件。HDFS 磁盘在使用时,IOPS(磁盘每秒读取/写入操作数)较低,读写性能不佳。而 ESS 会导致大量数据的读写,大量的磁盘 IO 资源浪费在 Shuffle 过程的等待时间上,而不是用于真正的 CPU 密集型计算。 如图所示,这个任务的 Shuffle Read 数据量为 9.5MB,但生成了 1.8 万个文件,总共产出 11 分钟,这是典型的磁盘处理性能。但其实应该只需要几秒钟,这就是 RSS 引入的背景。 RSS(Remote Shuffle Service)实质上为 push based shuffle,和 ESS 不同,它是由 executor 主动将数据推送到下一个 Reducer 所需的存储位置,也就是说数据写入的时候会按照读的要求做一定的合并和整理。在众多的开源 RSS 中我们选择了阿里的 Apache Celeborn,经过一系列的测试,Celeborn 的稳定性和性能都是比较好的。Celeborn 的一个重要收益是将 shuffle 过程中大量的随机读写操作转化为顺序读写操作。写入的时候会按照需求对 partition 做合并,数据已经被按照顺序整理好,可以进行直接读取。这样减少了随机读写操作,提高了磁盘吞吐量。此外,Celeborn 还支持 PartitionSplit 的功能,当发现 partition 太大的时候可以进行主动的分裂,避免一个 worker 处理过多的数据。Partition 分裂这一功能在平滑升级中非常有用,例如当某个节点需要维护或下线时,Celeborn 可以将该节点正在处理的 Partition 分裂并转移到其他 worker,从而避免新数据经过该节点。这使得在不中断业务的情况下,可以平滑地处理节点下线或进行滚动升级,确保集群的稳定运行,对业务不产生任何负面影响。 统计结果表明,Spark 作业的 shuffle read 耗时经过逐步将作业接入到 Celeborn worker 之后有了明显的下降,具体来说,整体的 shuffle read P99(即 99% 作业的最大耗时)平均损耗降低了 30%。04总结与展望
整体来看,我们主要通过两大手段保证了降本增效的效果,即 FinOps 系统建设和运营,以及技术优化,实现了可持续的降本。 未来规划,首先会推动 Hive 引擎逐步向 Spark 引擎迁移;其次利用主流方法,如 gluten+velox 进一步提升计算效率;同时探索通过弹性EMR 和固定资源池混合的方式提高资源利用效率。以上就是本次分享的内容,谢谢大家。分享嘉宾
INTRODUCTION
贾承昆
知乎
数据平台负责人
曾就职于阿里云、猿辅导、知乎等公司,大数据行业老兵,有多年的数据架构经验,目前在负责知乎大数据平台团队。
往期推荐
在Data-Driven时代下,如何打造下一代智能数据体系?
如何用Agent打造游戏Copilot?「永劫无间」手游AI队友的技术实现路径
数智平台重回“战国时代”:新一代 Data+AI 架构设计与演进
腾讯大数据实时湖仓智能优化实践
大模型数据建设探索与实践
一念 LLM 大语言模型推理加速
数据治理全景:技术成熟度曲线深度分析
主动元数据平台——实现持续、主动、长效数据治理的基石
基于ChatBI的Text2SQL应用实践探索!
创新 IAA 技术:360 引领语言模型在多模态理解中的无损进化
点个在看你最好看
SPRING HAS ARRIVED