亚马逊AWS官方博客

兼容并蓄 – JuiceFS 与 Amazon MemoryDB 夯实企业数据基石

近年来,随着各行业的发展,数据作为生产要素发挥着越来越重要的作用。在各企业中存储及使用 TB 以及 PB 级别的数据,已经屡见不鲜,那么如何实现海量的数据存储且提供稳定的高性能,如何使资源可以快速伸缩、无限扩展、安全合规、隐私保护等,成为每个客户都需要认真考虑的问题,同时,客户也在寻求一种后端存储解决方案,既降低存储和运维成本,同时也需要简化存储管理。

本文简要介绍一种开放式的文件管理系统 JuiceFS,可以应对不同行业客户,比如汽车行业客户在自动驾驶场景中的文件管理的挑战,同时介绍和 JuiceFS 配合默契的亚马逊云科技的 Amazon MemoryDB,不仅可以像 Redis 一样在存储元数据时加快速度,同时因为它持久化的特性,也可以保证数据不丢,是一个在文件系统中存储元数据的理想选择。

新型业务场景对文件系统的挑战

1. 汽车行业自动驾驶

自动驾驶系统的数据闭环是一个持续不断的迭代优化过程,旨在通过数据收集、标注、模型训练、验证和部署,不断提升系统性能。每天,自动驾驶研发都将产生海量数据,这些原始数据经过提炼后,需要在模型训练、仿真、验证等环节中被高频读取使用。模型训练和仿真验证阶段中,数据集通常由数十亿至数百亿个小文件组成,每次迭代需要读取数千万至数亿个文件,这就要求存储系统不仅要具备管理百亿文件的能力,还必须在高并发请求下,保持低时延、高吞吐的元数据性能。

自动驾驶数据闭环核心环节包括下面几个部分:

  • 数据采集:首先,需要通过车辆上的传感器(如摄像头、雷达、激光雷达等)收集原始数据。这些数据通常是大规模的,并且包含多种格式。
  • 数据标注:为了训练机器学习模型,需要对数据进行标注,以提供训练所需的标签。
  • 模型训练:使用处理和标注后的数据训练机器学习模型。这通常在高性能计算环境中进行,需要大量的计算资源和高并发的文件读取。
  • 仿真:在虚拟环境中使用数据来测试和训练自动驾驶模型。仿真平台可以模拟各种驾驶场景,以验证模型的性能。需要大量的计算资源和高并发的文件读取。
  • 验证和测试:在封闭测试环境或通过影子模式在公开道路上测试模型,以确保其在真实世界条件下的有效性和安全性。

自动驾驶研发每天都将产生海量的数据,这些数据经过提炼后(数据标注),也并不是静态存储的「冷数据」,还需要在模型训练,模型仿真等环节被高频使用。因此,海量数据存储和使用对于自动驾驶行业来说面临多重技术挑战:

  • 数据量大,且规模化的存储管理需求越来越强 – 大规模文件的种类繁多,包括文字、图片、视频等多媒体形式,尤其在自动驾驶领域,会产生大量的传感器数据、视频数据等,这些数据分布在不同的地理位置、云端及边缘设备中,总的规模化的文件多达几十亿、甚至几百亿文件,文件系统需要具备海量数据的存储和管理能力,包括数据的压缩、去重、生命周期管理等。
  • 高并发访问和低延迟 – 自动驾驶系统中,多个应用程序和服务可能同时访问相同的数据,文件系统需要支持高并发访问,并提供低延迟的数据访问。
  • 高吞吐的数据 I/O 挑战 – 随着市面上 GPU 一片难求, 应用程序的计算和存储形成了严重的不平衡的局面,底层存储的 I/O 需要快速跟上计算能力。

2. 其他行业

在其他的行业,也存在各种不同的挑战,主要来自于大数据量、安全合规、系统集成、高并发、版本控制等,解决这些挑战需要采用先进的分布式文件系统技术,如对象存储、分布式块存储等,并结合云计算和边缘计算技术,实现数据的高效管理和访问,需要根据不同行业的特点来设计和优化文件系统。

关于 JuiceFS

JuiceFS 是一种云原生的高性能分布式文件系统,它采用海量低价的数据存储作为存储介质,打破对象存储的性能瓶颈,同时,可以像使用本地存储一样使用 JuiceFS,它可以提供超越本地磁盘的性能和近乎无限的存储空间。文件进入 JuiceFS 之后,会按一定规则被拆分成数据块,存储在对象存储中,文件的元数据则被存储在专门的数据库中,比如 Redis,MySQL 等,这样的架构非常便于客户进行海量文件的检索,写入,以及读取,并经常用于跨平台的公有云,私有云之间的数据共享及备份,另外,它采用了弹性伸缩的存储,按需使用,经常被用作跨平台的 NAS 使用,可以被分布在各地的成千上万的主机同时挂载读写, JuiceFS 提供了丰富的 API, 比如 JavaAPI,可以无缝对接大数据平台, 为其提供海量、弹性、低价的高性能存储。

