开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
设计 NameNode 的元数据管理机制
什么是元数据?
我们都知道在分布式存储系统中的 NameNode 是不会实际存储文件的,NameNode的作用是存储文件系统中的元数据信息,包括文件的名称、位置、权限以及访问者所需的其他信息。
元数据可以大致理解为一种逻辑结构,记录着文件的层级关系、位置信息等!
实际的文件数据存储在 DataNode 上,而 NameNode 负责管理 DataNode 上文件的位置和配置。
NameNode确实不会直接存储文件数据,但是它需要跟踪每个文件的元数据;因此它内部还需要维护一棵目录树,来记录每个文件的位置、大小、权限、版本等信息。这样,当NameNode守护进程接收到文件读写请求时,它便可以根据目录树中的信息来指引DataNode守护进程去相应的DataNode节点读取/写入文件了。
NameNode 中的是逻辑目录树,它只是通过了一定的数据结构,如List,Map等,来记录文件的层级关系,而并不会在文件系统中实际创建文件.
NameNode 重启时,恢复元数据
因为元数据是文件逻辑结构在内存中的信息,在 NameNode 关机之后,内存中的信息就被清空了;所以在 NameNode 重启的时候需要想办法重新加载之前的元数据。
元数据是和实际的文件一一对应的,如果元数据丢失了,那么就再也找不到实际文件的位置了(哪怕文件在系统中真实存在)
基于 editslog 机制实现 Master 重启之后的数据恢复
为了保存 NameNode 内存中的元数据,所以我们需要设计一个机制,在合适的时候将元数据持久化。
我们的第一反应应该都是将它存储到磁盘文件中去的,那么这里面应该怎么设计呢?
这里考虑以下几个问题:
- editslog 是以什么形式来存储,什么格式(如何序列化?)
- editslog 是单文件读写,还是拆分成多文件?
- 单纯的 editslog 存在什么问题没有?
问题一:editslog 的存储格式
hadoop 中采用的是它自己独特的序列化机制。。。
基于特殊的序列化的机制,写入磁盘文件的东西看起来跟乱码一样的,在用的时候不是很方便,但是因为经过了压缩处理,所以会很节约磁盘的空间开销。
中间件系统在设计磁盘上的数据存储格式的时候,序列化方式的时候,考虑这个数据有多大,如果数据量很大很大的话,那必须精心设计一套数据存储格式,尽可能用二级制类的bit位来代表很多东西,long很多bit位就可以代表很多信息了,kafka就是这样,每条数据的大小就被压缩到了极致。kafka,磁盘文件日志去存储写入的所有的消息,每天可能上 TB 的,所以说它必须精心设计他的消息格式,序列化的方式,尽可能紧凑的压缩消息的存储,用最少的bit位去存储尽可能多的信息,节约磁盘开销。
但是我们这里考虑到的是分布式文件系统,文件目录树对应的磁盘文件,其实不会太大,如果太大的话,也可以分成几个文件来存放,一般来说都还好。所以说不用过于讲究,直接用简单易用的 JSON 格式,一行放一个 editslog 即可。
问题二:editslog 文件是否需要拆分?
单文件的读写性能是会随着文件变大而下降的,而分布式系统中的 editslog 是不断增长的,所以需要采取分段存储的机制。
先写入一个文件,待文件大到阈值之后,就拆分出一个新文件;一般来说建议单个日志文件的大小不要超过1GB。
问题三:editslog 机制还存在的问题?
对 editslog 文件进行拆分解决了单文件过大读取性能很差的问题,但是在 NameNode 重启时,还是需要读取所有的 editslog 文件,因为所有文件加起来才是完整的元数据;随着系统投入时间的增加,editslog 文件数量可能是巨大的,这样会导致 NameNode 重启时间很久。