system desing 系统设计(三): 分布式文件系统distributed file system设计原理
1、众所周知,数据要想永久保存,肯定是要放磁盘的啦!磁盘和内存不一样,内存最小的存储单位是byte,1 byte = 8bit;但是磁盘不一样了,最小存储单位是 sector, 1 sector = 512byte!而在磁盘上,数据都是以文件file的形式存储的。假如文件大小是1kb,那就需要在磁盘上找2个sector来存放!那么问题来了,现在磁盘的容量都是TB级别的,每个sector的大小是512byte,那么磁盘上有billion级别的sector,读取的时候怎么知道这2个sector的位置了?所以肯定是要在磁盘上找个地方存文件sector位置的。除此以外,文件自生还有很多属性要存储,比如文件名、大小、创建时间、创建用户等(大家打开文件夹,看到文件list时就能看到这些文件属性了),如下图:
这些属性统称为metadata(当然也包括了文件数据本身存放在sector的位置);因为对mestadata的访问频率远高于文件内容本身,所以metadata一般会和文件内容数据分开存放,比如刚开机时,就会把所有文件的metada读到内存,后续直接从内存读metadata,然后从里面找到这2个sector在磁盘为位置,进而从磁盘把文件内容读出来!整个流程就是这样的,但问题很明显:sector只有512byte,导致磁盘sector的数量是billion级别的,光是存储sector的位置就要耗费GB级别的空间,该怎么优化了?
既然sector的颗粒度太小,导致管理成本高,那就提升磁盘存储的颗粒度呗!这里一次性把8个sector看成整体,8*512byte = 4096byte =4kb,这里定义为block!所以现在metadata的结构展示如下:
block的大小和memory page的大小一样了,但如果按照block划分空间,产生的数据块还是很多,需要存储block offset的耗费还是很大。比如存储高清、蓝光电影,需要耗费上百GB的磁盘,如果按照4kb的block来计算,需要26 milliom个的block来存储,要记录这么多block offset,这个文件的mestadata该多大啊!为了减少metadata的大小,只能进一步提升颗粒度了,这里继续把最小存储单元的大小设置为64MB,称之为chunk!此时如果再存储100GB的文件,只需要 1600个chunk了,极大减轻了metadata的存储压力!图示如下:
此时的文件存储,还仅限于单机!如果现在要存10PB数据,单机肯定是存不下的,怎么在集群上存储这些数据了?
2、单机存不下,肯定就要考虑cluster集群的啦!一个集群,少则几个node,多则几千甚至数万nodes,这么多nodes,该怎么去管理和运维了?
(1)集群的管理和组织方式有两种:P2P和master-slave模式!
- P2P模式的经典代表就是block chain、bt下载等!在这种网络下,每个节点都是对等equality的!整个chain上随时都可以加入新节点,也随时都可以下线节点!在block chain这种去中心化decentralization设计理念和模式下,这种对等的节点是完全可行的,但现在需要设计的是file system,如果每个节点都是对等的,用户怎么去管理几千上万个节点的集群了?
- 为了方便管理和运维,最终还是需要centralized网络模式,所以master-slave这种模式至今仍然大行其道!想想也是:大到国家的运营,小到公司的运作,哪一个不是中心化、分层级的了?管理上都是层层下推的!
确定了master-slave模式,接着该讨论master和slave的功能定位了!从名字就能看出来,master是管理节点,slave是具体干活的,所以很自然而然的就能想到: master负责管理和分配slave,slave负责具体的存储数据!图示如下:
master存放了大文件的metadata,最重要的就是index了:记录了文件chunk在哪个slave的哪个offset!为了更加灵活,slave可以自行决定文件存放在哪个chunk!
经过上述铺垫,distributed file system写入流程就容易理解了,如下:
- client找到master,指定文件的写入路径;同时master存储文件的chunk list,便于后续读取
- master找到合适的slave,返回给client;这里合适的标准是什么了?(1)硬件负载低的 (2)反应速度快的(网速快)(3)当然也可以通过consistency hash算法找slave
- client把数据写入master指定的slave
读的过程类似:
- client从master那里得到文件的chunk list
- client找到slave读取数据
(2)上面解决了数据分布式存储问题,可万一slave宕机了怎么办?slave的磁盘坏了怎么办?一个大型集群有数千甚至上万节点,有少量节点宕机正常,怎么才能确保数据不丢失了?
- Erasure Coding 纠删码:额外需要50%左右的校验数据。一旦原来的数据丢失,会根据校验数据恢复。但由于恢复时会做大量的计算,所以恢复的效率并不高!
- replica 副本:这是目前最常见的数据备份方式,大名鼎鼎的HDFS采用的就是3副本,也就是同样的数据在3个不同的node分别存放。一旦其中一个副本损坏,立即通过另外2副本恢复数据!
replica 副本的存储过程如下:
- client找master分配slave。由于是3副本,肯定要写到3台不同的节点;
- 为了避免client多头对接,client只把数据传给其中一个slave,再由该slave把数据传到另外两个slave(内网速度快的嘛);首个存储数据的slave叫队长,选取的标准:负载低的、响应速度快的
存好后读的时候就简单了:3个slave随便找个就行啦!不过有一点要注意:数据存放后会随同一起存放checksum(可以是简单粗暴地把数据相加,也可以是取MD5等)!读取数据时也会检查checksum,如果不一致,说明数据损坏了,需要修复,最直接的办法就是找master帮忙,提供另外两副本的slave,然后从这两个slave取数据修复,流程如下:
读数据时,如果连slave整机都宕机了,直接选取另外两个读取,流程如下:
大型集群,master为了随时随地都能了解到slave的情况,以便后续的任务分配,需要slave每隔固定的时间给master发送消息,以告诉master自己仍然live,这种机制叫heartbeat!
3、以HDFS为例,详细的读写流程如下:
- 写数据的(upload file)流程:
- 读数据(download file)流程:
总结:
1、分布式文件系统,核心就是把文件拆分成chunk大小,合理地存放在不同的节点!
2、集群中master负责分配slave节点、记录文件在slave的chunk;slave负责存放数据
3、数据损坏后,slave会找master提供另外2副本的位置,然后通过这2副本恢复
参考:
1、https://www.bilibili.com/video/BV1Za411Y7rz?p=55&vd_source=241a5bcb1c13e6828e519dd1f78f35b2 GFS设计
2、https://www.bilibili.com/video/BV19V411k7VB?p=4&spm_id_from=pageDriver&vd_source=241a5bcb1c13e6828e519dd1f78f35b2 hdfs架构和原理