1. HDFS起源:GFS
1.1 分布式文件系统起源
在1990年前,信息技术不够普及,对于文件的存储,往往都是一整个文件存储到单台机器。随着互联网技术的发展,互联网也可以将成千上万的计算机作为存储连接在一起。
同时,对于企业而言,其文件越来越大,越来越多,导致单台机器没有空间存储这种大文件;同时,这种大文件读取和写入变得非常耗时。
分布式文件系统的提出就是为了解决这类问题:
- 将大文件条带化地存储到多台服务器上。理论上来说,只要有足够的存储服务器,单个文件可以无限大。
- 由于大文件被切分成多个数据块,在写入时,以块为单位向不同服务器写入,可以并发地向不同服务器中写,提高写入速度;在读取文件时,可以并发地向多台服务器读取数据块,提高读取速度。
在2003年,谷歌发表经典文章《The Google File System》,用来解决上述问题。
- 备注:条带化技术就是将一块连续的数据分成很多小部分并把他们分别存储到不同磁盘上去。
1.2 GFS使用场景
谷歌在设计该文件系统时,考虑了如下场景:
- 对于存储数据的机器,往往时一些便宜的商用机,它随时可能会宕机,文件系统需要在宕机时保证数据的正确性。
- GFS作为分布式文件系统,只考虑大文件存储的场景,一般单个文件应该大于100MB。
- GFS只支持流式顺序读取文件,支持顺序写入append。不支持随机写,主要是因为随机读写会导致过多的元数据操作,同时也难以保证读取正在写入文件的正确性。
- GFS支持多个客户端并发append同一个文件的操作。
- GFS不专注机器延迟,更关注网络带宽。网络带宽更容易影响大文件传输效率,单机延迟可能是机器自身性能差,处理包的速度慢。
1.3 GFS基本工作流程
GFS文件系统架构如下。其读取数据流程如下:
- 客户端根据文件大小,计算出需要访问的数据块chunk的下标,向master发起请求。
- master中保存了每个文件的chunk列表,根据文件名和下标获取块所在的机器位置和块句柄chunk handle。
- 注意:master不会存储块具体所在的机器和文件句柄,这时因为GFS可能为了容量平衡发起迁移操作,导致块经常变动。每次块服务chunkserver通过心跳告诉master,这台机器上所有块的句柄信息。
- 客户端从master获取到块所在的机器及其句柄。向对应的chunkserver发送句柄以及查询的数据范围,chunkserver返回数据内容。
在GFS中,允许多个客户端同时append一个文件。这可能有一致性问题:当多个客户端同时append不同的副本,这些副本向其他副本同步数据时,其先后顺序已经改变,导致每个服务的数据都不一致。为了解决这个问题,GFS引入租约概念:master赋予一个副本primary权限,由他来规定客户端写入数据的先后顺序。
数据写入流程如下:
- 客户端访问master,获取文件的Primary副本。如果没有Primary副本,则挑选一个副本授权租约。
- 每个客户端先寻找一台最近的副本,通过流水线的方式写入数据到该机器的LRU缓存中。
- 一旦所有副本接收到数据,客户端就发送写请求到primary副本,有primary副本确定每个写请求的执行顺序。
- 主副本转发写请求给次副本,次副本按顺序将LRU缓存数据写入磁盘中。次副本写完回向主副本应道确认操作完成。
- 主副本告知客户端执行完成。如果出错则重试。
1.4 GFS总结
- 高可用:master提供主备机器,任何一台机器挂了或者磁盘坏了,服务不终止,文件不丢失。
- 可扩展:GFS扩容非常方便,直接启动chunkserver,通过心跳即可加入到集群中。
- 高性能:吞吐量高,每秒处理几十万请求。
- 一致性:通过租约保证多客户端并发写入一个文件时,每个副本文件内容一致。
- 低成本:负责存储的机器不需要很高的性能,保证网络带宽足够即可。
2. HDFS介绍
HDFS是基于GFS的原理进行开发,是GFS的简化版。HDFS基本流程都是与GFS一致,但是发现多客户端并发写入实现起来比较难,因此进行了简化。写入文件时,只允许一个客户端进行操作。
因此,HDFS实现的租约和GFS完全不同,HDFS中,租约由客户端占有,一旦用户执行写操作,就申请文件租约,其他文件查看租约用户不是自己,就提示租约获取失败,写入失败。
其项目结构如下所示:
- hadoop-hdfs模块:服务端代码。主要实现了NameNode和DataNode。
- hadoop-hdfs-client模块:包含了与HDFS交互的客户端代码,提供了一组API和工具,用于与HDFS进行数据交互、文件操作等。
- hadoop-hdfs-httpfs模块:提供HDFS的HTTP代理服务,使用HTTP接口访问HDFS数据。
- hadoop-hdfs-native-client:该模块提供了HDFS的本地客户端库,使用C和C++编写,可以在不依赖Java环境的情况下与HDFS进行交互。
- hadoop-hdfs-nfs模块:该模块实现了HDFS的NFS网关,将HDFS暴露为NFS协议,使得可以通过NFS接口访问HDFS中的数据。
- hadoop-hdfs-rbf模块:该模块实现了HDFS的路由器基础设施,提供了多个HDFS命名空间之间的透明数据访问和负载均衡的功能。
3. HDFS痛点
对于HDFS而言,存在过多的小文件会导致其服务性能降级,合并小文件则非常繁琐。而S3这种文件系统则适合存储小文件。
例如JuiceFS,它支持S3存储,还支持可横向扩展的 TiKV 作为元数据存储,在大数据量下的扩展性上相比 HDFS 有着更优雅的解决方案。