分布式文件系统(Distributed File System,DFS),通过网络连接大量主机,将不同的磁盘、不同逻辑分区的数据组织在一起,提供海里的数据存储, 一般是PB级别(1PB=1024TB,1TB=1024GB),这是单机存储所无法比拟的。
Google File System 是谷歌三大论文之一,而HDFS(Hadoop Distributed File System)是它的一种重要实现。另外一篇论文BigTable 则为这个文件系统提供了搜索支撑。谷歌确实是很牛的一家公司。
Google作为一个搜索引擎服务商,它要存储海量的网站数据,还有这些网页的历史版本。那么用什么样子存储合适呢?我们知道数据库,有行式存储和列式存储之分,那么可不可以用来存储网页呢?它的表结构有应该是怎样的呢?其实很困难,因为网页的结构不固定,每个网址又有不同的元素,根本统一不了。所以只能考虑KV结构,就是MAP结构。key,可设计为<URL,Column,时间戳>, 列又可以细分为家族family,和自身标识Qualifier。
那么这个查询map用什么数据结构呢?可能我们第一个想到的就是hashmap, 但是你想url其实有很多前缀是重复的,那同一个网站,域名都是重复的。如果用hashmap,单条查询快,但范围查找就很弱。那么这里最常用的还是B+Tree,毕竟相同域名的网页资源同时被用到的概率更高。使用B+Tree,按照URL使用字典序进行排序,是一种不错的选择。把URL相近的数据存储到一个大数据块块中。这种大块,被称为分片(Tablet)。它作为数据分布的最小单位。分片内部使用像传统数据库一样的的行存储,也可以使用一个 B+ 树组织的列存储。
好了,啰嗦了那个一大堆,其实就是为了引出分片这个概念。分片在存储形式上,可以作为一个文件存放在文件系统中。为了存储安全,可以设定一定的冗余备份,一般是大于三份,如果有一份是不一致的,可以对照其他两份纠正。从访问效率上来讲,它们肯定是挨的越近越好。
分片还是比较大,所以又划分出来Chunk,在GFS中chunk是基本分配单元,它是比磁盘块设备的block要大的多的单元。关系结构如下图所示。
Block一般是8扇区,也就是4KB大小。GFS中chunk是64KB,HDFS则是128MB。越大,磁盘一次性读取的数据越多。显然后者更适合海量数据的处理。
怎么访问文件?
HDFS和GFS会把文件的chunk信息,存放在一个叫Master的节点上。
比如某个客户端,想要读取/net/data下1024号chunk的内容。那么先向master发请求,然后master响应把chunk信息(chunkserver地址和chunk的句柄id)返回回来。然后客户端像chunkserver发请求,从chunk的句柄中取多少信息。最后chunkserver把数据返回给客户端。
Master负责存储文件信息、Chunk 信息,权限信息等。相当于一个索引。
ChunkServer 负责存储 Chunk 数据。
怎么管理分布式文件?
所有的目录结构信息,包括chunk信息,都存在master节点上。
客户端想要读取一个文件的时候,会分为四步
1. 客户端向master发请求,把文件名和chunk序号发送给master
2. master节点返回chunk句柄和chunk位置信息
3. 客户端向chunkserver发送chunk句柄和内容位置信息
4. chunkserver返回数据给客户端
客户端,数据使用方,比如GFS中的Client
Master节点,存储所有的文件信息、Chunk 信息,权限信息等,它可以利用B树创建这些索引信息
ChunkServer 节点,存储数据,一般有很多台
怎样解决读写冲突?
chunk存在多个地方,这个就涉及到一个读写冲突的问题。要等所有chunkserver都更新了这个chunk数据,才算最终更新成功。数据推送到chunkserver需要时间,这一部分导致了数据不一致的时间窗口变大了。在GFS中,客户端发送给chunkserver的数据,会先缓存起来,等到所有数据都分发完毕,才一起更新。这减少了时间窗口。具体步骤如下
1. 客户端和Master针对某个chunk、签订一个租期,在这个租期内,其他客户端不能修改这个chunk
2. Master告知客户端chunk的节点位置,包括一个主节点和辅助节点。主节点会协助同步所有节点的数据。
3. 客户端将数据发送给所有节点,也就是chunkserver,chunkserver收到数据后进行缓存。
4. chunkserver缓存之后,会告诉客户端,它收到数据了,客户端向主请求写。
5. 主chunkserver发命令告知所有chunkserver进行数据落地。
6. chunkserver数据落地之后,告知主chunkserver,他们写完了。
7. 主chunkserver告诉客户端,写操作完成。
由此,GFS实现了一致性。如果实现强一致性,那么需要所有节点一起工作,这段时间对于其他任务反映就不能快了。GFS允许数据在一定时间范围内是不一致的,读到的数据,可能并非最新的,从而提高吞吐量。牺牲小范围的可接受的不一致性,来换取性能。
容灾问题
Master节点也成NameNode。其中有个辅助节点,会把NameNode的变更记录日志,放到DataNode中。每过一段时间,这些日志形成一个还原点,当NameNode发生故障,可以由此进行还原。
参考:
[0] 分布式文件系统
[2] 搜索引擎基本工作原理