在存储系统中,为了获得巨大的性能加成,一个很自然的想法就是采用分片(sharding),将数据分割存储到多台服务器上,这样获得了更大的存储容量,而且可以并行地从多台服务器读取数据。
我们在成百上千台服务器上进行分片,大量基数的情况下,出现错误的频率也大大提升,我们需要一个自动化的从错误中恢复的方法,这就引入了容错(fault tolerance)。
实现容错的最有用的方法就是复制(replication),使用副本存储相同的数据。
有了副本,就需要考虑副本之间的不一致性(inconsistency)问题。
为了解决不一致性的问题,需要进行一定的设计,使各个副本之间保持一致,这需要网络通信来令服务器交互。因此,一致性的代价就是低性能。
这是一个循环,我们需要进行一定的权衡和牺牲。
GFS有一个master节点(逻辑上的一个),多个chunkserver,为client提供服务。文件被分割成固定大小的chunk,chunk创建的时候,master服务器会给每个chunk分配一个不变的、全球唯一标识的64位chunk标识,chunk服务器把chunk以linux文件的形式保存在本地的硬盘上,并且根据指定的chunk标识和字节范围来读写数据。出于可靠性考虑,每个chunk可能会被复制到多个chunkserver上。
master节点管理所有的文件系统元数据,但不存储文件数据(这使得GFS将文件系统管理和数据存储分开了),这些元数据包括名字空间、访问控制信息、文件和chunk的映射信息、当前chunk的位置信息。master节点还管理着系统范围内的活动,比如chunk租用、孤儿chunk的回收、以及chunk在chunkserver之间的迁移。master节点用心跳信息周期地和每个chunkserver通讯,发送指令到各个chunkserver并接收chunkserver的状态信息。
GFS客户端代码以库的形式被链接到client的客户程序里,使client可以通过这些函数进入GFS系统访问数据。
一次读取的流程是,首先client将文件名和客户程序指定的字节偏移,根据固定的chunk大小转换成文件的chunk索引,然后把文件名和chunk索引发送给master节点,master节点将相应的chunk表示和副本的位置信息发送回client,client用文件名和chunk索引作为key来缓存这些信息。之后客户端发送请求到其中一个最近的副本处(根据ip计算距离),请求信息包括了chunk的标识和字节范围。
tips:单一的master节点虽然大大简化了设计,但也可能导致master节点成为系统的性能瓶颈所在。因此我们必须尽量减少master节点的读写。
客户端将从master获取的元数据缓存一段时间,后续的操作将直接和chunkserver进行数据读写,除非元数据信息过期或者文件被client重新打开。
chunk的大小是关键的设计参数之一,通常选用64MB,这个尺寸远远大于一般文件系统的blocksize(惰性分配可以避免因为大的chunk尺寸造成的内部碎片)。这样做有许多优点:1. 减少了client和master的通信,因为只需要一次和master节点的通信就可以获取chunk的位置信息,之后就可以对同一个chunk进行多次的读写操作;2. 采用较大的chunk尺寸时,client能够对一个块进行多次操作,通过与chunkserver保持较长时间的tcp连接来降低网络负载;3. 较大的chunk尺寸减少了对master存储能力的要求,同时元数据也更有可能全部放在master的内存中,这样访问速度会快很多。
大的chunk尺寸也有一定的缺陷:这通常会产生热点问题。小的文件包含较少的chunk,如果多个client同时对小文件进行访问,存储这些chunk的chunkserver会成为热点。也许多个client同时访问一个小文件并不是GFS设计目标中的常见情景,但是当GFS初次启动的时候,一个可执行文件在GFS上存储为singe-chunk文件,之后这个可执行文件在数百台机器上同时启动,此时热点问题就出现了。为了解决热点问题,通常使用更大的复制参数来保存可执行文件(在更多的chunkserver上复制更多份)、或者错开系统启动的时间、再或者允许client从其他client读取数据(这里就引入了一个新的通信路径)。
master服务器主要存储三种类型的元数据:文件和chunk的命名空间、文件和chunk的对应关系、每个chunk副本的存放地点。命名空间和对应关系的更新采用保存变更日志的方式更新master服务器的状态,日记由操作系统记录在磁盘上,具有持久性。存放地点不会由master服务器持久化保存,master服务器在启动或者有新的chunkserver加入时,向chunkserver询问存储的chunk信息,同时定期轮询更新,以此获得chunk副本最新的存放地点。
tips:master始终通过chunkserver获取chunk的存放地点,这一设计源于一个思想:只有chunkserver才能最终确定一个chunk是否在它的硬盘上。例如,chunkservre的故障可能会导致chunk的消失,而这是master无法自动获知的。
这里的一致性是指chunk副本之间的一致性,要求所有chunk副本中保存的内容都是已定义的,并且包含最后以此修改操作写入的数据。为了达到这样的一致性,GFS有以下两项措施:对chunk的所有副本的修改操作顺序一致、使用chunk的版本号来检测副本是否因为它所在的chunk服务器宕机而错过了修改操作导致其失效。GFS通过master服务器和所有chunkserver的定期握手来找到失效的chunkserver,并且使用checksum来校验数据是否损坏。一旦发现问题,数据要尽快利用有效的副本进行恢复。
tips:设计系统时,一个重要原则时最小化所有操作和master节点之间的交互。
使用租约(lease)对chunk的多个副本进行主从管理,master节点为chunk的一个副本建立租约,把这个副本叫做主chunk,主chunk对chunk的所有更改操作进行序列化,所有的副本都遵从这个序列进行修改。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.cnblogs.com/MiaoMiaoGarden/p/15735146.html
内容来源于网络,如有侵权,请联系作者删除!