基于 Alluxio 构建统一数据接入层

01 背景

       首先介绍一下我们的机房分布,出于成本和容灾的考虑,知乎是多云混合的架构,架构图如下:

图片

       离线机房: 专为满足大数据相关业务方需求而设计的离线计算服务中心。其主要职能是部署离线调度、离线存储以及调度平台等服务。这些服务的目标是提供高效的离线数据处理和计算能力。在离线机房中,大数据业务方可以安心进行批量数据处理和计算任务,从而满足他们对数据处理、存储和调度的要求。

       在线机房: 此机房专为知乎主站提供直接面向用户的服务而设计。其中包括评论、回答、搜索、推荐等核心服务。在线机房的重点在于实时性和响应速度,以确保用户能够在最短的时间内获得稳定、高效的服务体验。知乎主站作为一个知识社区,其在线机房是为了保障用户对知识和信息的交流与分享能够得到优质、连续的支持。

       GPU 机房: 此机房专门用于部署机器学习平台,主要服务于算法用户。其主要特点是提供强大的 GPU 资源管理、模型训练、数据集导入导出等一站式解决方案。GPU 机房的核心任务是为算法用户提供高性能计算资源,以满足机器学习模型训练和推理的要求。这样的设计能够使算法用户更专注于模型的研发与优化,而不必担心计算资源的供给。

       多云架构给存储带来了新的挑战,相比于单一机房,需要额外考虑专线容量和网络延迟对存储系统带来的影响。就算法场景而言,模型的训练与上线都需要考虑对专线的影响,避免跨专线读取过多的数据,导致专线被打满,从而影响其他的跨云服务。在前一段时间,我们小试牛刀,将 Alluxio 用在了大语言模型的训练与推荐搜索模型的上线中,利用其缓存能力,解决了算法跨云使用数据的性能问题与专线流量问题,并取得了不错的效果,感兴趣可以查看多云缓存在知乎的探索。(https://zhuanlan.zhihu.com/p/622005118)

图片

        随着大语言模型项目的快速迭代和开发,我们对 Alluxio 的理解和使用有了更深入的认识,同时也发现 Alluxio 的价值远不止于此。借助于 Alluxio 的缓存和统一命名空间这两个核心能力,我们成功构建了一个统一数据接入层,进一步提升了数据处理的效率和管理的便利性。

02 大语言模型训练与数据管理

       总所周知,大语言模型训练所需的数据集以及训练产出的模型本身都是十分珍贵的,因此我们希望算法用户在使用它们时,受到到严格的权限控制,来避免模型和数据集的泄露,从而保护公司的资产。

       首先是底层数据的安全性保障,我们的数据都是存放在 HDFS 上,而我们的 HDFS 目前的认证和授权是基于组账号和 HDFS ACL 实现,是一个粗粒度的管控。可以预想到,按组账号进行用户认证,必然会导致用户认证信息在同一小组的成员之间口口相传。而且每个人对于安全的认知具有差异,这就可能会出现有一些安全防范意识薄弱的同事,会将 HDFS 的认证信息写入到 Gitlab 项目的配置或者代码中,造成用户认证信息泄露。虽然安全部门的同事可能会及时检测到此类情况,但我们很难确定认证信息是否已经遭到泄露。因此,我们与安全部门和算法团队合作,共同制定了一套全新的安全方案。

下面介绍我们的方案:

  1. 搭建一套全新的 HDFS 集群专供大语言模型训练,而不是与其他用户共享同一套 HDFS;

  2. 利用云厂商提供的安全组策略,给独立 HDFS 集群在网络层面配置访问权限,HDFS 机器所使用的网络策略我们叫做黑箱策略,这些机器叫做黑箱机器;

  3. 只有特定的机器才能访问黑箱机器,并且黑箱策略具有传染性,任何可以访问黑箱的机器也会划入黑箱中,被黑箱策略限制;

  4. 少量黑箱外的机器可以访问黑箱内的特定服务,用于数据集或模型的导出,这些机器叫做灰箱机器。灰箱机器被严格监控和限制,有任何异常行为将会直接发出报警,并且在企业微信群提醒所有相关同事。

       总之,我们的方案核心思想是将大语言模型训练所需的所有服务部署在受黑箱策略限制的机器上。虽然这将增加一定的运维负担,但它能够最大程度地保障模型和数据集的安全性。

       我们大语言模型训练的最终架构图如下:

图片

整个模型训练的流程如下:

  1. 原始未经处理的数据集存储在离线 HDFS 上,经过离线 Spark 集群进行清洗和处理;

  2. 清洗后的优质数据集被转移到黑箱 HDFS,为模型训练提供支持;

  3. 用户在读取或写入模型数据集时,通过 Alluxio Fuse 实现数据读写,网络策略限制了用户直接访问黑箱 HDFS 和离线 HDFS;

  4. 模型训练容器在启动时,根据任务声明的数据集需求,挂载相应数据集存放目录,确保任务间数据隔离;

  5. Alluxio 以只读方式挂载离线 HDFS 上的数据,确保模型训练容器能够访问离线 HDFS 数据,但不能向其写入数据;

  6. 黑箱 HDFS 生成的审计日志将被导入 Kafka,由 Flink 进行消费和行为统计,异常行为将立即触发报警。

       在整个训练流程中,Alluxio 作为大语言模型与 HDFS 数据的桥梁,为模型训练提供了高效且安全的数据访问:

        首先,我们借助 Alluxio 的高性能缓存能力,提高了模型训练数据集跨云访问的效率,高效的 IO 可以使得 GPU 利用率得到极大的提高;

        其次,我们利用 Alluxio 的统一命名空间功能,将多个 HDFS 挂载到 Alluxio 上,为模型训练提供了灵活且统一的数据访问能力,由于 Alluxio 可以灵活配置 UFS 的只读属性,我们可以保证数据不外泄;

        最后,得益于 Alluxio Fuse 对本地文件系统可以灵活挂载,我们实现了数据集的隔离管控

        虽然 Alluxio 功能强大,但是也不是万能的,我们仍有一些问题没有解决:

        一方面,因为 Alluxio 目前不支持随机写入,所以面对随机写入的场景,我们只能选择将数据写入本地磁盘或者支持随机写入的文件系统,最后再由算法平台同步数据至 HDFS。

        另一方面,因为 Alluxio 目前没有提供类似 HDFS DataNode 的 Pipline 写入方式,所以我们无法一次性向 Alluxio 写入多个副本,而单副本写入我们又担心数据丢失,所以我们写数据时,没有采用异步写的方式, 而是通过 Alluxio Fuse 向 HDFS 同步写入,尽管在效率上不如异步写入。

03 推荐/搜索模型训练

        这一节介绍我们简单介绍推荐/搜索模型的训练。推荐/搜索模型的训练一直是专线带宽消耗的主力,虽然我们提供了 UnionStore(自研组件)作为数据接入层来供算法用户使用,但是因为性能的原因,只有少量的用户进行了接入,在很长一段时间里,大部分用户还是直连 HDFS 读写模型与数据。模型训练的架构图如下,其中 UnionStore 是我们的自研组件:

图片

        直连 HDFS 的方式虽然在短期内能够满足用户的需求,但是也有一些隐患,随着模型训练规模的扩大,从 HDFS 读取训练数据的流量也会越来越大,并且由于我们 GPU 机房读取离线 HDFS 数据需要通过两次专线(离线机房 → 在线机房 → GPU 机房),我们很难保证机房之间的专线不被打满,而扩容专线的成本又非常高,所以我们必须寻找可靠的缓存组件来缓解专线流量的问题。我们在大语言模型训练中,积累了 Alluxio 的使用经验,而 Alluxio 也确实能够比较好地满足我们的需求,所以在推荐/搜索模型训练的场景,我们依然选择了 Alluxio。推荐/搜索模型的训练流程与大语言模型的流程基本一致,唯一的区别在于训练不在黑箱中完成,架构图如下:

图片

        不管是大语言模型训练还是推荐/搜索模型的训练,我们都遇到了 Alluxio Fuse 同步写 HDFS 性能不达标的情况,这是因为 Alluxio 原生同步写入 HDFS 的效率最高只能与直接写 HDFS 持平,相比于异步写入 NVMe 磁盘部署的 Alluxio,速度差距在十倍以上,因此我们开发了 Alluxio Fuse 同步写入 HDFS 的新方案,下面介绍我们同步写入 HDFS 加速方案:

  1. 在 Alluxio Fuse 内维护一个内存池,内存池内有多个内存块;

  2. Alluxio Fuse 在接受用户写入的时候,不直接向 HDFS 写,而是向内存池申请空闲的内存块,如果申请到内存块了,就写入到内存块;如果没有申请到内存块,就走正常的写入逻辑;

  3. 内存块写满了以后,由 Alluxio Fuse 内维护的线程池将数据异步上传到 HDFS 上的一个临时文件,上传完成后向内存池归还内存块;

  4. 重复步骤 2 直到用户写完, 在 close 文件时,Alluxio Fuse 会等待所有的内存块上传完成,然后利用 HDFS 的 concat 命令将所有的临时文件拼接成一个完整的文件,最后将文件 rename 到对应的路径。

这样写入有以下几个好处:

  1. 文件在写入时,具有原子性,不会存在中间状态,写入要么成功文件可见,要么失败文件不可见;

  2. 在将内存块上传至 HDFS 的临时文件时,可以进行多次重试,提高写 HDFS 的成功率,这对我们在前一段时间遇到的问题有很大的帮助:我们的 DataNode 因为使用了存储密集机型,达到了 Block 锁的瓶颈(已通过拆分读写锁等方案解决),从而导致算法业务在向 HDFS 写大文件时,失败率偏高;

  3. 上传内存块的数据到 HDFS 的过程是由后台线程池完成,可以支持极高的并发,在用户向 Alluxio Fuse 写入文件的整个过程中,相当于直接写入内存,能够达到极高的写入速度。我们测试用户单线程写入 Alluxio Fuse,Alluxio Fuse 5 个后台线程向 HDFS 上传数据时,能够达到 1GB/sec 的写入速度。

需要注意以下几点:

  1. 如果是有 Federation 的 HDFS,临时文件的路径一定要考虑 NameService,临时文件和写入的路径一定要在同一个 NameService 下,否则会出现 rename 的错误;

  2. 内存池内的每个内存块尽量要与 HDFS block 大小对齐(一般为 64MB 或 128MB),太小会导致文件的 block 过多,对 NameNode 产生较大的压力;

  3. 此方案虽然只适用于 HDFS,但是思路是通用的,对于其他的 UFS 比如对象存储,可以考虑用 MutipartUpload 实现。

        推荐/搜索模型训练使用 Alluxio 后,专线流量能够显著降低,特别是对于一些回溯性的训练任务,它们在训练时,会以极高的并发读取几个月内数十甚至上百 TB 的数据,而 Alluxio 能够将这些数据缓存至集群,重复使用,避免跨专线向 HDFS 读取。

04 对象存储统一管理与加速

        首先,让我们解释为何有必要统一管理对象存储。

         一方面,在我们的内部运作中,云服务是以团队为单位进行申请和采购的。每个团队都拥有自己的云厂商子账号,其成员共享此子账号。对象存储是我们常用的云服务之一,同样也按照子账号进行分配。尽管我们可以申请不同的存储桶(bucket),但归属于同一子账号的存储桶共享相同的访问密钥(AK)和密钥(SK)。这种安排带来了安全性方面的问题:安全意识较低的成员可能会将 AK 和 SK 写入公共仓库的配置文件中,从而使得该子账号下所有存储桶的数据都面临泄露的风险。

        另一方面,由于知乎采用多云混合架构,而对象存储又是与云厂商绑定的,跨云使用对象存储时稍有不慎就可能导致产生昂贵的公网流量费用。

        上述两个问题长期以来一直困扰着我们,直到我们引入了 Alluxio 解决方案,这些问题终于得到了彻底的解决。

        我们引入 Alluxio 之前,对象存储的使用方式如下:

可以看到:

  • 所有用户用同一个 AK SK 来访问对象存储的不同 bucket;

  • 部分用户(user4)通过跨机房使用对象存储,可能产生公网流量。

在引入 Alluxio 之后,对象存储的使用方式如下:

  • 不同的对象存储被挂载到 Alluxio 上不同的一级目录,一级目录的名字与对象存储的 bucket 名字一一对应,便于用户通过 S3 Proxy 接入;

  • 利用 Alluxio S3 Proxy 用户认证插件,我们让每一个用户有自己独立的 AK 和 SK,互不干扰,就算 AK 和 SK 泄露,我们也能及时变更;

  • 我们将 AK 与不同的用户对应起来,这样可以利用 Alluxio 文件系统的目录权限功能,让每一个 AK 具有不同的权限,只能访问指定的目录,从而实现 bucket 之间的隔离;

  • 用户跨机房访问数据时,由于对象存储的数据已经通过 Alluxio 代理,公网流量将转换为机房专线流量。当然,这里我们更推荐的方式是在需要访问数据的机房,再扩建一套 Alluxio 集群,利用本机房的缓存,不仅能够节省公网/专线流量,还能够获得更好的性能。

        将对象存储用 Alluxio 代理后,用户几乎无需改造,只需通过 Alluxio S3 Proxy 就能以对象存储协议轻松接入 Alluxio,并且还能享受到 Alluxio 的高性能缓存与元数据缓存。通过 Alluxio S3 Proxy 访问对象存储,其单线程下载速度能提升近百倍;同时 Alluxio 的元数据缓存能够节省用户向对象存储请求的操作数,并且获得更好的 API 性能,降本增效。

05 总结与展望

        在本文中,我们详细介绍了如何在知乎的多云混合架构下,通过使用 Alluxio 来优化大语言模型的训练与数据管理、推荐/搜索模型的训练以及对象存储的统一管理与加速。通过利用 Alluxio 的缓存和统一命名空间等核心能力,我们构建了一个统一的数据接入层显著提升了数据处理的效率和管理的便利性

        在大语言模型的训练与数据管理方面,我们通过搭建独立的 HDFS 集群,并利用黑箱策略、灰箱机器以及网络策略来保障数据的安全性。通过 Alluxio 的高性能缓存和统一命名空间,我们实现了高效且安全的数据访问,同时解决了跨云、跨机房的数据读取问题。

        在推荐/搜索模型的训练中,我们利用 Alluxio 缓解了专线流量问题,显著降低了跨机房读取数据的成本。通过引入内存池和 HDFS 并发上传方案,我们进一步提升了数据写入速度。

        最后,在对象存储的统一管理与加速方面,我们通过挂载不同的对象存储到 Alluxio 上,并通过 Alluxio S3 Proxy 实现了用户认证和权限控制,从而解决了安全性和多云使用的问题,同时还获得了高性能的数据访问体验。

        Alluxio 在我们内部一经引入便赢得了用户的一致赞誉,进而推动了其迅猛的增长。截止到目前,我们内部已经部署了 5 个规模庞大的 Alluxio 集群,总计拥有超过 300 个节点,缓存容量甚至达到了 PB 级别。这些集群分布在不同的机房,为多个关键领域提供了支持,包括大型语言模型的训练、推荐和搜索模型的训练与上线、实时计算平台以及数据集成平台。

        总的来说,Alluxio 在知乎的多云架构中发挥了重要作用,为我们解决了数据安全、跨云、专线流量等一系列问题,为知乎的数据处理和模型训练提供了高效、安全、便利的解决方案。在未来,我们将继续深入挖掘 Alluxio 的潜力,探索更多的应用场景,为知乎的技术发展贡献更多的力量。

摘自:基于 Alluxio 构建统一数据接入层

猜你喜欢

转载自blog.csdn.net/iamonlyme/article/details/132844810