说说hdfs是如何处理块副本多余和缺失的
上一文,我们讲了nn在内存中如何对元数据进行存储和管理的,文章最后也提到了nn内部如何保证块的副本数维持在指定个数,即对副本缺失的块触发块副本复制,对副本多余的块触发块副本删除。本文就来详细聊聊具体流程及细节。
【块副本复制的场景与处理逻辑】
哪些时候会出现需要块的副本数不够,需要进行块副本复制呢?
一种是客户端或管理员手动修改块的副本数,将其扩大;另一种则是块副本所在dn节点异常,包括网络异常,物理机异常,程序被kill导致的异常下线;又或者是块副本存储所在dn节点的磁盘异常,例如磁盘被拔掉,或者确实出现了坏盘。两种情况都会导致块的副本数不满足实际设置要求。
不管哪种情况,在nn内部最终处理时(处理dn的块汇报、处理dn的心跳超时,处理管理员或客户端的设置),都会将不满足副本数的块放到UnderReplicatedBlocks中。
接下来就是块副本复制的处理流程(看图说话)
1. 块副本监测线程(ReplicationMonitorThread)定时监测是否有不满足副本数的块,如果有则取出块信息。
2. 根据块的当前副本数情况,选择一个作为副本复制源的dn节点,同时结合块的存储要求,选择一个合适dn节点,作为复制的目的节点。
3. 然后封装成一个任务放到复制源dn节点信息(DatanodeDescriptor)的链表中。
4. 同时将块副本复制任务进行封装放到等待执行块副本复制的队列中。
5. 此后,nn在处理块副本复制源的dn节点的心跳处理时,从队列中取出块副本复制任务作为心跳响应的命令下发给dn,dn节点处理心跳响应的命令,向指定的节点建立连接并传输块副本数据及校验和数据。
当dn完成块副本的数据传输后,目的端的dn节点会通过增量块汇报向dn上报块副本的信息。
6. 在块副本监测线程将块副本复制任务放到队列后,另外一个等待块副本复制的监测线程(PendingReplicationMonitorThread)定时监测块副本复制队列中任务情况,如果块副本复制任务在队列中超过指定时间,其块的副本数仍旧没有达到指定副本数时,将该任务从队列取出置为超时状态,并将其放到超时队列中。如果已经达到指定副本数,则直接从队列中移除。
7. 上面提到的块副本监测线程在一轮处理的最后,会将超时队列中的任务重新加到UnderReplicatedBlocks中,等待下次轮询时再重复上面的处理逻辑。
【处理中的一些细节】
首先是用于存储块副本数的不满足的UnderReplicatedBlocks采用了5个队列,每个队列中又是一个轻量级的集合的方式进行存储。
5个队列实际上对应5个不同的优先级,即对不满足副本数的块定义了不同的优先级,这些块在存储时按按优先级存到不同的队列中,取出时则按高优先级到低优先级的顺序依次取出触发块副本复制任务。
对应源码:
其次,在块副本复制的过程中,是具有一定的流控机制的。具体体现为:
块副本监测线程的执行是有一定时间间隔的
块副本监测线程每次从UnderReplicationBlocks中取出的块个数是有限制的,每次轮询触发块副本的个数为:当前在线的dn节点数 ✖️ 指定系数
nn通过心跳给dn下发块副本复制任务也是有最大限制的,即如果给某个dn下发的块副本复制任务已经达到最大数,在该dn(任意一个块副本复制任务)未完成之前,不会再继续下发复制任务。
这样一来,可以确保dn节点不会瞬间因大量的副本复制任务影响到正常的读写流程。
【块副本删除的流程】
既然有不满足副本数的场景,那么相应的也会有超过副本数的场景,例如客户端或管理员对某个文件设置比原来小的副本数;或者某个dn节点异常先触发了副本复制任务,在完成副本复制之后,异常的节点又恢复了,这个时候节点重新向nn注册并进行块汇报,就出现了某些块的副本数超出了指定个数的情况。
块副本删除的处理逻辑和块副本复制的处理流程几乎相同,首先是超出副本数的块会存放到指定的地方(InvalidBlocks);其次,同样是在副本监测线程中从invalidBlocks中取出块的信息,并决定需要从哪个dn节点删除对应的块副本,构造对应的删除任务放到dn节点信息的某个链表中,然后在心跳响应中将任务下发给dn节点。
最后,块副本的删除也同样是具有一定流控机制的。
相关配置整理:
# 副本监测线程轮询处理的时间间隔
# 默认时间间隔为3s
dfs.namenode.replication.interval
# 每次触发副本复制的系数
# 默认为2, 即当前在线dn节点数的2倍
dfs.namenode.replication.work.multiplier.per.iteration
# 单个dn的最大副本复制任务数
# 默认值为2个
dfs.namenode.replication.max-streams
# 每次触发副本删除的系数
# 默认为0.32
dfs.namenode.invalidate.work.pct.per.iteration
# 单个dn副本删除任务的上限
dfs.block.invalidate.limit
【总结】
本文主要讲解了nn中块副本复制、块副本删除的流程,由此可以看出,hdfs具备一套完整的机制来确保副本数与设置的数目保持一致。
里面还可以深究的一些点,例如块副本复制时,如何选择源节点,目的节点的选择会受哪些因素制约;同样,块副本删除时怎么选择应当删除哪个节点上的副本;块副本的复制会产生额外的带宽,是否会影响正常的写等等,我们下次再聊~
好了,本文就介绍到这里,如果觉得本文对你有些帮助,来个点赞,在看吧,也欢迎分享转发, 谢谢~
本文分享自微信公众号 - hncscwc(gh_383bc7486c1a)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
dart系列之:如丝滑般柔顺,操作文件和目录
简介 文件操作是IO中非常常见的一种操作,那么对应dart语言来说,操作文件是不是很简单呢?实际上dart提供了两种读取文件的方式,一种是一次性全部读取,一种是将文件读取为流。 一次性读取的缺点是需要将文件内容一次性全部载入到内存中,如果遇到文件比较大的情况,就会比较尴尬。所以还需要流式读取文件的方式。一起来看看dart中这两种文件的读取方式吧。 File 事实上dart中有很多地方都有File这个类,这里我们要讲解的File类是dart:io包中的。 读取整个文件 File代表一个整体的文件,他有三个构造函数,分别是: factory File(String path) factory File.fromUri(Uri uri) factory File.fromRawPath(Uint8List rawPath) 其中最常用的就是第一个构造函数。 我们可以这样来构造一个文件: var file = File('file.txt'); 有了文件之后,就可以调用File中的各种读取方法。 文件读取本身有两种形式,一种是文本,一种是二进制。 如果是文本文件,File提供...
- 下一篇
COG云原生优化遥感影像,瓦片切分的最佳实践
摘要:云上遥感影像文件Cloud optimized GeoTIFF(COG)格式的详细介绍,大量数据上云面临的挑战,并分享了获得云原生影像最佳性能的实践经验。 本文分享自华为云社区《COG云原生优化遥感影像,瓦片切分的最佳实践》,作者: tsjsdbd 。 1 遥感影像文件格式 遥感影像就是地球自拍照,一般文件很大,一张文件5GB左右。 这些影像文件大多数都保存为 TIFF 格式(而不是JPEG),因为TIFF格式记录的内容是比较原始的多个波段的信息,也不会因为压缩丢失信息。 1.1 TIFF格式 这里分享一下 TIFF文件的格式: TIFF是一个灵活适应性强的文件格式,能够在一个文件中保存多幅图像。然后每幅影像带一个标签目录(多个标签),记录它的像素深度、每像素波段信息,RGB编码等详细信息。 注意:上图属性之间没有顺序要求,都通过offset查找。实际上是链表的形式: 因此,TIFF文件内部各Block块之间的顺序可以很灵活自由。 1.2 TIFF标签目录格式 每幅影像,带有一组标签目录,记录该图形的各种属性。 标签目录的格式如下: 每个标签(属性),由于信息内容不一样,其值大小...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS关闭SELinux安全模块
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS8安装Docker,最新的服务器搭配容器使用
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Docker使用Oracle官方镜像安装(12C,18C,19C)