怎么做 HDFS 的原地平滑缩容?
背景
当数据规模越来越大,存储成本也水涨船高。随着时间推移,数据热度分布往往呈 2⁄8 原则,即 80% 的访问集中在 20% 的数据上。对于那不经常访问的 80% 数据来说,使用多个 SSD 来存储真是巨大的浪费,需要将冷数据迁移到其他存储成本更低的系统里。这时 JuiceFS 成了理想之选,成本下降 20 倍,同时又提供跟 HDFS 一样高性能的元数据能力(避免Metastore 遍历元数据时雪崩),大量扫描冷数据时也有很高的吞吐量。如果 80% 的数据转移到 JuiceFS 上来,整体成本可节省 90%。如果再给 JuiceFS 提供 适当的空间做缓存,还可以完整替换 HDFS (20% 的热数据通过 JuiceFS 管理的缓存盘来服务,也可以有极高的性能)。
2019 年里,我们就实施过几个这样的案例。当数据迁移到 JuiceFS 上之后,HDFS 容量降下来了,就需要做好缩容才能最终把存储成本降下来。扩容大家都做过,但是缩容很多人还不熟悉,下面我们就详细说说如何做好 HDFS 缩容,尤其是这个背景下的缩容。
三种缩容方案
第一种缩容方法,如果 DataNode 的节点数目比较多,并且允许缩减存储空间的同时缩减 CPU 和内存资源,则可以缩掉若干个 DataNode 节点,直接使用 HDFS 提供的 decommission。这是最常见的方法,缩减过程中涉及大量数据的跨节点迁移,会产生大量的内网流量可能影响线上负载,需要运维人员保持密切关注和手动调优,通常需要一两周的时间。如果集群只剩 3 个 DataNode 节点,或者上面的 CPU 或者 内存资源不能同步缩减时,就不能用这个方法了。
第二种缩容方法,即在保持 DataNode 节点数不变的情况下,缩减每个节点上的磁盘空间,可以修改 DataNode 上的 dfs.data.dir参数,删掉一个或者多个磁盘目录,然后等待 HDFS 自动补充副本。这个方法统一也会导致节点间的大量数据移动,会产生大量的内网流量可能影响线上负载,需要运维人员保持密切关注和手动调优,可能也需要一两周时间。此外,如果数据只有 2 副本,相对会比较危险,一旦删除一个磁盘目录时正好有节点出问题或者某块磁盘坏掉,极有可能造成数据缺失。
以上两种方法都会产生大量网络流量,可能影响线上服务,并且会增加丢失数据的风险。本文提供第三种方法,怎么在缩容的同时,尽量避免产生的内网流量影响线上工作负载,同时尽量减少缩容过程中数据丢失的风险。
方案分析
首先我们看一下 DataNode 在磁盘上的目录结构:
└── dn
├── current
│ ├── BP-847673977-192.168.0.120-1559552771699
│ │ ├── current
│ │ │ ├── dfsUsed
│ │ │ ├── finalized
│ │ │ │ ├── subdir0
│ │ │ │ │ ├── subdir1
│ │ │ │ │ │ ├── blk_1073742303
│ │ │ │ │ │ ├── blk_1073742303_1479.meta
│ │ │ ├── rbw
│ │ │ └── VERSION
│ │ ├── scanner.cursor
│ │ └── tmp
│ └── VERSION
└── in_use.lock
BP-847673977-192.168.0.120-1559552771699:这是块池目录,如果以 Federation 方式部署的时候,会有多个块池目录。dfsUsed:保存的是磁盘的使用统计数据,每 10 分钟刷新一次。finalized和 rbw 目录:这两个都是用于存储数据块的,finalized 放的是已经完成写入的数据块,rbw 是正在写入的数据块。每个数据块对应 2 个文件,blk 文件存放数据,另外一个以 meta 结尾的存放校验和等元数据。VERSION文件:主要包含布局版本、集群 ID、DataNode ID、块池 ID 等信息。scanner.cursor文件:DataNode 会定期的对每个blk文件做校验,这个文件是用来记录校验到哪个位置的。- 不难看出所有的数据文件都存在
finalized和rbw里面,并且同一个DataNode上面不会存在相同 Block ID 的数据文件。因此完全可以通过迁移 blk 文件的方式来将一块磁盘上面的数据移动到另外一块磁盘上,然后在卸载此磁盘来达到缩容的目的。
缩容步骤
本文示例的 HDFS 是 CDH 5.16 版本,使用 ClouderaManager 管理集群。集群只有 3 个节点,每个节点有多块 SSD 盘,数据两副本,存储利用率很低,每个节点都可以卸载掉一块磁盘,但是无法使用前面两种常见的缩容方法,同时缩容过程要尽可能可能减小对线上服务的影响。
以下操作均是针对单一 DataNode 的操作,其他 DataNode 也需要按照以下步骤执行(可以适当并行):
- 选择磁盘。选择需要被卸载的数据盘和接收数据的数据盘,注意要确保接收数据的磁盘剩余空间够大于被卸载磁盘上的数据。这里假设:
被卸载磁盘:/dfs1,此磁盘上的 DataNode 数据目录:/dfs1/dfs/dn
数据接收盘:/dfs,此磁盘上的 DataNode 数据目录:/dfs/dfs/dn
- 第一次复制数据。从
dfs.data.dir里面挑选出在被卸载磁盘上面的目录,然后将此目录全量拷贝到接收数据盘上,为了尽量减少对 IO 的占用,用ionice加rsync的方式拷贝数据,确保不阻塞高优先级的任务。
ionice -c 2 -n 7 rsync -au /dfs1/dfs/dn/ /dfs/shrink_temp/dn
需要保证数据都被拷贝过去了,所以需要将 DataNode 停掉。可以通过 ClouderaManager 界面关闭 DataNode。
第二次增量复制数据。重复步骤 2,将在步骤 2 和步骤 3 之间的新增数据增量更新到接收盘上。增量数据会比较少,估计能很快完成。
ionice -c 2 -n 7 rsync -au /dfs1/dfs/dn/ /dfs/shrink_temp/dn
- 合并目录。此时被卸载盘上的数据都已经复制到接收盘上,但是数据还在原来的文件夹里面。如果同一块磁盘上面有两个 DataNode 数据目录的话,会导致 HDFS 容量计算重复,因此需要合并。可以通过 rsync 的硬链的方式将数据拷贝过去,这样不涉及真正的数据拷贝,执行非常快,同时将拷贝过去的源数据删除。检查剩余数据是否有 blk 文件,没有就合并完成。
ionice -c 2 -n 7 rsync -au --link-dest=/dfs/shrink_temp/dn --ignore-existing --remove-source-files /dfs/shrink_temp/dn/ /dfs/dfs/dn
通过 ClouderaManager 修改 dfs.data.dir 配置项,删除卸载磁盘上的数据目录。
通过 ClouderaManager 启动 DataNode,并检查 HDFS 的状态。
sudo -u hdfs hdfs fsck /
为什么不直接将被卸载盘的数据复制合并到接收盘的 DataNode 数据目录里面呢? 这是因为,在第一次拷贝的时候,DataNode 仍然在运行,因此 DataNode 会定期检查副本数量,此时拷贝过去的数据算是额外副本,有可能会被 DataNode 删除掉。
整个缩容过程中 DataNode 停止的时间只是步骤 4 和步骤 5 所需时间。步骤 4 是增量拷贝,速度很快,步骤 5 只是文件元数据操作,同样很快。
以上步骤看起来比较多,手动操作会容易出错,因此我们将以上缩容过程写了一个脚本(部分操作依赖 Hadoop 发行版的 API,目前支持 CDH5),请下载setup-hadoop.py,运行命令,并按照提示输入进行缩容:
python setup-hadoop.py shrink_datanode
未来改进
在上面的缩容过程里,需要将数据是从一块磁盘完整地拷贝到另外一块磁盘,需要它有足够的剩余空间,另外也可能导致 DataNode 内磁盘间数据不均衡。未来可以改进下这个缩容过程,在复制数据时根据某个规则将 blk 文件复制到多块盘,确保多块磁盘之间的数据均衡。
如有帮助的话欢迎关注我们项目 Juicedata/JuiceFS 哟! (0ᴗ0✿)
怎么做 HDFS 的原地平滑缩容?的更多相关文章
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容
上一篇我们讲到了dapr提供的bindings,通过绑定可以让我们的程序轻装上阵,在极端情况下几乎不需要集成任何sdk,仅需要通过httpclient+text.json即可完成对外部组件的调用,这样 ...
- Mycat节点扩缩容及高可用集群方案
数据迁移与扩容实践: 工具目前从 mycat1.6,准备工作:1.mycat 所在环境安装 mysql 客户端程序. 2.mycat 的 lib 目录下添加 mysql 的 jdbc 驱动包. 3.对 ...
- 023.掌握Pod-Pod扩容和缩容
一 Pod的扩容和缩容 Kubernetes对Pod的扩缩容操作提供了手动和自动两种模式,手动模式通过执行kubectl scale命令或通过RESTful API对一个Deployment/RC进行 ...
- 生产调优4 HDFS-集群扩容及缩容(含服务器间数据均衡)
目录 HDFS-集群扩容及缩容 添加白名单 配置白名单的步骤 二次配置白名单 增加新服务器 需求 环境准备 服役新节点具体步骤 问题1 服务器间数据均衡 问题2 105是怎么关联到集群的 服务器间数据 ...
- Redis Cluster 自动化安装,扩容和缩容
Redis Cluster 自动化安装,扩容和缩容 之前写过一篇基于python的redis集群自动化安装的实现,基于纯命令的集群实现还是相当繁琐的,因此官方提供了redis-trib.rb这个工具虽 ...
- k8s Pod 扩容和缩容
在生产环境下,在面临服务需要扩容的场景时,可以使用Deployment/RC的Scale机制来实现.Kubernetes支持对Pod的手动扩容和自动扩容. 手动扩容缩容 通过执行扩容命令,对某个dep ...
- 基于Ambari的WebUI实现服务缩容
基于Ambari的WebUI实现服务缩容 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.实现服务的扩容 1>.进入到主机的管理界面 2>.查看主机的信息概览 3&g ...
- map的自动扩容与手动缩容
map的自动扩容与手动缩容 首先还是提出问题:扩容和缩容有什么用?为什么需要扩容和缩容? 在想解答这个问题之前,首先还是需要了解一下go语言中的map go语言中的map与Java中的map实现还是有 ...
- LVM划分磁盘及扩容缩容
lvm:logical volume monitor 逻辑卷管理器 作用: 采用lvm划分磁盘:磁盘空间不够时,方便扩展磁盘.物理卷加到卷组时被划分等大的pe,即pv是由众多pe构成.pe是卷组的最小 ...
随机推荐
- CAAnimation——简介
- IOS开发之----常用函数和常数--秀清
介绍一下Objective-c常用的函数,常数变量 算术函数 [算术函数] 函数名 说明 int rand() 随机数生成.(例)srand(time(nil)); //随机数初期化int val = ...
- 基于zynq XC7Z100 FMC接口通用计算平台
1.板卡概述 此板卡是北京太速研发,由SoC XC7Z100-2FFG900I芯片来完成卡主控及数字信号处理,XC7Z100内部集成了两个ARM Cortex-A9核和一个kintex 7的FPGA, ...
- 常用文本处理命令 & 三剑客之 sed
今日内容 文本处理命令 Linux 三剑客之 sed 内容详细 文本处理命令 1.sort : 文件内容排序 默认按照文件隔行内容的第一个字符大小进行排序(默认是升序) 默认输出文本结果 sort [ ...
- Note -「最大团-最小度不等式」
这是什么奇怪的名字qwq. 一些定义 只为便于理解,没有苛求专业的定义. 简单无向图:不存在重边.自环的无向图. \(\delta(G)\):无向图 \(G\) 中结点的最小度数.即 \(\m ...
- 简述LSM-Tree
LSM-Tree 1. 什么是LSM-Tree LSM-Tree 即 Log Structrued Merge Tree,这是一种分层有序,硬盘友好的数据结构.核心思想是利用磁盘顺序写性能远高于随机写 ...
- Smartbi权限安全管理系统_保障数据权限安全
思迈特软件Smartbi具有完善的安全管理体系,Smartbi权限安全管理系统它可以控制用户功能权限.数据访问权限.资源访问权限.Smartbi权限安全管理系统支持按用户.用户组.角色进行管理:支持多 ...
- 案例六:shell脚本监控httpd服务80端口状态
这里是举例监控httpd服务端口状态,根据端口判断服务器是否启动,如果没有启动则脚本自动拉起服务,如果服务正在运行则退出脚本程序:如果换成别的服务端口也可以,但是脚本程序需要做调整. #!/bin/b ...
- 多态在C#中的应用
C# 语言经过专门设计,以便不同库中的基类与派生类之间的版本控制可以不断向前发展,同时保持向后兼容.这具有多方面的意义.例如,这意味着在基类中引入与派生类中的某个成员具有相同名称的新成员在 C# 中是 ...
- [转帖]Linux 下解压 rar 文件
转至:https://www.cnblogs.com/jinanxiaolaohu/p/13824185.html https://www.cnblogs.com/xuyaowen/p/unrar_f ...