优势:JuiceFS 作为分布式文件系统,在管理大数据量、高并发访问和低延迟、高吞吐的数据 I/O 方面有 3 方面的优势,可以满足各种大数据和高性能计算场景的需求:

  • 大数据量支持:JuiceFS 基于对象存储构建,可以充分利用对象存储的高吞吐特性,轻松支持 PB 级别的海量数据存储。
  • 高并发访问和低延迟:JuiceFS 采用元数据缓存,大幅降低数据访问延迟,并支持异步写入、数据压缩、分布式缓存以及数据预热等机制,进一步优化数据访问性能。
  • 高吞吐的数据 I/O: 分布式架构可以充分利用集群资源,实现负载均衡,提高整体的 I/O 吞吐量。

JuiceFS 技术架构

JuiceFS 文件系统技术架构如上,主要由三个部分组成:

JuiceFS 客户端(Client)

所有文件读写,以及碎片合并、回收站文件过期删除等后台任务,均在客户端中发生。客户端需要同时与对象存储和元数据引擎打交道。客户端支持多种接入方式:

  • 通过 FUSE,JuiceFS 文件系统能够以 POSIX 兼容的方式挂载到服务器,将海量云端存储直接当做本地存储来使用。
  • 通过 Hadoop Java SDK,JuiceFS 文件系统能够直接替代 HDFS,为 Hadoop 提供低成本的海量存储。
  • 通过 Kubernetes CSI 驱动,JuiceFS 文件系统能够直接为 Kubernetes 提供海量存储。
  • 通过 S3 网关,使用 S3 作为存储层的应用可直接接入,同时可使用 AWS CLI、s3cmd、MinIO client 等工具访问 JuiceFS 文件系统。
  • 通过 WebDAV 服务,以 HTTP 协议,以类似 RESTful API 的方式接入 JuiceFS 并直接操作其中的文件。

数据存储(Data Storage)

文件将会被切分上传至对象存储服务。JuiceFS 支持几乎所有的公有云对象存储,同时也支持 OpenStack Swift、Ceph、MinIO 等私有化的对象存储。

元数据引擎(Metadata Engine)

用于存储文件元数据(metadata),包含以下内容:

  • 常规文件系统的元数据:文件名、文件大小、权限信息、创建修改时间、目录结构、文件属性、符号链接、文件锁等。
  • 文件数据的索引:文件的数据分配和引用计数、客户端会话等。

JuiceFS 将元数据信息和真实数据块分离管理,通过 FUSE 实现 POSIX 接口,允许用户像使用本地文件系统一样操作。当用户将文件写入 JuiceFS 挂载的目录时,文件的实际数据块会存储到对象存储中,而相应的元数据信息,如文件名、文件大小、权限组、创建修改时间和目录结构等,则会存储到高性能的元数据引擎中。在这种架构下,诸如列出目录内容、删除文件等操作仅涉及对元数据引擎的读写,不受对象存储速度的限制,因此可以获得较好的性能保证。由于元数据引擎通常采用高效的存储和索引机制,即使在处理大量文件时,这些元数据操作也可以保持高效和低延迟。同时,真实数据块的读写则依赖于对象存储的性能,但由于数据分布式存储,可以实现高吞吐量和并行访问。

JuiceFS 元数据引擎

JuiceFS 目前已经支持 10 种以上元数据引擎,包括 Redis、MySQL、PostgreSQL、TiKV、etcd 等,据 JuiceFS 官方博客描述,大概一半的用户选择 Redis 来作为元数据引擎,主要是因为 Redis 具有高性能、可扩展性和易用性。作为内存数据存储,Redis 可以提供快速的数据访问和检索,这对于 JuiceFS 的高效运行至关重要。

通过利用 Redis 作为元数据存储后端,JuiceFS 可以利用其速度和灵活性,同时将数据管理的复杂性卸载到经过验证且广泛采用的解决方案上。这种方法使 JuiceFS 能够专注于其核心功能,如提供高性能分布式文件系统,同时依赖 Redis 高效地处理元数据的存储和检索。

随着数据量的不断增加,特别是在自动驾驶、大模型训练等数据密集型场景,以及对架构可靠性的更高要求,使用 Redis 作为 JuiceFS 的元数据存储可能会面临一些挑战和限制,原因在于 Redis 不能保证数据完全不丢。虽然主节点发生故障时,Redis 能够选择出合适的读节点来作为新的写节点,但并不能保证新的节点有全部的数据。所以,客户在选择 Redis 作为元数据引擎前,需要评估自己的应用能否接受少量的数据丢失。

