这是我参与「第四届青训营 」笔记创作活动的第7天,今天分享一下写简易分布式存储系统设计的一些心得,这是我们项目的GitHUb地址,欢迎大家批评指导: liuzongzhou/GoDFS (github.com)
1、详细设计
1.Mkdir:创建目录
首先会获取当前存活的datanode元数据组信息,如果没有存活的节点或者存活的节点连接失败会直接返回err,对获取到的所有有效dataNode实例,使用rpc调用创建相应的目录。
2.Put:上传文件
首先查看文件元信息,文件不存在或者路径有问题,直接返回false。rpc调用nameNode的Service.WriteData方法,获取写入请求的元数据数组,包含每个BlockId对应的主dataNode和多个备份remainingDataNodes。rpc调用dataNode的Service.PutData方法实现对主从dataNode的元数据写入。
特殊设计点:
- 实现多副本的一致性写,nameNode负责写入主副本,副本的数据信息从主副本异步拉取。
- 实现了负载均衡的存储策略,随机选择存储节点,尽量做到负载均衡。
3.Get:下载文件
首先通过文件的绝对路径去nameNode查询文件的元数据信息,通过远程调用nameNode的Service.ReadData方法得到NameNodeMetaData,其中包含了文件的blockId和blockAddress,通过blockAddress创建nameNodeInstance,调用nameNode的Service.GetData方法,传入文件的路径和blockId,如此往复,指导获取所有block块为止。
特殊设计点:
- 支持存储节点单节点故障时,不阻塞已有数据的读取。
在NameNodeMetaData中,我们会得到文件每个block所在的所有nameNode节点信息,当从主dataNode节点读取成功,直接进行下个block的读取,当从主dataNode节点读取失败,我们会读取其他dataNode节点的备份信息。
4.Delete:删除文件或者删除目录及所有子文件
DeletePath
首先取得当前存活的所有dataNodes节点信息,构造nameNode实例,向所有存活dataNode发起删除目录的rpc请求,当所有的dataNode上路径删除均成功时,才会删除nameNode上存储的元数据信息。
- 实现了防止dataNode出现脏数据的功能 即首先删除dataNode的数据信息,再删除nameNode的元数据信息,当删除在某个节点失败时,由于元数据信息不丢失,只要重新删除即可。
DeleteFile
首先取得需要删除文件的元数据信息,通过rpc调用nameNode实例的Service.ReadData方法得到文件的BlockIds和对应的BlockAddresses,通过BlockAddresses构造nameNode实例,向存活dataNode发起删除对应BlockId文件的rpc请求,当所有的dataNode上的Block块删除均成功时,才会删除nameNode上存储的元数据信息。
特殊设计点:
- 实现了防止dataNode出现脏数据的功能
即首先删除dataNode的数据信息,再删除nameNode的元数据信息,当删除在某个节点失败时,由于元数据信息不丢失,只要重新删除即可。
- 处理了当删除过程中nameNode节点死亡的特殊情况,当某个nameNode连接不上时,会删除其他nameNode的数据,并不会报错。
本次介绍就到这里,下次继续介绍stat、rename、list接口设计和开发。