cover_image

eBay EB级HDFS集群纠删码和一致性读的深度优化实践

林意群 eBay技术荟
2025年02月07日 03:11

图片


01

ONE

在当前整体行业“降本增效”的大背景下,eBay大数据团队在年初完成Hadoop3升级(eBay万台规模Hadoop集群3.3升级实践)的目标后,也开始了数据降本增效之路。eBay大数据平台拥有着EB级别的数据规模体量,同时仍然保持着每年净增长百PB级别的数据体量。面对不断增长的数据存储压力以及相应会带来的巨大RPC流量压力,今年我们聚焦于eBay HDFS大数据集群,基于Hadoop3升级完成的前期基础上,在效率和成本两方面都做了一定的改进实践并最终收获了一些成果。本篇文章将具体介绍我们大数据团队如何充分发挥HDFS Consistent Read(一致性读)和Erasure Coding(纠删码)功能来做到数据的降本增效。



02

HDFS Consistent Read on eBay

TWO

降本增效细分为降本和增效两块,我们这里先来聊聊“增效”的部分。HDFS在Hadoop3版本里引入了一个叫Consistent Read from Standby的功能。这个功能的意思是说Standby NameNode可以对外提供一致性读的能力,以此来提高整体HDFS集群的RPC性能。简单来说,就是Standby NameNode可以作为一个Read-Only的NameNode(下文简称NN)叫Observer NN。Active NN则专门用来服务写的traffic,其实这个架构和我们常见的读写分离架构十分类似,里面的核心点在于如何保证数据的一致性访问。


Consistent Read on RBF架构

我们先来快速浏览一下Consistent Read目前在我们内部的架构模式(如下图所示),这样能更加方便理解它的一致性数据读的能力。

图片


在我们eBay HDFS集群,我们采用的是RBF(Router-based Federation)方案,因此客户端面对的服务层是我们的Router layer层,然后由Router再将RPC请求分发到Active NN和Observer NN。Active NN和Observe NN之间会做近实时的元数据同步来保证最新的数据状态,这实质上是一种最终一致性的实现。虽然这里做到了近实时的元数据同步,但依然是存在延时的,并不完全等于实时同步。以如下一个简单的读写操作为例,用户A在t0时刻创建完file5,但是用户B在t0时刻后的瞬间(t0+的时刻)从Observer NN是读不到最新创建的file5的,直到等到t1时刻Observer NN同步到file5的文件信息才能读到实际文件。

图片


一般而言,在主从系统中,有下面2种常见的方法能够做到一致性的读:

  • 方法一,从服务在处理客户端读请求时,和主服务节点通信来判断其内部transaction状态是否达到和主节点一致,如果是则进行处理,如果不是则将请求fallback到主节点进行处理。

  • 方法二,Client节点请求从服务节点,发现读取不到数据,然后直接fallback到主节点进行读请求操作。

HDFS Consistent Read架构倾向于采用第一种方案原理,不过这里的状态比较不是和主服务进行比较,而是和客户端传来的状态进行比较。Observer NN在其内部基于客户端携带的状态id和自身applied的最新状态id之间做比较的方式,来间接实现了一致性读的功能。当Observer NN自身状态晚于(小于)客户端所能看到(携带)的状态时,Observer NN则会延迟处理和返回客户端的RPC请求直到其自身状态已经达到客户端所携带的状态id。


我们在回过头来看具体涉及状态同步的问题,出问题的场景主要集中在“写完即读”的场景,这里面可以细分为下面2类:

  • Read your own write

  • Read other’s write

对于第一种自己写自己读的模式,相对比较好解决,客户端只要能够读到它自己刚刚写出去的最新的数据状态即可。客户端在数据写出去的那一刻,它是始终持有着最新自己的数据状态id,因此在自写自读场景下一致性读本身已经支持。第二种模式的读就需要拿到当前时刻最新的全局的数据状态。Consistent Read功能在实现上提供了msync的API支持客户端向Active NN拿到最新的集群数据状态id,然后客户端携带此id向Observer NN发起read操作。


鉴于上述场景二仍需客户端调用额外API实现同步语义,因此我们在Consistent Read的场景应用目前主要集中在偏数据分析的一些workload上。


Consistent Read带来的问题

尽管我们对Consistent Read的使用场景做了限制,但在实际应用中仍然出现了一些问题。


Server RPC Handler死锁