Amazon MemoryDB 的推出,解决了 Redis 的持久性问题,做到“数据不丢”。因为与 Redis 的兼容,用户在为 JuiceFS 选择元信息引擎时,可以直接选择 Amazon MemoryDB 。由于持久性的保证,用户可以拓展使用 Redis 作为元信息引擎的边界,不再只是临时文件、中间结果的存储,也可以用作关键数据的存储。

Amazon MemoryDB

Amazon MemoryDB 是一款云原生的数据库服务,能够提供良好的持久型、强一致性和高可用性。在写节点发生故障时,它能选择读节点作为 failover 对象,新的写节点拥有全部的数据,实现“数据不丢”。它能提供 99.99% 的可用性,微秒级别读取延迟和个位数毫秒写入延迟。

Amazon MemoryDB 架构

Amazon MemoryDB 使用 Redis 作为内存级的计算和存储引擎,使用跨多个可用区的事务日志系统来持久化对 Redis 的操作日志。数据写入写节点时,写节点会把事务日志同步写入事务日志,等事务日志落盘后,写节点返回写入成功给应用程序。同时,读节点从事务日志系统异步复制更新。 沿用 Redis 的计算引擎,可以实现 Redis 的 API 的完全兼容。使用 Redis 的应用程序可以无缝迁移到 Amazon MemoryDB。基于多个可用区的事务日志系统是亚马逊内的一套成熟稳定的系统,能够提供低延迟、跨多个可用区的强一致性提交以及 11 个 9 的持久性保障。

Amazon MemoryDB 特性

作为一款数据库系统,Amazon MemoryDB 在持久性、可用性和扩展性上都有独特的实现。

持久性

Amazon MemoryDB 能够做到数据的持久性,保证“数据不丢”。它的持久化存储基于跨多可用区的事务日志来实现,能够应对可用区级别的故障。用户向写节点写入的每一条记录,更改内存实际数据的同时,也会将日志记录同步到事务日志系统中。Amazon MemoryDB 在同步日志的过程中复用了 Redis 的复制模型,采用了 write-behind logging 的机制,即:先更新内存中数据,再发送日志信息,这使它能够处理非确定性指令,比如 SPOP。为确保落盘完成后才返回成功给客户端,同时提高数据处理效率,Amazon MemoryDB 采用了异步落盘和 Tracker 的机制,将被更改的数据 key ID 存放在一个单独的结构 Tracker 中,当收到底层事务日志系统的 ACK 确认落盘响应后,才会对数据更改进行确认,返回给客户端。

可用性

Amazon MemoryDB 能够在集群节点发生故障时,实现快速监测,切换或者拉起新的节点。
Amazon MemoryDB 的架构支持写节点和读节点。如果写节点发生故障,Amazon MemoryDB 会通过读节点和跨多个可用区的事务日志系统之间的沟通交互,选举出合适的新写节点,继续对外提供服务。

  • Leader 选举过程的基础是节点和事务日志系统交互的 Append 接口,该接口要求请求指明前序日志的 ID。当事务日志系统发现发送的 Append 请求与自己已经持久化的 ID 不匹配时,会拒绝这条 Append 请求。
  • Leader 租约的实现。为避免集群中各个节点协调沟通谁是 Leader 的消耗,提高读写效率,Amazon MemoryDB 在分片级别采用了租约的机制。一个节点成为 Leader 后,其他节点会设定一个 backoff 阶段,即在约定的时间(大于租约期)内不进行竞选。写节点租约到期后,会优先续约。
  • 写节点发生故障无法续约时,读节点会读完最新的数据,以及 backoff 阶段终止,然后发起竞选,即发送一条 Append 指令给事务日志系统。因为这条指令需要指定日志系统中已经持久化的前序记录 ID,即便有多个读节点发起竞选请求,日志系统只会选择出一个节点作为新的写节点。

因为 Amazon MemoryDB 已经提供了持久化的功能,客户对每个分片只配置 1 个写节点,即便该节点故障,Amazon MemoryDB 也能够根据底层存储拉起一个新的写节点。为提高拉起新节点的速度,Amazon MemoryDB 采取了快照和事务日志结合的方式。Amazon MemoryDB 会定期快照并把快照存储到 S3。快照实际是对快照时刻之前所有的数据操作进行了整合,只保存此时刻的数据形态。进行数据恢复时,Amazon MemoryDB 只需选择离当前时间点最近的快照,根据快照恢复成新的节点,再把快照之后的事务日志依次应用到新节点上即可,避免了从事务日志的开始逐步应用日志的过程,降低了 RTO。

此外,Amazon MemoryDB 在监测故障时结合了外部监测和内部监测。外部监测持续对所有 Amazon MemoryDB 的节点进行心跳监测,内部监测通过集群内部的各个节点之间的 gossip协议发送心跳信息实现。Amazon MemoryDB 的管控节点会结合外部和内部的信息来进行判断,并及时恢复失效节点。

