HDFS 作为 Hadoop 提供存储组件,已经成为大数据生态里面数据存储最常用的选择,通常在机房环境部署。
JuiceFS 是一个基于对象存储的分布式文件系统,用户可以在云上快速地搭建按需扩容的弹性文件系统。
如果企业正在考虑在云上构建大数据平台,了解这两种产品的差异和优缺点,可以为企业迁移或切换存储产品提供参考。这篇文章将从技术架构、功能特性、使用场景等多个方面来解析 HDFS 和 JuiceFS 的异同。
1. 架构
1.1 HDFS 架构
HDFS(Hadoop Distributed File System)是 Hadoop 生态系统中的分布式文件系统。在 HDFS 的架构中,有两种类型的节点:NameNode 和 DataNode。一个最简单的 HDFS 集群就是由一个 NameNode 和一组 DataNode 组成。
NameNode 是 HDFS 的元数据管理节点,负责管理文件系统的命名空间和响应客户端对文件元数据的请求(比如 create,open,rename,delete 等请求),同时, NameNode 也负责管理 DataNode 和数据块的映射关系,维护所有文件和目录的层次结构,记录文件的名称、文件大小、文件块的位置等信息。在生产环境使用时,HDFS 需要部署多个 NameNode 并结合 ZooKeeper 和 JournalNode 来实现高可用。
DataNode 是 HDFS 的数据存储节点,负责存储实际的数据。一个文件会被分割成一个或多个文件块,每个 DataNode 节点存储一部分数据块,并向 NameNode 汇报存储的块的列表和状态信息。DataNode 节点处理客户端的读写请求,向客户端提供文件块的数据。
1.2 JuiceFS 架构
与 HDFS 不同,JuiceFS 社区版采用的是插件化架构,JuiceFS 的文件数据是被切分后并保存在对象存储(如 Amazon S3、MinIO)中,元数据则存储在用户选择的数据库中,例如 Redis、TiKV、MySQL等。这种架构的设计使得 JuiceFS 可以通过共享同一个数据库和对象存储实现强一致性保证的分布式文件系统。
JuiceFS 的元数据管理是完全独立于数据存储的,这意味着 JuiceFS 可以支持大规模数据存储和快速文件系统操作,同时保持高可用性和数据的一致性。JuiceFS 提供了兼容于 Hadoop 生态的 Java SDK,支持 HDFS 到 JuiceFS 的无缝切换,与此同时,JuiceFS 还提供了包括 POSIX、S3 Gateway、Kubernetes CSI Driver 等多种 API 和工具,使其易于集成到现有的应用程序中。
JuiceFS 企业版有着与社区版一致的技术架构,不同之处在于 JuiceFS 企业版面向对性能、可靠性和可用性要求更高的企业级用户提供了一套自研的分布式元数据存储引擎。同时在社区版的基础上提供了一系列高级功能,包括 Web 控制台、快照、跨区数据复制、文件系统镜像等。
2. 基础能力
这部分内容将对 HDFS 与 JuiceFS 的架构核心进行拆解,进一步对比它们在元数据管理、数据管理以及访问协议支持方面的特点和差异。
2.1 元数据
2.1.1 元数据存储
HDFS 将元数据存储在内存中,使用 FsImage 和 EditLog 两种技术来保证元数据不丢失和重启后快速恢复。
JuiceFS 社区版采用独立的第三方数据库来存储元数据,比如Redis、MySQL、TiKV等。截止本文发布,JuiceFS 社区版支持三类共 10 种事务型数据库。
JuiceFS 企业版采用自研的高性能元数据存储引擎,JuiceFS 企业版将元数据存储在内存中,通过 changelog 和 checkpoint (类似于 HDFS 的 EditLog 和 FsImage) 保证数据不丢失和重启快速恢复。
2.1.2 元数据内存消耗
HDFS 每个文件的元数据约占用 300 字节内存空间。
JuiceFS 社区版使用 Redis 作为元数据引擎时,每个文件的元数据约占用 300字节 内存空间;
JuiceFS 企业版热数据每个文件的元数据约占用 300字节 内存空间。JuiceFS 企业版支持内存压缩,针对不常使用的冷数据,内存占用可以降低到每个文件 80字节左右。
2.1.3 元数据扩容
元数据存储是一个关键的组件,因为它包含了文件系统中所有文件和目录的信息。如果元数据存储的容量不足,那么就会对文件系统的性能和可靠性造成影响。
HDFS 可以采用联邦的方式来解决单个NameNode的容量限制问题。联邦中的每个 NameNode 是独立的命名空间,它们可以共享同一个DataNode 集群来简化管理。应用需要访问指定的NameNode或者通过静态配置的 ViewFS 来构成统一命名空间,但垮NameNode 的操作都是不支持的。
JuiceFS 社区版使用第三方数据库作为元数据存储,这些数据库系统通常都有较为成熟的扩容方案,一般来说只需简单的增加数据库的容量或者添加数据库的集群节点即可实现存储扩容。
JuiceFS 企业版也支持元数据集群的水平扩容,多个元数据服务节点共同组成单一命名空间,以支撑更大规模的数据和处理更多的访问请求,进行横向扩展时无需客户端做任何修改。
2.1.4 元数据操作
HDFS 对文件路径的解析是基于完整路径的。HDFS 客户端会将需要访问的完整路径直接发送到 NameNode,因此,任何深度文件的请求都只需要进行一 RPC 次调用。
JuiceFS 社区版基于 inode 进行文件路径访问,根据文件层级从根目录开始逐层查找,直到找到最终文件。因此,根据文件深度可能存在多次 RPC 调用。为了加速此过程,一些支持快速路径解析的元数据引擎,如 Redis,服务端能够直接解析最终文件。如果使用的数据库不支持快速路径解析,可以通过启用元数据缓存来加速此过程。同时,启用元数据缓存后,可以减轻元数据服务的压力。但是,启用元数据缓存后会导致一致性语义有所改变,需要根据具体场景调节参数。
JuiceFS 企业版支持服务端路径解析,请求任何深度的文件都只需一次 RPC 调用即可。
2.1.5 元数据缓存
元数据缓存可以显著提高文件系统的性能和吞吐量,通过将最常用的文件元数据存储在缓存中,元数据缓存可以避免频繁地从元数据服务器获取元数据,从而减少 RPC 调用,提高性能。
HDFS 不支持客户端元数据缓存。
JuiceFS 社区版和企业版均支持在客户端缓存元数据,以加速 open、list、getattr 等元数据操作,降低元数据服务的负载。
2.2 数据管理
2.2.1 数据存储
HDFS 默认以 128M 的块来存储文件,会在三个不同的 DataNode 上存储每个数据块的三个副本进行容错,以此来保证存储的可靠性,可以通过修改配置来调整副本数量。此外,HDFS 还支持纠删码( Erasure Coding),一种高效的数据编码技术,通过将数据块切分成多个数据块并编码存储来提供容错机制。与副本相比,纠删码可以节省存储空间,但会增加计算负载。
JuiceFS 则将数据拆分成 4M 的块存储在对象存储中,同时为大数据场景引入了 128 M 的逻辑分块用来做计算任务划分。由于 JuiceFS 采用对象存储作为数据存储层,数据的可靠性取决于选用的对象存储,一般的对象存储服务会通过多副本复制、纠删码等技术为存储的可靠性提供保证。
2.2.2 数据缓存
HDFS 可以将指定数据缓存在服务端 DataNode 的堆外内存中,从而来提高数据访问的速度和效率。比如 Hive 场景下,可以将小表缓存在 DataNode 内存中,提高 join 速度。
JuiceFS 的数据持久化层一般在对象存储上,而对象存储通常都有较高的基础时延。为了解决这个问题,JuiceFS 提供了客户端数据缓存功能,通过将对象存储上的数据块缓存在本地磁盘上,从而提高数据访问的速度和效率。
JuiceFS 企业版除了基本的客户端缓存能力外,还提供了缓存共享功能,多个客户端可以组成缓存集群,共享本地缓存。此外,JuiceFS 企业版还可以搭建独立的缓存集群,为弹性伸缩的计算节点提供稳定的缓存能力。
2.2.3 数据亲和性
HDFS 为每个数据块提供存储位置信息,可以被 YARN 等资源调度器用于实现亲和性调度。
JuiceFS 支持使用本地磁盘缓存来加速数据访问。它通过预先设置的计算节点列表为每个数据块计算生成偏好的位置信息,让 YARN 等资源调度器将同一个数据分配的计算调度到固定节点, 以提高缓存数据的命中率。
JuiceFS 企业版还支持在多个计算节点之间共享数据缓存,即使计算任务没有调度到偏好的节点,也可以通过计算节点间的网络访问其他节点上缓存的数据。
3. 功能与特性
3.1 数据一致性
HDFS 和 JuiceFS 的元数据都是保证强一致性的(CP系统),可以为文件系统数据提供强一致性保证。
JuiceFS 支持元数据的客户端缓存,当启用客户端缓存时,可能会影响数据一致性,需要应用的一致性要求合理设置。
对于读写混合场景,HDFS 和 JuiceFS 均提供 open-after-close 语义,即保证新打开的文件,能够读到之前已经 close 的文件所写入的数据。而当一个文件持续打开时,它可能读不到其他客户端写入的数据。
3.2 数据可靠性
一般应用往 HDFS 写数据时,都是依赖成功的关闭文件来确保数据被持久化,JuiceFS 也是一样的。
为了给 HBase 提供低时延的数据写入方式(通常在 HBase 的 WAL 文件使用),HDFS 提供 hflush 方法来牺牲数据持久化(只写入到多个DataNode 的内存中)以获得低时延。
JuiceFS 的 hflush 会将数据持久化到客户端的缓存盘上(writeback 模式),依赖于缓存盘的性能和可靠性。另外,当往对象存储上传的速度更不上时,或者客户端退出,可能导致其他节点读不到刚写入的数据,会影响 HBase 的故障恢复能力。
为了更高的数据可靠性,HBase 可以通过 HDFS 的 hsync 接口来保证数据持久化。JuiceFS 也支持 hsync, 此时 JuiceFS 会将数据持久化到对象存储中。
3.3 并发读写
HDFS 和 JuiceFS 都支持多机并发读同一个文件,可以获得比较高的读性能。
在并发写方面,HDFS 不支持多个客户端同时对同一个文件进行写操作。而 JuiceFS 支持并发写,但需要应用自己管理文件的偏移量(offset),如果多个客户端同时向相同的偏移量写入数据,可能会导致数据的相互覆盖。
HDFS 和 JuiceFS 一样,如果多个客户端同时打开一个文件,其中一个客户端对文件进行了修改,其他客户端可能不能读到最新的修改。
3.4 安全性
Kerberos 用于身份认证。HDFS 和 JuiceFS 企业版均支持。JuiceFS 社区版本仅支持使用认证后的用户名,无法判断用户真伪。
Apache Ranger 用于授权。HDFS 和 JuiceFS 企业版均支持。JuiceFS 社区版不支持。
HDFS 和 JuiceFS 企业版均支持给目录和文件设置额外的访问规则(ACL),JuiceFS 社区版不支持。
3.5 数据加密
HDFS实现了透明的端到端加密。一旦配置完成,用户从特殊的 HDFS 目录中读写数据时,数据会被自动加密和解密,无需对应用程序代码进行修改,操作过程对用户透明。详见:Apache Hadoop 3.3.4 – Transparent Encryption in HDFS
JuiceFS 也支持透明的端到端加密,包括传输加密(encryption in transit)及静态加密(encryption at rest)。在用户开启了静态加密时,需要用户一个自行管理的密钥,所有写入的数据都会基于此密钥进行数据加密,详情见 《数据加密》。这些加密都应用都是透明的,无需修改应用代码。
3.6 快照
HDFS 的快照是指对某个目录的只读镜像,能够让用户持续方便一个目录在某个时间点上的状态。快照中的数据是只读的,任何原目录的修改都不会影响到快照。在 HDFS 中,快照是通过记录文件系统目录树上的元数据信息来实现的,具有以下特点:
- 快照的创建是即时的:成本是O(1),不包括节点查询时间。
- 只有在相对于快照进行修改时才会使用额外的内存:内存使用量为O(M),其中M是修改的文件/目录的数量。
- 数据节点中的块不被复制:快照文件记录了块列表和文件大小。没有数据复制。
- 快照不会对常规的HDFS操作产生不利影响:修改是按时间顺序倒过来记录的,因此可以直接访问当前数据。快照数据是通过从当前数据中减去修改内容来计算的。
另外利用快照差异(snapshot diff),可以快速的拷贝增量数据。
JuiceFS 企业版快照功能采用了类似克隆的方式实现,快速复制元数据而不复制底层数据,创建快照是 O(N), 内存使用量也是 O(N)。与 HDFS 的快照不同,JuiceFS 的快照可以被修改的。
3.7 存储配额
HDFS 和 JuiceFS 均支持文件数和存储空间配额。JuiceFS 社区版需要升级到即将发布的 1.1 版本。
3.8 符号链接
HDFS 不支持符号连接。
JuiceFS 社区版支持符号链接,Java SDK 可以访问通过 POSIX 接口创建的符号链接(相对路径)。
JuiceFS 企业版除了支持相对路径的符号链接外,还支持链接到外部存储系统(HDFS 兼容),实现类似于 Hadoop 的 ViewFS 的效果。
3.9 目录使用量统计
HDFS 提供 du 命令可以获得某个目录的实时使用量统计,JuiceFS 也支持 du 命令,企业版可以提供跟 HDFS 类似的实时结果, 社区版则需要在客户端遍历子目录来统计。
3.10 弹性伸缩
HDFS 在存储空间的弹性伸缩方面支持动态节点调整,但这可能涉及数据迁移和负载均衡问题。相比之下,JuiceFS 通常使用云上对象存储,其天然的弹性使得存储空间可以按需使用。
3.11 运维管理
在运维管理方面,HDFS 各个大版本存在不兼容性,同时需要匹配其他生态组件版本,升级过程较为复杂。相比之下,JuiceFS 社区版和企业版均支持 hadoop2 和 hadoop3,升级简便,只需要替换 jar 文件即可。此外,JuiceFS 提供工具来导出和导入元数据,方便在不同集群之间进行数据迁移。
4. 适用场景
在比较选择 HDFS 和 JuiceFS 时,需要考虑不同的使用场景和需求。
HDFS 更适合规模比较固定的机房环境,使用裸盘作为存储介质,无需考虑弹性和存算分离需求的使用场景。而在公有云环境下,公有云可提供的裸盘节点类型比较少,对象存储成为了更好的存储选择,通过 JuiceFS 可以实现存算分离以获得更好的弹性,同时支持 Hadoop 大数据生态的绝大部分应用,会是更高效的选择。
此外,当大数据场景还需要跟其他应用(比如AI) 共享数据时,由于 JuiceFS 提供了更丰富的接口协议,可以很方便地在各个应用之间共享数据,省去了数据拷贝的麻烦,也会是更方便的选择。
5. 总结:
特性
特性 | HDFS | JuiceFS 社区版 | JuiceFS 企业版 |
发布时间 | 2005 | 2021 | 2017 |
编程语言 | Java | Go | Go |
开源 | Apache V2 | Apache V2 | 闭源 |
高可用 | 支持(依赖ZK) | 依赖元数据引擎 | 支持 |
元数据扩展 | 独立命名空间 | 依赖元数据引擎 | 横向扩展,单一命名空间 |
元数据存储 | 内存 | 数据库 | 内存 |
元数据缓存 | 不支持 | 支持 | 支持 |
数据存储 | 磁盘 | 对象存储 | 对象存储 |
数据缓存 | Datanode 内存缓存 | 客户端缓存 | 客户端缓存/分布式缓存 |
数据亲和性 | 支持 | 支持 | 支持 |
一致性 | 强一致 | 强一致 | 强一致 |
重命名原子性 | 是 | 是 | 是 |
追加写 | 支持 | 支持 | 支持 |
文件截断(truncate) | 支持 | 支持 | 支持 |
并发写 | 不支持 | 支持 | 支持 |
hflush(HBase WAL 使用) | 多个DataNode内存 | 写缓存盘 | 写缓存盘 |
ApacheRanger | 支持 | 不支持 | 支持 |
Kerberos认证 | 支持 | 不支持 | 支持 |
数据加密 | 支持 | 支持 | 支持 |
快照 | 支持 | 不支持 | 支持(克隆) |
存储配额 | 支持 | 支持 | 支持 |
符号链接 | 不支持 | 支持 | 支持 |
目录统计 | 支持 | 不支持(需要遍历) | 支持 |
弹性伸缩 | 手动 | 自动 | 自动 |
运维管理 | 较为复杂 | 简单 | 简单 |
访问协议
协议 | HDFS | JuiceFS |
✅ | ✅ | |
libhdfs (C API) | ✅ | ✅ |
WebHDFS (REST API) | ✅ | ❌ |
POSIX (FUSE or NFS) | ❌ | ✅ |
Kubernetes CSI | ❌ | ✅ |
S3 | ❌ | ✅ |
虽然 HDFS 也提供了 NFS Gateway 和 基于 FUSE 的客户端,但因为跟 POSIX 的兼容性比较差,性能也不够好而很少被使用。