初期我们在内部一个比较大的分析型集群上上线了此功能,我们发现在流量高峰期总会莫名其妙发生NN服务hung住的情况,后来经过调研发现是内部RPC call在进queue操作时发生了死锁的情况(如下图)。

图片


在Consistent Read的功能里,本身用来消化处理RPC call的Handler实例额外包含了进queue的操作,在我们内部的版本中进queue操作被改成了阻塞式的操作,从而导致了死锁问题。后续经过内部改动,此问题得到解决。


数据不一致问题

在Consistent Read上线的半年多时间里,发生了几次数据不同步的问题,全部集中在“写完即读”的场景。用户应用测的表现通常是一个文件刚刚被创建,然后另外一个task马上去读这个文件发现文件少了或者文件不存在的错误,下面是发生的3个出问题的场景。


1. File output commit阶段数据丢失

我们发现Spark job在file output commit阶段做最终数据rename到目标目录的时候偶尔会出现数据少了的情况。最终通过分析发现在commit阶段,driver端在rename前执行的list操作因为使用的standby read的方式存在数据未拿全的可能性,于是我们在FileOutputCommitter内部关键list操作之前额外多加了msync的调用操作来确保状态的同步。这个问题只发生在file output commit算法v1版的时候,v2版本的rename操作被分散到各个task中各自执行,因此不会碰到这种问题。


2. 文件merge重写问题

这里提到的文件merge重写是我们平台内部的一个工具操作。在上线完Consistent Read后,此合并文件工具时不时出现File not Found错误。经过debug分析,发现是此工具逻辑经常会使用同一个fs client进行边读边写,边rename的操作,后续我们在必要步骤添加msync操作最终解决了潜在的同步问题。


3. YARN localization失败

第三类问题发生在YARN application在启动阶段resource localization失败的问题,会出现类似如下的错误。

图片


YARN client提交端在upload完资源文件后,发现在NM端下载的resource状态不一致。社区有类似的JIRA(HDFS-17156)解决这类问题,但是评估下来在我们内部拥有多Router instance的RBF模式下,社区的方案依然无法彻底解决我们的问题。我们最终还是依赖了fs msync API操作解决了localization阶段的数据同步问题。


上述3类数据状态不一致问题有个共同点:问题隐蔽性强,难以准确复现,容易导致问题分析方向发生偏差,这类问题得结合具体的发生场景具体分析


Consistent Read的“增效”成果

我们在许多Heavy-Read的workload中应用了这个功能,它带来的增效效果是十分显著的。在下图所示我们的一个主要namespace集群中,Observer NN承担了大约30%的流量,RPC queue time也降低到了100ms以内。

图片
图片


在我们另外一个主要的分析型集群内,我们同时部署了双Observe NN模式构成了ANN+2 ONN+SNN模式(如下图所示),单namespace最大吞吐已经能够达到10w+Op/s的RPC处理能力,相比之前提高了近一倍的吞吐能力。同时集群的读写隔离性变得更强,异常的Heavy读和Heavy写操作导致的影响也变小了。

图片



03

EC在eBay的实践

Three

上半部分聊完“增效”,下面的篇幅我们来谈谈数据的“降本”。说到大数据的降本,不得不提Hadoop3里的HDFS Erasure Coding(EC)技术。


相比传统数据三副本模式,HDFS EC技术通过data block(数据块)+parity block(校验块)的方式,能够大大降低数据存储的冗余度。以当前我们使用的RS 6-3 policy来说,一个文件包含有9个block块,其中6个块是真实数据存储块,额外只有3个块是冗余的。换算成三副本模式来说,它则需要6(数据块)*3(副本)=18个块来保证数据可用性。但是使用EC技术,我们可以节省(18-(6+3))/18=50%的数据使用空间。另外在数据可用性的保障上,EC数据能够容忍等同于parity block数量的块损坏,它可以做数据的encode,decode操作做缺失块数据的重建。下面我们来主要介绍一下EC在我们eBay内部的落地实践。


Intel ISA-L native库加速

EC作为一种可以大幅度降低存储空间的技术,它的一个tradeoff是数据读写性能相比较副本文件会有一定的损失,因为它涉及到多台节点的数据读写(IO放大)以及包括其中校验块的encode生成。同时它在做数据重建恢复的时候是需要耗费CPU和网络的,这个过程需要读取其他数据块做编解码操作,因此业内一般使用EC来做冷数据的存储。