扩展性

Amazon MemoryDB 支持不同维度的扩展:纵向扩展,即更改实例类型;横向扩展,包括增减读副本和增减分片。

  • 增减读副本。减读副本就是终止 Redis 进程并释放 EC2 资源。增加读副本与根据快照和事务日志恢复数据过程相同,追踪到最新的事务日志后,新节点会加入到集群中,并通知给集群中其他节点。
  • 更改实例类型。Amazon MemoryDB 采用 N+1 Rolling Upgrade 的方式更改实例类型。优先处理读节点,最后处理写节点。每处理一个节点时,都采用先加新读节点再删除旧的读节点,最后删除写节点时会触发一次 failover。
  • 增减分片。增减分片包括创建或删除 EC2 节点、事务日志,以及迁移数据。Amazon MemoryDB 以 Slot 为单位进行数据迁移,包括传输数据和转移 Slot 所有权两部分。传输数据包括已经持久化的数据迁移和源写节点上的新数据 CDC 迁移。等数据几近追齐,会阻塞源写节点的写入请求,等待数据完全同步,然后转移 Slot 所有权。Slot 所有权转移以源 Owner 和新 Owner 两阶段提交的方式持久化存储在事务日志来实现,能够应对过程中可能发生的故障。所有权迁移后,新的 Owner 会开始接受写请求,原 Owner 会向仍然发送过来写请求的应用端回复 redirect 重定向信息,同时启动后台任务开始删除已经转移出的数据。

Amazon MemoryDB 性能

正常事务读写

Amazon MemoryDB 在只读负载能够达到亚毫秒的平均延迟,表现上优于 Redis。原因在于 Amazon MemoryDB 的多路复用 IO 实现,可以将多个客户端的请求连接合并到一起发送给 Redis 主线程,减少了 IO 线程和主线程之间的沟通成本,提高了效率,增加了吞吐量。Amazon MemoryDB 的只读负载能够达到亚毫秒的平均延迟。

Amazon MemoryDB 在只写负载能够达到个位数毫秒的响应延迟,比 Redis 不落盘配置的性能要差。原因在于 Amazon MemoryDB 会将每个写操作都落到跨多个可用区的事务日志中,延迟相对较高。对于较高并发、pipeline 操作或者是较大的工作负载,Amazon MemoryDB 的每个分片能支撑 100MB/s 的吞吐量。

打快照时读写

普通 Redis 为了应对 BGSave 对内存的额外消耗,占用 SWAP 空间,影响 Redis 的可用性,Redis 用户通常需要预留一部分内存供快照使用,通常情况下一个 Redis 节点只有一半左右的空间能够用来支持前端读写操作。或者用户需要对自己的应用负载特别了解,选择在零写入或者低写入的时候进行快照操作。

然而,Amazon MemoryDB 打快照是基于后台事务日志,启动单独的后台集群进行操作的,对前端实例没有任何影响,不同的实例类型对 Amazon MemoryDB 快照也没有影响。由于 Snapshot 过程采用的是离线集群(独立于用户的集群)进行快照,用户在使用 Amazon MemoryDB 时并不需要预留快照内存空间,也不需要考虑选择合适的时间节点进行快照操作。Amazon MemoryDB 能够供用户使用的有效内存比例更高。

总结

JuiceFS 与 Amazon MemoryDB 的结合在自动驾驶、HPC 高性能计算等场景下,是一种性能卓越的数据存储和访问方案,JuiceFS 作为分布式共享文件系统,可与 Amazon MemoryDB 无缝结合,使用 Amazon MemoryDB 作为元数据缓存,可以加速数据的读取,从而提供毫秒级的访问延迟,同时,Amazon MemoryDB 的高可用性和数据持久化特性,确保元数据的可靠存储,通过这种组合,可提供可靠、高效的数据存储服务,满足高并发、低延迟的需求,从而为大数据、AI 等场景带来巨大的性能提升和成本优势。

本篇作者

梁战雷

亚马逊云科技解决方案架构师,具有超过 13 年的运维工作经验,在微服务,容器,devops 等云原生领域有丰富的项目落地实施经验,现在主要负责汽车行业客户的上云推广、出海规划及支持工作。

马丽丽

亚马逊云科技数据库解决方案架构师,十余年数据库行业经验,先后涉猎 NoSQL 数据库 Hadoop/Hive、企业级数据库 DB2、分布式数仓 Greenplum/Apache HAWQ 以及亚马逊云原生数据库的开发和研究。

郭耀华

亚马逊云科技数据库高级产品经理,拥有 20 年 IT 咨询和实施以及大客户 Engage 经验,现负责亚马逊云科技的数据库产品 Go To Market 工作。曾就职于 HP、IBM。