Hadoop 上云: 存算分离架构设计与迁移实践
在去年的案例中,一面分享了架构设计和实践。本次案例,进一步补充了在后续数据迁移过程中一面遇到的具体挑战以及分级存储的实践。如果你正在考虑将 Hadoop 迁移到云上,这篇文章从架构设计到实际操作都涵盖了丰富的内容,是一篇不容错过的案例。
一面数据原有的技术架构是在线下机房中使用 CDH 构建的大数据集群。自公司成立以来,每年都保持着高速增长,业务的增长带来了数据量的剧增。
在过去几年中,我们按照每 1 到 2 年的规划扩容硬件,但往往在半年之后就不得不再次扩容。而每次扩容都需要花费大量精力。
为了解决包括扩容周期长、计算存储资源不匹配以及高昂的运维成本等这些问题,我们决定对数据架构进行改造,并将数据迁移到云端,采用存算分离的结构。 在这个案例中,我们将为大家介绍 Hadoop 上云的架构设计、选型的思考、组件评估以及数据迁移的整个过程。
目前,基于 JuiceFS 我们实现了计算和存储分离的架构,总存储量增加了 2 倍;性能方面的变化无明显感知,运维成本大幅降低。在案例的末尾还附上了针对阿里云 EMR 以及 JuiceFS 的一手运维经验,希望这个案例能为其他面临类似问题的同行提供有价值的参考。
为了满足业务需求,一面数据抓取了国内外数百个大型网站的数据,目前数量已经超过 500 个,并积累了大量的原始数据、中间数据和结果数据。随着我们不断增加抓取的网站数量和服务的客户群,数据量也在快速增长。因此,我们着手开始进行扩容以满足需求的增长。
原有的架构是在一个线下机房使用 CDH 构建了一个大数据集群。如下图所示,我们主要使用了 Hive、Spark 和 HDFS 等组件。在 CDH 的上游有多种数据生产系统,在这里只列出了 Kafka,因为与 JuiceFS 相关;除了 Kafka 之外,还有其他一些存储方式,包括 TiDB、HBase、MySQL 等等。
一面数据原有数据架构
数据流向方面,我们有一个上游的业务系统和数据采集系统,数据会被采集下来后写入 Kafka。然后我们使用一个 Kafka Connect 集群,将数据同步到 HDFS。
在这个架构上方,我们使用了一个自研的数据开发平台,称为 OneWork,用于开发和管理各种任务。这些任务会通过 Airflow 下发到任务队列进行调度。
业务 / 数据会增长比较快,业务扩容周期长。公司在 2016 年线下机房部署了 CDH 集群,到 2021 年已存储和处理 PB 级的数据。公司自创立以来一直保持每年翻一番的高增长,而比业务量增长更快的是 Hadoop 集群的数据量。
在这几年间,按 1 到 2 年规划的硬件,往往因数据增长超出预期而在半年后不得不再次扩容。每次扩容周期可达到一个月,除了花费大量精力跟进行政和技术流程,业务端也不得不安排较多人日控制数据量。如果选择购买硬盘和服务器来进行扩容,实施周期会相对较长。
存储计算耦合,容量规划难,容易错配。 传统的 Hadoop 架构中,存储和计算是紧密耦合的,难以根据存储或计算的需求独立进行扩容和规划。举个例子,假设我们需要扩容存储,于是首先需要购买一批新的硬盘,同时连带着需要购买计算资源。在最初时,计算资源可能会变得过剩,因为可能实际不需要那么多的计算资源,从而一定程度上导致了超前投资。
CDH 版本比较老,不敢升级。 我们因为集群也建的比较早了,为了稳定,也就不敢升级了。
运维成本较高(全公司仅 1 个全职运维)公司当时有 200 多个人,只有一个运维,这意味着运维工作的工作量很大。因此,我们希望能够采用更稳定、更简单的架构来提供支持。
机房存在单点风险。考虑到长远的因素,所有的数据都存储在同一个机房中,这存在一定的风险。例如,如果光缆被挖断,这种情况经常发生,那么我们仅有一个机房仍然会面临单点故障的风险。
考虑到这些因素和挑战,我们决定进行一些新的改变。以下是我们考虑架构升级的一些主要维度:
上云,弹性伸缩,灵活运维。利用云上的服务可以简化运维工作。例如,在存储方面,尽管 HDFS 本身是一个稳定且成熟的解决方案,但我们更愿意将时间投入到业务层面上,而不是底层的运维工作。因此,使用云服务可能更加简单。此外,通过利用云上的资源,我们可以实现弹性伸缩,无需等待长时间的硬件部署和系统配置周期。
存储计算分离。我们希望将存储和计算解耦,以实现更好的灵活性和性能。
尽量使用开源组件,避免云厂商绑定。尽管我们选择上云,但我们不希望过于依赖云服务本身。我们在为客户提供服务时会使用云原生的解决方案,例如使用 AWS Redshift 等,但我们在自身业务方面更倾向于使用开源组件。
尽可能与现有方案兼容,控制改动成本和风险。我们希望新架构与现有解决方案兼容,以避免引入额外的开发成本,并对我们的业务产生影响。
最终选择的方案是使用“阿里云 EMR + JuiceFS + 阿里云 OSS” 来搭建存算分离的大数据平台,将云下数据中心的业务逐步迁移上云。
这个架构使用对象存储来替代 HDFS,并选择了 JuiceFS 作为协议层,因为 JuiceFS 兼容 POSIX 和 HDFS 协议。在顶部,我们使用了云上半托管的 Hadoop 解决方案 EMR。它包含了很多 Hadoop 相关的组件,例如 Hive、Impala、Spark、Presto/Trino 等等。
一面数据架构图
首先是决定使用哪家云厂商。由于业务需求,AWS、Azure 和阿里云都有在用,综合考虑后认为阿里云最适合,有这些因素:
物理距离:阿里云在我们线下机房同城有可用区,网络专线的延迟小,成本低
开源组件齐全:阿里云 EMR 上包含的开源组件很多很全,除了我们重度使用的 Hive、Impala、Spark、Hue,也能方便集成 Presto、Hudi、Iceberg 等。我们在调研时发现只有阿里云 EMR 自带了 Impala,AWS 和 Azure 要么版本低,要么要自己安装部署。
阿里云的 EMR 本身也有使用 JindoFS 的存算分离方案,但基于以下考虑,我们最终选择了 JuiceFS:
JuiceFS 使用 Redis 和对象存储为底层存储,客户端完全是无状态的,可以在不同环境访问同一个文件系统,提高了方案的灵活性。而 JindoFS 元数据存储在 EMR 集群的本地硬盘,不便于维护、升级和迁移。
JuiceFS 的存储方案丰富,而且支持不同方案的在线迁移,提高了方案的可移植性。JindoFS 块数据只支持 OSS.
JuiceFS 以开源社区为基础,支持所有公有云环境,方便后期扩展到多云架构。
直接截取官方文档[1] 的介绍:
JuiceFS 是一款面向云原生设计的高性能共享文件系统,在 Apache 2.0 开源协议下发布。提供完备的 POSIX[2] 兼容性,可将几乎所有对象存储接入本地作为海量本地磁盘使用,亦可同时在跨平台、跨地区的不同主机上挂载读写。
JuiceFS 采用「数据」与「元数据」分离存储的架构,从而实现文件系统的分布式设计。使用 JuiceFS 存储数据,数据本身会被持久化在对象存储[3](例如,Amazon S3),相对应的元数据可以按需持久化在 Redis、MySQL、TiKV、SQLite 等多种数据库[4] 中。
除了 POSIX 之外,JuiceFS 完整兼容 HDFS SDK,与对象存储结合使用可以完美替换 HDFS,实现存储和计算分离。
JuiceFS 架构图
PoC 的目的是快速验证方案的可行性,有几个具体目标:
验证 EMR + JuiceFS + OSS 整体方案的可行性
检查 Hive、Impala、Spark、Ranger 等组件版本的兼容性
评估对比性能表现,用了 TPC-DS 的测试用例和部分内部真实业务场景,没有非常精确的对比,但能满足业务需求
评估生产环境所需的节点实例类型和数量(算成本)
探索数据同步方案
探索验证集群与自研 ETL 平台、Kafka Connect 等的集成方案
期间做了大量测试、文档调研、内外部(阿里云 + JuiceFS 团队)讨论、源码理解、工具适配等工作,最终决定继续推进。
我们在 2021 年 10 月开始探索 Hadoop 的上云方案;11 月做了大量调研和讨论,基本确定方案内容;12 月和 2022 年 1 月春节前做了 PoC 测试,在春节后 3 月份开始搭建正式环境并安排迁移。为了避免导致业务中断,整个迁移过程以相对较慢的节奏分阶段执行, 迁移完后,云上的 EMR 集群数据量预计会超过单副本 1 PB。
做完技术选型之后,架构设计也能很快确定下来。考虑到除了 部分业务仍然会保留在数据中心的 Hadoop 集群,所以整体实际上是个混合云的架构。
整体架构大致如上图所示:左侧是的线下机房,使用了传统的 CDH 架构和一些 Kafka 集群。右侧是部署在阿里云上的 EMR 集群。这两部分通过一条高速专线进行连接。顶部是 Airflow 和 OneWork,由于都支持支持分布式部署,因此可以轻松进行水平扩展。
我们 CDH 版本比较老,也不敢升级,但我们既然做了迁移,肯定还是希望新集群能够升级到新版本。在迁移过程中,需要注意 HDFS 2 和 3 之间的差异,接口协议和文件格式有可能会发生变化。JuiceFS 完美兼容 HDFS 2 & 3,很好地应对了这个挑战。
Spark 的一个升级对我们影响是比较大的,因为有不少不兼容的更新。这就意味着原来在 Spark 2 上面写的代码需要完成修改才能适配到新的版本里面去。
在机房环境中,默认使用的是 CDH 自带的 Hive on Spark,但当时 CDH 中的 Spark 版本只有 1.6。我们在云上使用的是 Spark 3,而 Hive on Spark 并不支持 Spark 3,这导致我们无法继续使用 Hive on Spark 引擎。
经过调研和测试,我们将 Hive on Spark 改为了 Hive on Tez。这个改动相对来说还比较容易,因为 Hive 本身对于不同的计算引擎提供了抽象和适配,所以对于我们的上层代码改动较小。Hive on Tez 在性能上可能略慢于 Spark。此外,我们也关注国内网易开源的一个新计算引擎 Kyuubi,它兼容 Hive,并提供了一些新特性。
对于 Hive 升级来说,最主要的影响之一是元数据结构的变化,因此在迁移过程中,我们需要进行数据结构的转换。因为无法直接使用 Hive 来处理这种迁移,所以我们需要开发相应的程序来进行数据结构的转换。
这是一个比较小的问题,就是我们之前使用 Sentry 做权限管理,这个社区不怎么活跃了,EMR 也没有集成,所以就替换为 Ranger。
除了技术挑战外,更大的挑战来自与业务端。
我们拥有多个业务,涉及不同的网站、客户和项目。由于业务交付不能中断,迁移过程必须进行分业务处理,采用渐进式迁移的方式。迁移过程中,数据的变动会对公司的多个环节产生影响,例如 ETL 数据仓库、数据分析师、测试和产品开发等。因此,我们需要进行良好的沟通和协调,制定项目管理计划和排期。
除了数据,我们在上层还有许多业务代码,包括数据仓库的代码、ETL 的代码以及一些应用程序的代码,如 BI 应用需要查询这些数据。
要迁移的数据包括两部分:Hive Metastore 元数据以及 HDFS 上的文件。由于不能中断业务,采用存量同步 + 增量同步(双写)的方式进行迁移;数据同步完后需要进行一致性校验。
对于存量文件同步,可以使用 JuiceFS 提供的功能完整的数据同步工具 sync 子命令[5] 来实现高效迁移。JuiceFS sync 命令支持单节点和多机并发同步,实际使用时发现单节点开多线程即可打满专线带宽,CPU 和内存占用低,性能表现非常不错。需要注意的是,同步过程中 sync 命令会在本地文件系统写缓存,因此最好挂载到 SSD 盘来提升性能。
Hive Metastore 的数据同步则相对麻烦些:
两个 Hive 版本不一致,Metastore 的表结构有差异,因此无法直接使用 MySQL 的导出导入功能
迁移后需要修改库、表、分区存储路径(即
dbs
表的DB_LOCATION_URI
和sds
表的LOCATION
)
因此我们开发了一套脚本工具,支持表和分区粒度的数据同步,使用起来很方便。
增量数据主要来自两个场景:Kafka Connect HDFS Sink 和 ETL 程序,我们采用了双写机制。
Kafka Connect 的 Sink 任务都复制一份即可,配置方式上文有介绍。ETL 任务统一在 OneWork 上开发,底层使用 Airflow 进行调度。通常只需要把相关的 DAG 复制一份,修改集群地址即可。实际迁移过程中,这一步遇到的问题最多,花了大量时间来解决。主要原因是 Spark、Impala、Hive 组件版本的差异导致任务出错或数据不一致,需要修改业务代码。这些问题在 PoC 和早期的迁移中没有覆盖到,算是个教训。
为了能让业务放心的使用新的架构,数据校验必不可少。数据同步完后需要进行一致性校验,分三层:
文件一致。在存量同步阶段做校验,通常的方式是用 checksum. 最初的 JuiceFS sync 命令不支持 checksum 机制,我们建议和讨论后,JuiceFS 团队很快就加上了该功能(issue,pull request[6])。除了 checksum,也可考虑使用文件属性对比的方式:确保两个文件系统里所有文件的数量、修改时间、属性一致。比 checksum 的可靠性稍弱,但更轻量快捷。
元数据一致。有两种思路:对比 Metastore 数据库的数据,或对比 Hive 的 DDL 命令的结果。
计算结果一致。即使用 Hive/Impala/Spark 跑一些查询,对比两边的结果是否一致。一些可以参考的查询:表 / 分区的行数、基于某个字段的排序结果、数值字段的最大 / 最小 / 平均值、业务中经常使用的统计聚合等。
数据校验的功能也封装到了脚本里,方便快速发现数据问题。
迁移完业务稳定运行后,我们开始考虑分级存储。分级存储在各种数据库或存储系统中都是一个常见问题,数据存在冷热区别,而存储介质的价格也存在差异,因此我们希望将冷数据存储在更便宜的存储介质上以控制成本。
在之前的 HDFS 中,我们已经实施了分级存储策略,购买了两种类型的硬盘,将热数据存储在高速硬盘中,将冷数据存储在低速硬盘中。
然而,JuiceFS 为了优化性能采取的数据分块模式,会对分级存储带来限制。按照 JuiceFS 的处理,当文件存储在对象存储上时,它被逻辑上拆分为许多 chunks、slices 和 blocks,最终以 block 的形式存储在对象存储中。
JuiceFS 数据分块示意图
因此,如果我们观察对象存储中的文件,实际上无法直接找到文件本身,而只能看到被分割成的小块。即使 OSS 提供了声明周期管理功能,但我们也无法基于表、分区或文件级别进行生命周期的配置。
后续我们通过以下这种方式来解决。
两个 bucket:标准( JuiceFS ) + 低频(OSS):创建两个存储桶,一个存储桶用于 JuiceFS,并将所有数据存储在标准存储层中。另外,我们额外创建一个低频的 OSS 存储桶。
基于业务逻辑,对表 / 分区 / 文件,配置存储策略表。我们可以根据表、分区或文件来设置存储策略,并编写定时任务来扫描并执行这些策略。
用 Juicesync 将低频文件从 JuiceFS 导出到 OSS 并修改 Hive 元数据。文件从 JuiceFS 转移到 OSS 之后会从 JuiceFS 删除,并且在 OSS 上能看到完整的文件内容,我们就可以对其设置生命周期规则。转移完文件后需要及时修改 Hive 元数据,,将 Hive 表或分区的位置更改为新的 OSS 地址。EMR 的 Hive/Impala/Spark 等组件原生支持 OSS,因此应用层基本无感(需注意访问低频文件会带来额外开销)。
完成这个操作后,除了实现分级存储以降低成本外,还有一个额外的好处是我们可以减少 JuiceFS 元数据的数量。因为这些文件不再属于 JuiceFS,而是由 OSS 直接管理,这意味着 JuiceFS 中的 inode 数量会减少,元数据的管理压力就会减轻,Redis 请求的数量和容量也会降低。从稳定性的角度来看,这对系统会更有利。
总的存储量增长了两倍,计算资源不动,偶尔开启临时的任务节点。在我们的场景中,数据量增长非常快,但查询需求相对稳定。从 2021 年至今,数据量已增长两倍。计算资源在初始阶段至今基本没有做过太多的改动,除非出于某些业务需求需要更快的计算速度,我们会开启弹性资源和临时任务节点来加速。
总体无明显感知,PoC 期间做过简单的 TPCDS 测试显示差异不大,ad-hoc 的 Impala 查询响应变快了
影响因素多:HDFS -> JuiceFS、组件版本升级、Hive 计算引擎变化、集群负载等
在我们的业务场景中,主要是进行大数据的批处理离线计算,总体而言对于性能的延迟并不敏感。
在 PoC 期间,我们进行了一些简单的测试。然而,这些测试很难准确说明问题,因为测试过程受到了许多影响因素的影响。我们首先更换了存储系统,从 HDFS 切换到了 JuiceFS,同时进行了组件版本升级,Hive 引擎也发生了变化。此外,集群负载也无法完全一致。在我们的场景中,与之前在物理服务器上部署的 CDH 相比,集群架构的性能差异并不明显。
JuiceFS 本身没出过问题
EMR 的使用有遇到些小问题,总体上 CDH 更稳定易用
我们的场景里, 增量双写 & 数据校验过程花的时间最多(回过头看校验的投入过大,可以精简) ;
影响因素多:跟业务场景(离线 / 实时、表 / 任务数量、上层应用)、组件版本、配套工具和储备。
当评估类似架构或方案的复杂度时,有许多影响因素需要考虑。其中包括业务场景的差异,以及对延迟要求的敏感程度不同。此外,表数据量的规模也会产生影响。在我们的场景中,我们有大量的表和数据库,文件数量相对较多。此外,上层应用程序的特性、使用业务的数量以及相关程序等也会对复杂度产生影响。另一个重要的影响因素是版本迁移的逐渐差异。如果只进行平移而保持版本不变,那么组件的影响基本上可以消除。
配套工具和储备是一个重要的影响因素。在进行数仓或 ETL 任务时,有多种实现方式可供选择,例如手动编写 Hive SQL 文件、Python 或 Java 程序,或者使用常见的调度工具。但无论采用哪种方式,我们都需要复制和修改这些程序,因为双写是必要的。
我们使用自研的开发平台 OneWork,在任务配置方面非常完善。通过 OneWork 平台,用户可以在 Web 界面上配置这些任务,从而实现统一管理。Spark 任务的部署也无需登录到服务器上操作,OneWork 会自动提交到 Yarn 集群。这个平台大大简化了代码配置和修改的过程。我们编写了一个脚本将任务配置复制出来,进行一些修改,就可以实现高度的自动化程度,几乎达到百分之八九十,从而顺利运行这些任务。
后续计划大致有几个方向:
继续完成剩余业务的上云迁移;
探索 JuiceFS + OSS 的冷热分级存储策略。JuiceFS 的文件在 OSS 上完全被打散,无法基于文件级别做分级。目前的思路是将冷数据从 JuiceFS 迁移到 OSS 上,设置为归档存储,修改 Hive 表或分区的 LOCATION,不影响使用;
目前 JuiceFS 使用 Redis 作为元数据引擎,假如将来数据量增加,使用 Redis 有压力的话可能考虑切换为 TiKV 或其他引擎;
探索 EMR 的弹性计算实例,争取能在满足业务 SLA 的前提下降低使用成本。
能提供专线服务的供应商很多,包括 IDC、阿里云、运营商等,选择的时候主要考虑线路质量、成本、施工周期等因素,最终我们选择了 IDC 的方案。IDC 跟阿里云有合作,很快就完成了专线的开通。这方面如果遇到问题,可以找 IDC 和阿里云的支持。除专线租用成本,阿里云也会收取下行(从阿里云到 IDC)方向传输费用。专线两端的内网 IP 完全互通,阿里云和 IDC 两侧都需要一些路由配置。
JuiceFS 可以使用本地硬盘做缓存[7],能进一步减少 OSS 带宽需求并提高 EMR 性能。更大的本地存储空间,可以提供更高的缓存命中率。
阿里云本地 SSD 实例是较高性价比的 SSD 存储方案(相对于云盘),用作缓存正合适。JuiceFS 社区版未支持分布式缓存,意味着每一个节点都需要一个缓存池,所以应该选用尽量大的节点。
基于以上考虑和配置对比,我们决定选用 ecs.i2.16xlarge,每个节点 64 vCore、512GiB Memory、1.8T*8 SSD。
软件方面,主要包括确定组件版本、开启集群、修改配置。我们机房使用的是 CDH 5.14,其中 Hadoop 版本是 2.6,阿里云上最接近的版本是 EMR 3.38. 但调研时发现该版本的 Impala 和 Ranger 不兼容(实际上我们机房使用的是 Sentry 做权限管理,但 EMR 上没有),最终经过评估对比,决定直接使用 EMR 5 的最新版,几乎所有组件的大版本都做了升级(包含 Hadoop 3、Spark 3 和 Impala 3.4)。此外,使用外部 MySQL 作为 Hive Metastore、Hue、Ranger 的数据库。
基本参考 JuiceFS 官方文档《在 Hadoop 中通过 Java 客户端访问 JuiceFS[8]》即可完成配置。另外我们也配置了这些参数:
缓存相关:其中最重要的是
juicefs.cache-dir
缓存目录。这个参数支持通配符,对多个硬盘的实例环境很友好,如设置为/mnt/disk*/juicefs-cache
(需要手动创建目录,或在 EMR 节点初始脚本中创建),即用全部本地 SSD 作为缓存。另外也要关注juicefs.cache-size
、juicefs.free-space
两个参数。juicefs.push-gateway
:设置一个 Prometheus Push Gateway,用于采集 JuiceFS Java 客户端的指标。juicefs.users
、juicefs.groups
:分别设置为 JuiceFS 中的一个文件(如jfs://emr/etc/users
、jfs://emr/etc/groups
),解决多个节点 uid 和 gid 可能不统一的问题。
经过一些测试,确认 JuiceFS 可以完美应用于 Kafka Connect 的 HDFS Sink 插件(我们把配置方式也补充到了官方文档[9])。相比使用 HDFS Sink 写入 HDFS,写入 JuiceFS 需要增加或修改以下配置项:
将 JuiceFS Java SDK 的 JAR 包发布到 Kafka Connect 每一个节点的 HDFS Sink 插件目录。Confluent 平台的插件路径是:
/usr/share/java/confluentinc-kafka-connect-hdfs/lib
编写包含 JuiceFS 配置的
core-site.xml
,发布到 Kafka Connect 每一个节点的任意目录。包括这些必须配置的项目:
fs.jfs.impl = io.juicefs.JuiceFileSystem
fs.AbstractFileSystem.jfs.impl = io.juicefs.JuiceFS
juicefs.meta = redis://:[email protected]:6379/1
请参见 JuiceFS Java SDK 的配置文档。
hadoop.conf.dir=<core-site.xml 所在目录>
store.url=jfs://<JuiceFS 文件系统名称>/<路径>
在整个实施过程中陆陆续续踩了一些坑,积累了一些经验,分享给大家做参考。
兼容性
EMR 5 的 Hive 和 Spark 版本不兼容,无法使用 Hive on Spark,可以把默认的引擎改成 Hive on Tez.
Impala 的 stats 数据从旧版同步到新版后,可能因为 IMPALA-10230[10] 导致表无法查询。解决方案是在同步元数据时,将
num_nulls=-1
的改成num_nulls=0
. 可能需要用到 CatalogObjects.thrift[11] 文件。原集群有少量 Textfile 格式的文件用了 snappy 压缩,新版 Impala 无法读取,报错
Snappy: RawUncompress failed
,可能是 IMPALA-10005[12] 导致的。规避方案是不要对 Textfile 文件使用 snappy 压缩。Impala 3.4 相比 2.11 的
CONCAT_WS
函数行为有差异,老版本CONCAT_WS('_', 'abc', NULL)
会返回NULL
,而新版本返回'abc'
.Impala 3.4 对 SQL 中的保留关键字引用更严格,必须加上 “''”. 其实一个好习惯是业务代码不要使用保留关键字。
PoC 或前期测试的覆盖度尽可能完整,用真实的业务代码去跑。我们在 PoC 和早期迁移的业务中用到的组件特性比较少,基本都是最常用、保持兼容的功能,因此比较顺利。但在第二批迁移过程中就暴露出了很多问题,虽然最终都有解决,但花了很多额外的时间去做诊断和定位,打乱了节奏。
性能
EMR 5 的 Impala 3.4 打了 IMPALA-10695[13] 这个补丁,支持对
oss://
和jfs://
(本意是支持 JindoFS,但 JuiceFS 也默认使用 jfs 这个 scheme)设置独立的 IO 线程数。在 EMR 控制台上增加或修改 Impala 的配置项num_oss_io_threads
.阿里云 OSS 有账号级别的带宽限制,默认 10Gbps,随着业务规模上升容易成为瓶颈。可以与阿里云沟通调整。
运维
EMR 可以关联一个 Gateway 集群,通常用来部署业务程序。如果要在 Gateway 上用 client 模式提交 Spark 任务,需要先将 Gateway 机器的 IP 加到 EMR 节点的 hosts 文件。默认可以使用 cluster 模式。
EMR 5 会开启一个 Spark ThriftServer,在 Hue 上可以直接写 Spark SQL,用起来很方便。但默认配置有个坑,会写大量日志(路径大概是
/mnt/disk1/log/spark/spark-hadoop-org.apache.spark.sql.hive.thriftserver.HiveThriftServer2-1-emr-header-1.cluster-xxxxxx.out
),导致硬盘写满。解决方案有两个:配置 log rotate 或把spark.driver.extraJavaOptions
配置清空(阿里云技术支持的建议)。
JuiceFS 相关
JuiceFS 需要每个节点上具有相同的 UID 和 GID,否则很容易出现权限问题。有两种实现方式:修改操作系统的用户[14](比较适合新机器,没有历史包袱),或者在 JuiceFS 上维护一个用户映射表[15]。我们之前也分享过一篇 JuiceFS + HDFS 权限问题定位[16],有详细讨论。通常需要维护映射的用户有 impala, hive, hadoop 等。如果使用 Confluent Platform 搭建 Kafka Connect,也需要配置 cp-kafka-connect 用户。
使用默认的 JuiceFS IO 配置[17] 时,相同的写查询,Hive on Tez 和 Spark 都比 Impala 快很多(但在机房里 Impala 更快)。最终发现将 juicefs.memory-size 从默认的 300 (MiB) 改成 1024 之后 Impala 的写入性能有成倍的提升。
在做 JuiceFS 的问题诊断和分析时,客户端日志很有用,需要注意 POSIX 和 Java SDK 的日志是不一样的,详见 JuiceFS 故障诊断和分析 | JuiceFS Document Center[18]
注意监控 Redis 的空间用量,Redis 如果满了,整个 JuiceFS 集群无法写入。(这点需要特别注意) 使用 JuiceFS sync 把机房数据往云上同步时,选择在有 SSD 的机器上跑,获得更好的性能。
一面数据创立于 2014 年,是一家领先的数据智能解决方案提供商,通过解读来自电商平台和社交媒体渠道的海量数据,为企业提供实时、全面的数据洞察。长期服务全球快消巨头(宝洁、联合利华、玛氏等),获得行业广泛认可。公司与阿里、京东、字节合作共建多个项目,旗下知乎数据专栏“数据冰山”拥有超 30 万粉丝。一面所属艾盛集团(Ascential)在伦敦证券交易所上市,在 120 多个国家为客户提供本地化专业服务。
刘畅,一面数据运维负责人
李阳良,一面数据大数据部门负责人
B 站回顾视频:https://www.bilibili.com/video/BV1im4y1J7GP/
[1]
官方文档: https://juicefs.com/docs/zh/community/introduction/
[2]
POSIX: https://en.wikipedia.org/wiki/POSIX
[3]
对象存储:https://juicefs.com/docs/zh/community/how_to_setup_object_storage# 支持的存储服务
[4]
数据库: https://juicefs.com/docs/zh/community/databases_for_metadata
[5]
sync 子命令: https://juicefs.com/docs/zh/community/administration/sync
[6]
issue,pull request: https://github.com/juicedata/juicefs/pull/1208
[7]
缓存: https://juicefs.com/docs/zh/community/cache_management
[8]
在 Hadoop 中通过 Java 客户端访问 JuiceFS: https://juicefs.com/docs/zh/cloud/use_juicefs_sdk_in_hadoop/#%E9%98%BF%E9%87%8C%E4%BA%91-emr
[9]
官方文档: https://juicefs.com/docs/zh/community/hadoop_java_sdk#kafka-connect
[10]
IMPALA-10230: https://issues.apache.org/jira/browse/IMPALA-10230
[11]
CatalogObjects.thrift: https://github.com/apache/impala/blob/3.x/common/thrift/CatalogObjects.thrift
[12]
IMPALA-10005: https://issues.apache.org/jira/browse/IMPALA-10005
[13]
IMPALA-10695: https://issues.apache.org/jira/browse/IMPALA-10695
[14]
修改操作系统的用户: https://juicefs.com/docs/zh/community/sync_accounts_between_multiple_hosts
[15]
用户映射表: https://juicefs.com/docs/zh/community/hadoop_java_sdk/#%E5%85%B6%E5%AE%83%E9%85%8D%E7%BD%AE
[16]
JuiceFS + HDFS 权限问题定位: https://zhuanlan.zhihu.com/p/452232533
[17]
JuiceFS IO 配置: https://juicefs.com/docs/zh/community/hadoop_java_sdk#io-%E9%85%8D%E7%BD%AE
[18]
JuiceFS 故障诊断和分析 | JuiceFS Document Center: https://juicefs.com/docs/zh/community/fault_diagnosis_and_analysis
你也「在看」吗? 👇
微信扫码关注该文公众号作者