鉴于EC存在的性能损耗问题,经过调研我们发现可以启用native库来加速其中的编解码操作以此提升EC数据读写的性能。随后我们enable了社区推荐的Intel ISA-L native库(如下),然后对EC数据的读写进行了测试。


$ /apache/hadoop/bin/hadoop checknative

Native library checking:

...

ISA-L:true/apache/releases/hadoop-3.3.3/lib/native/libisal.so.2


我们通过标准的DFSIO的程序做数据的读写对比测试(下图IO Rate值为内部测试环境的结果,仅作性能对比参考),然后分别针对输入文件的size进行不同大小的设置,以此能覆盖到小文件和大文件的所有场景。

图片
图片


上述对比测试能够得到以下几个结论:

  • 尽管开启了native库加速,EC对于小文件的读性能依然不如三副本文件。

  • 随着文件size变大,EC对于大文件的读写性能并不比副本文件差,甚至在写文件上比副本文件还要略胜一筹。

另外我们还做了EC数据在重建阶段中的读数据性能测试,在停止掉其中1到2台data block节点的情况下,读数据的性能并没有明显的下降。

图片


通过以上的性能测试结果,EC ISA-L的native库加速让我们更加有信心在平台上去使用EC来存储我们的冷数据。


EC自动数据转化方案构建

有了前期的EC性能指标评估,后续的问题就在于如何将EC落地到我们的现有冷数据当中。目前社区EC功能不支持原地转换数据到EC格式,只能通过在EC policy目录新写入数据来达到间接转换的效果。一种简单的做法是通过sql将数据从表里按照指定partition读出来然后再insert到另外一张表里,这样可以做到透明转化而且不需要启动额外的DistCp job做数据拷贝。


上述这种方法实施起来确实比较简单,但是整体评估下来这种方法缺乏一定的通用性。另外上述方案里面还需要额外更新新旧表的路径映射关系,数据对应的底层表hdfs路径关系在这个过程中其实是变更了的。对此,我们设计了一种更加透明,通用化的EC自动数据转化方案,方案过程如下图所示:

图片


在这个过程中,我们以表的标准dt路径作为数据转化的基本单元,另外在数据拷贝过程中为了避免可能存在的数据修改操作,我们在这个过程中通过给路径增加read-only属性以及在rename阶段revoke掉所有权限来锁住路径的访问,最终完成数据原子性的rename替换。


目前我们平台上已经能够做到Self-Service方式的EC数据自动化转存能力,服务形式如下所示:

1.用户输入EC调度策略policy,包括需要转EC的路径,retention时间等信息

2.我们后台EC调度器根据policy设置定期生成对应的EC workflow

3.生成好的EC workflow的工作原理如上述介绍的会做透明的数据转换

4.转化好的EC数据最终会daily更新到我们的离线oiv分析表里

5.然后我们会利用oiv分析表数据做metric的展示以及相应的告警通知给用户

图片


后续我们会有计划将支持非标准化的dt路径,这样可以支持更多其他类型的用户路径数据,而不是仅限于表级别的标准dt路径。


EC数据问题挑战

借助于上述构建的EC自动化转化方案,我们集群内的冷数据逐渐地转到了EC存储,随之伴随而来的是一些EC相关的数据问题。尽管目前我们内部使用的Hadoop 3.3.3版本已经解决了很多EC相关的数据问题,但是在实际使用过程中还是发现了其他一些问题,尤其是和数据质量相关的问题。


Snapshot下的EC数据删除错误

在Snapshot路径下同时enable EC路径时,EC block的删除可能会造成NN crash。原因是目前NN逻辑里面默认EC block删除逻辑是不会触发到truncate逻辑的,因为HDFS EC本身不支持truncate操作。但是在EC with Snapshot同时enable的情况下,block的删除是可能执行到INodeFile#collectBlocksBeyondSnapshot的这段出问题的逻辑的,详细问题可参考我们提交给社区的issue:HDFS-17604。对此我们的解决办法是跳过EC的block处理,利用NN端的块处理逻辑延时处理掉这些invalidate block。


EC数据损坏问题

数据质量安全对于数据平台部门来说是至关重要的,不管它是EC的冷数据还是说常规的副本数据,我们在使用EC数据的过程中碰到了一些数据损坏的场景。


