一、Alluxio 介绍
1、背景介绍
当前计算引擎越来越多样化,存储系统和部署环境也越来越复杂。不同的计算和存储适用于不同的场景。比如 Presto 的即席查询性能比较好,比 Spark 要快很多,而 Spark 又更适合于批量处理。存储系统也是一样的,常用的 HDFS 是一个可以存取海量数据的存储系统,但有些场景下又希望能够使用存储密度更高的存储系统。与此同时,部署方式也在不断变化,比如之前一般使用的是 CDH,将来可能会用 Ambari 这样一个开源的方式,还可能会考虑使用容器化的部署,为将来的云化做一个铺垫。
环境的日趋复杂化,带来了很多问题与挑战。比如我们在实践过程中,为了建设数据湖仓,必须要引入 Iceberg,但是已有的 HDFS 是 2.6.x,Spark 是 1.6.x,对 Iceberg 是不支持的。为了引入 Iceberg,HDFS 要升级到 3.x,Spark 也要升级,才能建设成一个整体。
在这样一个过程中,我们面对了四点比较突出的问题:
- 高耦合:计算引擎与存储系统已经形成了一个整体,任意一方的升级或者变更,都意味着需要重新考虑兼容性的问题。
- 难迭代:计算引擎需要使用不同 API 去访问不同的存储系统,数据的跨存储系统迁移往往需要兼顾计算机应用,甚至需要重新开发。
- 难迁移:从本地集群的部署方式平滑迁移为云部署的难度高,不仅维护成本高,还很难适应混合云环境。
- 持续性的迭代压力:任何方案都会过时,想要追逐技术前沿,就需要面对持续性的迭代压力。
2、数据编排概览
Alluxio 是一种基于数据编排技术的开源组件。
数据编排技术是位于存储层与计算层之间的一个抽象层。它可以将复杂多样的底层存储进行包装,向上提供统一的访问路径,兼容多种访问协议,以应对多样化的存储需求与应用计算之间的矛盾。为数据驱动的应用程序提供数据可访问性、数据本地性和数据可伸缩性。
Alluxio 可以带来如下一些好处:
Alluxio 可以跨存储系统将数据访问抽象出来,计算引擎只需使用标准 API 就可以访问不同存储系统中的数据。
Alluxio 允许挂载多个不同的存储系统以及不同版本的相同存储系统,解耦计算与存储,方便存储系统的升级和引入过程。
Alluxio 具有缓存功能,加速访问热数据。
Alluxio 是云原生的,可以在任何云中快速搭建数据编排层。
Alluxio 为数据驱动型应用和存储系统构建了桥梁,使得应用程序能够通过一个公共接口连接到多种存储系统。与此同时,Alluxio 内存至上的层次化缓存架构使得数据的访问速度比现有方案快几个数量级,非常适合 IO 成为瓶颈的存算分离场景。
Alluxio 的最上层是计算层,最底层是存储层,中间是数据编排层。计算层通过多种标准数据访问 API 来访问数据编排层。编排层负责对多种存储系统的访问。
3、Alluxio 架构设计
计算应用通过 Alluxio Client从Alluxio Master 获取 AlluxioWorker 节点与默认配置,并与 Worker 建立连接进行数据读写。在这个过程中,Alluxio Client 会将计算应用的 API 进行自动转换,让整个过程对于计算应用是透明的。
Alluxio Master 基于 zookeeper 或者内嵌的 Raft 服务实现 HA,并负责维护默认配置、协调 Worker 节点、接收请求、块位置等工作。
Alluxio Worker 的职责包括:
- 跨存储系统的数据读写:Alluxio Worker 主要负责与底层存储系统进行交互,它不仅实现了不同存储系统的 API,还可以自动转换,实现了跨存储系统的数据读写。
- 多级缓存:Alluxio Worker 维护了一个多级缓存,用以加速热数据的访问,减少读取底层存储的次数。而基于块注释的缓存设计,不仅可以为热数据提供最佳性能,还能在缓存空间不足时自动释放较冷的数据,以非常自然的方式实现了数据的冷热分离。
- 访问短路:当计算应用与 Alluxio Worker 处于同一节点时,还可以直接通过 NIO 进行短路交互,进一步优化数据的访问链路,减少响应时间。
- 弹性部署:Alluxio Worker 在启动时会主动向 AlluxioMaster 注册自己,并通过心跳机制维持存在,而基于数据易失性的设计,可以让用户根据需要,灵活的进行水平拓展或者缩容。
4、Alluxio 核心功能
(1)统一命名空间
- 灵活挂载
Alluxio 的根挂载点需要在启动时指定,绑定 Alluxio 的根目录。嵌套挂载点则可以在任意 Alluxio 子目录上通过命令行指定。嵌套挂载点的数量没有限制,可以分别挂载不同的存储系统,或者相同存储系统的不同版本。 - 访问控制
用户通过 Alluxio 访问底层存储时,只能访问挂载在 Alluxio 上的目录,同时 Alluxio 也可以将挂载点设定为 read-only,进一步限制用户对底层存储的访问。这是区别于用户权限管理的强制限制。 - 访问透明
用户通过 Alluxio 访问底层存储时,并不需要感知底层存储系统的类别、版本,也不需要关注挂载点(某些情况除外)。在大部分场景中,通过 Alluxio,用户可以无感知地访问挂载其上的底层存储。
(2)缓存
- 缓存读写策略
读:NO_CACHE(Alluxio 仅作为代理,不做缓存),CACHE_PROMOTE(尽量放到缓存最上层),CACHE。
写:THROUGH(Alluxio 仅作为代理,不做缓存),CACHE_THROUGH(写入存储时备份到缓存空间中,适合于写入后还需要读的场景),ASYNC_THROUGH(异步写),MUST_CHACHE(仅写入缓存空间)。 - 缓存管理
块注释策略:根据块注释策略为数据块进行排序,位于序列尾部的数据块将作为优先的空间释放对象。
最少最近策略
基于权重的最少最近策略
缓存分层:数据块可能已配置存储层中,基于块注释策略,Alluxio 会在各存储层中移动数据块,包括块对齐、块升级、迁移任务退后等。
缓存驱逐:当 Alluxio 的存储空间不足时,无法接受新数据的写入,会基于注释策略释放存储空间,这个过程叫做缓存驱逐。它保证了 Alluxio 总是存储着热数据,但也会在某些场景下造成缓存命中率降低的问题。 - 缓存生命周期
数据操作:LOAD(加载数据到缓存空间),PERSIST(缓存空间中的数据回写到底层存储),FREE(只清除缓存空间中的数据,不动底层存储数据),DELETE(缓存空间和底层存储的数据都清除)
TTL:Alluxio 可以为文件和目录设置生存时间,当生存时间到达时,执行一种数据操作,默认为 DELETE。这样可以对缓存空间进行策略化管理。
元数据同步:Alluxio 可以为文件和目录设置元数据检查周期,当缓存过期时,会自动从 UFS 重新加载。如果每次访问都同步底层存储,开销会比较大,因此可以根据应用场景进行定制。如果对数据时效性比较敏感,底层存储的任何更新,在通过 Alluxio 去访问时都希望能感知到,这时就可以设置每次读之前同步元数据。而大多数情况下,对数据时效性没有那么敏感,那么就可以根据需要设置同步的时间间隔。
二、Alluxio 实践分享
1、长链计算任务的迁移需要兼顾上下游依赖关系
建设湖仓一体化,不可避免的一个问题就是如何去做数据迁移,以及生成这个数据的长链任务的迁移。如果没有数据编排层去做迁移,需要兼顾上下游的数据关系。有了编排层,如图所示,首先将旧集群中的数仓和新的湖仓进行元数据同步,可以看到旧的数仓和新的湖仓均含有两张表,但实际上从底层来看,这两张表的数据只维护了一份,好处是不需要在两个集群里面都维护相同的数据,减少了存储的压力,同时可以避免数据不一致的问题。通过 Alluxio 将元数据同步,做迁移时就可以只迁移该任务所依赖的数据本身,这样任务迁移就变得非常灵活。
2、利用高速的缓存空间加速数据的读写
在加速场景里面,我们根据不同的应用场景,使用不同的 Alluxio 集群。
- 将 Trino 和 Alluxio 混合部署在 SSD 集群上(混合部署时性能最佳),利用 Alluxio 缓存空间加速热数据的加载。
- 对于热度不高的数据也可以通过直连底层存储进行访问。
- Spark shuffle 加速主要基于 Spark RSS 这边的接口,每个公司使用不同的产品,Alluxio 集群可以整合空闲的内存或是零散的 SSD 空间,把这些空间充分地利用起来。
- 利用 Alluxio 可以将 RSS 产生的 IO 占用限制在指定集群、节点或者磁盘上,减少集群的 IO 竞争带来的任务时长波动。
3、提供数据本地性,将需要单点部署的应用与大数据存储直接连通
(1)痛点:
- 有些 AI 计算需要部署在装有 GPU 的特定机器上,与大数据集群环境天然隔离;
- 算法工程师需要学习并实现特定存储系统的 API 才能去读写数据;
- 部分计算应用需要将原始数据拉取到本地才能进行计算,但是本地节点的磁盘空间有限。
(2)优化:
- Alluxio 支持 POSIX API,它可以直接 mount 到本地节点的目录上,连通大数据存储与本地节点。
- 算法工程师可以像读写本地文件一样读写大数据存储上的数据,而不必关注远端存储系统,从而节省学习和开发成本。
- 为本地节点提供集群级别的存储空间,并提供最高内存级别的数据读写速度。
4、两种实现冷热分离的架构
Alluxio 实现冷热分离有两种方式,一种方式是可以在存储层做冷热分隔。如果一个集群性能比较高,主要是热数据,另一个集群数据都是冷数据,但是存储密度高。当数据变冷时,需要人工将数据从高性能的集群迁移到高存储密度的集群,从而实现冷热分离,这样对于上层应用不太友好,底层数据在迁移的时候,目录、命名空间不一样,用 Alluxio 就可以避免这些问题。在此过程中 Alluxio 仅需要作为一个代理,不需要缓存空间,仅需要满足 IO 计算。这种方式对 Alluxio 本身的缓存能力没有很高的要求。
第二种方式是利用 Alluxio 直接做一个上下层的冷热分离,在此过程中 Alluxio 作为编排层,直接放热数据,存储层直接放冷数据。冷数据可以通过预加载的方式暖起来,把数据写进缓存空间。这种方式需要 Alluxio 提供一个较大的缓存空间。
实践中,我们综合使用了两种方式。整体上是以第一种方式为主,我们有一个高性能的集群和一个高存储密度的集群。与此同时,也为 Alluxio 配置了一些缓存空间,来进一步提升性能。
5、大数据架构演变
Alluxio 带来的大数据架构演变过程如上图所示。
- 引入Alluxio,实现缓存加速。
- Alluxio 挂载多个存储系统,助力存储升级和数据迁移,数据在逻辑层面实现存算分离。
- 将计算应用做容器化改造,与 Alluxio 一起迁移到 K8s 中,完全实现存算分离,具备上云的条件。
- 根据业务需求,为不同的计算应用单独定制 Alluxio 集群,满足个性化需要。
三、展望
最后来分享一下未来的规划。
1、更轻:轻量部署无负重
通过引入 Alluxio,我们可以将计算应用与存储系统解耦,进而减少大数据架构迭代的难度和成本。Alluxio 的部署已经足够灵活简单,但我们仍然希望有更轻量、更无侵入的部署方式或配置项:
- 更灵活的逻辑域名配置项,避免修改 core-site.xml
- 客户端级别的可配置化的访问映射,避免修改 HMS
- 集成度更高的服务端进程
2、更快:让快变得更快
通过利用 Alluxio 的缓存空间,计算应用可以获得最高内存级别的读写加速,并减少与底层存储的 I/O 吞吐,获得全方位的数据加速体验。但在复杂的部署环境中,我们希望获得一些新的特性,让快变得更快。
- 更丰富的缓存请求分配策略(例如给 LocalFirst 增加备选策略)
- 跨集群数据读写的 I/O 限流
- 基于客户端的 UFS 读写(例如客户端从 worker 获取挂载信息和配置后自己去读)
3、更稳定:稳定可靠控风险
通过引入 Alluxio,我们将存储系统置于更底层,由 Alluxio 与计算应用进行交互,这带来了许多稳定性上的好处,例如审计日志、Metrics、访问控制等等,但也带来了一些新的挑战,等待我们去探索更稳定的集群环境:
- 基于 tag 或者用户组的缓存配额
- AlluxioWorkerJVM 与 RAM 缓存的内存统一
- 本地缓存数据的故障载入
关键字:
声明:我公司网站部分信息和资讯来自于网络,若涉及版权相关问题请致电(63937922)或在线
提交留言告知,我们会第一时间屏蔽删除。