在eBay内部有着严格的安全合规要求,大数据平台的slave机器每个月需要做服务的重启来打上最新的安全漏洞补丁。在周期性服务重启的过程中,不可避免会触发节点大量block的replication操作来保证集群数据的可用性。EC block数据在这个过程中除了会做replication外,还存在额外的block reconstruction操作当NN发现EC block块出现缺失的情况。


我们在生产环境遇到的一个例子是用户某一天的历史数据突然出现读取失败的情况,最后分析下来是因为block重建导致的数据问题,并且我们在出问题的机器上发现了部分硬件错误。除了硬件异常可能导致EC数据恢复失败之外,软件层面的bug也可能会导致生产的block数据有问题,以社区issue HDFS-14768为例,当出现EC live index数和target需要恢复的index数不一致的时候,就会存在数据生成错误的可能。


以RS 6-3 policy为例,比如EC block live index = [0, 1, 2, 3, 4, 5, 7, 8], target index经过多重条件判断下来需要恢复2个index的block数据(实际丢失的数据只有index 6的数据),那么实际在构造EC reconstruction task的时候就会变成target index[0]=6, target index[1]=0(默认值)的情况,这里target index[1]=0去错误恢复live index 0的数据块从而造成了原始数据的损坏。


后来我们马上打开了EC reconstruction的数据检验功能(dfs.datanode.ec.reconstruction.validation)来规避此类问题,社区版本目前支持了EC block reconstruction重建之后的数据校验功能,能在一定程度上保障数据的安全性。在打开此功能之前,EC block数据的重建不会做数据的内容检查,并且从文件长度上不会有任何的差异,再加上本身EC一般用于冷数据的存储,访问频率也低。这几个条件结合下来就会导致EC数据的损坏难以被及时的发现。


EC数据Decommission性能问题

节点decommission(下线)操作在大数据集群运维当中是一项十分关键的操作,日常机器的硬件升级维修都需要触发node decommission操作来保证平滑的节点数据服务下线。但是随着EC数据逐渐变多,我们发现DataNode节点在decommission时候的速度变得越来越慢,其中一个很重要的原因是因为EC数据不像副本文件可以从其他replica机器做block replication。这导致EC数据的复制总是集中在正在做decommission下线的机器,进而导致机器的高IO和高网络带宽的使用。


通过对比发现,假设我们将机器直接进行stop处理,让它被动地进行block数据的重建,速度要比主动decommission要快很多。基于这个思路,我们在NN逻辑里主动选择将部分EC block数据从原来需要用replication的方式改成了用reconstruct重建的方式来做数据的生成,以此来分担decommission机器集中式的IO压力,如下图所示:

图片


另外拥有大量EC数据的机器在做decommission的时候,机器本身的高IO操作也会影响到其他正常客户端的读数据操作,这里我们另外做了HDFS的读策略选择优化,不优先将decommissioning的机器服务于用户的读请求。


在NameNode测,同样存在着低效选择block location的逻辑,我们经常会发现类似如下频繁retry的log:

图片


原因是NN在为EC block数据做target location选择的时候会优先做local rack的选择(类似副本的放置策略),但是EC block本身的placement policy是尽可能按照rack级别做分布,这会造成这个过程中频繁无谓的选择。后来我们关闭了NN在这块优先按照local rack进行选择的处理,极大缩短了NN对于EC block target的选择时间。


同时我们调优了NN decommission的相关参数,社区HDFS-16846将dfs.namenode.replication.max-streams-hard-limit参数的影响范围设置为仅仅影响EC block,因此我们调大了此参数的值并同时减小dfs.namenode.reconstruction.pending.timeout-sec时间来提高NN decommission过程中的block处理吞吐量。


EC的“降本”成效

近半年多时间EC带给我们大数据平台的降本效果显著,下图是我们集群上的EC数据趋势图,截至目前已经累计转化超过300PB+的数据,总共节省150+PB的数据存储,为公司带来了可观的预算节省。

图片



04

未来展望

Four

对于未来的展望,我们计划在后续继续拓宽Consistent Read和EC在我们生产环境的使用场景,充分发挥它们所能带给大数据平台降本增效的作用。


另外一方面,随着目前存储机型的迭代更新,机器容量变得越来越大。我们发现HDFS DataNode端也逐渐地暴露出了一定的性能瓶颈,未来我们也会针对DataNode端做性能的相关改进来持续提升大数据集群的数据服务能力。



END





继续滑动看下一个
eBay技术荟
向上滑动看下一个