怎么处理HDFS问题

60次阅读
没有评论

共计 9898 个字符,预计需要花费 25 分钟才能阅读完成。

这篇文章主要介绍“怎么处理 HDFS 问题”,在日常操作中,相信很多人在怎么处理 HDFS 问题问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么处理 HDFS 问题”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!

1. 定期 block 全盘扫描,引起 dn 心跳超时而脱离集群

hdfs 有一个目录扫描机制,默认 6 小时会全盘扫描一次所有 block,判断与内存里的那份 blockMap 是否一致。参考
https://blog.cloudera.com/hdfs-datanode-scanners-and-disk-checker-explained/
在小文件比较多的情况,扫描的时候特征很明显——磁盘的 iops 很高,但吞吐量很低。当然这不是引起 datanode 心跳超时的原因,真正的原因是处理扫描后的结果,比如比较完发现有 20000 个 block 不一致,在修复这些 block 时不断的持有了 FsDatasetImpl 这个对象的一把锁,在磁盘比较慢的情况下,可能需要 5 分钟甚至 10 分钟处理完,从而一直阻塞读、写、心跳的线程。

详细的可以了解 HDFS-14476 lock too long when fix inconsistent blocks between disk and in-memory,包括一些特征、证据,以及 block 修复逻辑,细节比较多。

解决办法是,我们这边加了个 patch(已合入 2.10 和 3.x),在处理异常 block 的时候,中间休息 2 秒,处理一下正常的请求,不至于 datanode 卡住甚至离线。
修复后的结果也是很明显,datanode 心跳平滑了许多

2. namenode 迁移裁撤,遇到客户端无法写入

在文章  HDFS namenode 节点裁撤不停服迁移实践   里总结了在线迁移 namenode 的方法。迁移 / 裁撤的思路是保持 namenode hostname 不变,滚动迁移 standby 的方式迁移。

但是在我们的迁移实践中,发现 hdfs namenode 完成迁移后,集群正常,但 hdfs 客户端访问异常。在 yarn 这样的长任务场景下,会导致文件读写一直失败,直到 yarn nodemanager 重启。

具体问题是这样的:

client 使用的是 ConfiguredFailoverProxyProvider,client 启动之后会根据当时的 inetsocket 创建 nn1,nn2 两个 namenode proxy,这个在任何网络异常的情况下都不会重新创建。

client 的 updateAddress 方法能检测到 namenode ip 发生了变化,但由于那个异常没有捕获,本该在下次循环使用正确的 namenode ip 就能正常,但抛出异常后导致 client 重新连接 namenode,然而上面的 namenode proxy 还是旧地址,SetupConnection 异常,又进入 updateAddress 判断逻辑,返回 true 又去建连接,陷入了死结。

复现步骤

打开一个 hdfsclient,长时间写一个文件 hdfs put

更新 hdfs 新 namenode hostname-ip

stop old nn2, start new nn2

更新客户端的 namenode hostname-ip (client 还在操作文件)

切换到新 namenode hdfs haadmin -failover nn1 nn2

此时会发现 client 一直报错
在 yarn 客户端启动的周期内,哪怕是新文件写入,依旧会报错

对 ConfiguredFailoverProxyProvider 打了个 patch,就是在 client failover 之后,也进行 updateAddress 判断,如果有 ip 变动,就重新 createProxy。验证这个 patch 同样有效。不过在 client 那边统一捕获会比较好,因为还有其他类型的 HaProvider 可能也有这个问题。

这个问题的 patch 已经被合入 Apache Hadoop 3.4,见 HADOOP-17068 client fails forever when namenode ipaddr changed。我们用的版本是 2.6.0-cdh6.4.11,也已合入。

除了从根源问题上解决,也可以在 namenode 迁移操作时,在老节点上启用端口转发,再逐个重启 yarn,避免引起大范围故障。

3. 集群 dn 不均衡导致文件写入失败

现象:集群将满时,扩容了批机器缓解空间。运行了 2 个星期客户端突然报文件写入失败
原因:hdfs 在部分 datanode 空间满的情况下,理论会自动挑选其它可用的空闲节点。由于  dfs.datanode.du.reserved 配置不当,导致依然会选中满节点。具体是 dfs.datanode.du.reserved 如果小于分区 block reserved,在磁盘用满时就会出现

org.apache.hadoop.ipc.RemoteException(java.io.IOException): File 
/kafka/xxxtmp.parquet could only be replicated to 
0 nodes instead of minReplication 
(=1).  \
There are 14 datanode(s) running and no node(s) are excluded in this operation.

解决:

扩容完,跑 rebalance

修改磁盘分区的 block reserved,使其小于  dfs.datanode.du.reserved. 见  hdfs datanode Non DFS Used 与 Remaining .

增加单个 datanode 容量告警

4. 做 rebalance 时速度很慢

启动 rebalance 命令./start-balancer.sh -threshold 10,如果需要提高速度可以修改限流带宽 hdfs dfsadmin -setBalancerBandwidth 52428800
但是 datanode 上同时接收 blocks 并发数,是不能在线调整的(或者说只能调小),调整 hdfs-site.xml 默认的 balance 参数,并重启

dfs.balancer.moverThreads=1000
dfs.balancer.dispatcherThreads=200
dfs.datanode.balance.max.concurrent.moves=50

如果启动 balance 时,尝试以更高的并发执行,datanode 会判断没有足够的线程接收 block: IOException: Got error, status message Not able to copy block … because threads quota is exceeded。
当 move 出现失败时,迁移速度是指数级下降的,因为 move block 失败默认会 sleep 一段时间。

./start-balancer.sh 
-threshold 
5\
-Ddfs.datanode.balance.max.concurrent.moves=20 \
-Ddfs.datanode.balance.bandwidthPerSec=150000000 \
-Ddfs.balancer.moverThreads=500 \
-Ddfs.balancer.dispatcherThreads=100

5. 给 datanode 在线增加磁盘

腾讯云上的机器,可以直接在原有 datanode 上直接挂在新的磁盘,快速给 hdfs 扩容。
增加磁盘,不需要重启 datanode。(前提是设置了  dfs.datanode.fsdataset.volume.choosing.policy 为 AvailableSpaceVolumeChoosingPolicy)

挂载后,先建立 hadoop 数据目录并修正权限

在 hdfs-site.xml  里加上新目录配置  dfs.datanode.data.dir

可以使用 reconfig 命令使其生效: hdfs dfsadmin -reconfig datanode dn-x-x-x-x:50020 start

6. namenode 设置了 HA,但故障时未成功切换

现象:active namenode 内存故障,主备切换失败
原因:dfs.ha.fencing.methods 设置为了 ssh,但是并不能登录其他 namenode 执行 fence
解决:生成 ssh key,免密码登录。或者改成 shell(/bin/true),强切。注意,修改 fence 方式后,需要重启 zkfc。

7. hdfs client input/output error

现象:执行  hdfs  客户端命令报错  input/output error,试着拷贝 hadoop / jdk 的介质目录,亦发现文件损坏。有时会发现 jvm core
原因:磁盘存在坏块,刚好 hdfs 或者 jdk 的 jar 库损坏。通过观察 messages 发现有  sda IO Input/Output Error
使用 badblocks -s -v -o bb.log /dev/sda  可以看到磁盘损坏了哪些扇区
解决:从其他机器,拷贝一份正常的介质

8. hdfs 误将 data 盘作为数据盘

误将系统盘作为了 dfs.datanode.data.dir,运行一段时间后,这个分区很容易最先满。
这个是配置上的问题,理解 datanode 的工作方式,可以快速的将这个分区里的 block 挪到正确的磁盘分区。
处理方法就是停止 datanode,拷贝 /data block 到其它分区,删掉 /data 的配置。因为 datanode 上 block 的位置是每次启动的时候,扫描上报给 namenode,所以可以做物理拷贝。
可以使用拷贝命令 cp -a /data/hadoopdata/current/BP-*-*/current/finalized/* /data1/hadoopdata/current/BP-*-*/current/finalized/ ,不能拷贝整个 hadoopdata 目录,因为 VERSION 文件里面的 storageID 不同。

9. 使用 decomiss 方式将 datanode 退服时,客户端读写异常

现象:将 datanode 加入 exclude,正常 decomissing 的方式退役节点,应用层反馈 spark 任务部分异常,报错  Unable to close file because the last block doest not have enough number of replicas ,但该集群一些其它的文件读写任务正常。
原因:spark 任务会频繁的创建、删除 application 目录。在 decomissing 时,部分磁盘性能低的节点,磁盘更加繁忙,导致出现 last contact 心跳时间长
解决:经过验证,发现直接 kill datanode 进程的方式,不影响 spark 任务。但必须保证一个一个的 kill,否则会出现 missing block.(这不一定是解决问题最好的办法,但的确有效)

10. namenode editlog 长时间未做 checkpoint

standby namenode 的一个作用是,定期合并从 journalnode 上获取的 editlog,生成新的元数据 fsimage,然后推送到 active namenode。
当 standby namenode 出现异常,如进程退出、软件 bug(比如我们遇到过  IOException: No image directories available!),导致长时间未合并 editlog。一旦需要发生切换或者重启 namenode,有可能导致启动时间过长,严重的 editlog 合并需要的内存不足,无法启动 namenode.

如果内存不足,一种解决办法是借一台高内存临时机器合并 editlog:

把 standby 停下来,将 hdfs 的软件介质和配置文件,拷贝到高内存机器

同时拷贝 dfs.namenode.name.dir  目录中最新能用的  fsimage_xxx  和它之后的所有  edits_xxx-xxx

在临时机器上启动 namenode 进程,会自动从对应目录加载 fsiamge、合并 editlog

预防比补救要重要,一定要监控 namenode 上  TransactionsSinceLastCheckpoint  这个指标,我们的阈值是达到 5000000 就告警。

11. HDFS 3.x datanode 出现大量 CLOSE-WAIT

这个问题  HDFS-15402  是在定期对 datanode http://127.0.0.1:50075/jmx jmx 进行探测的时候产生的,我们有 5 个 hadoop 3.1.3 的集群都存在该问题。在 hadoop 2.x 中正常。
50075 端口上产生过多 close-wait 的影响是,正常的 webhdfs 会出现 504 Gateway-timeout

[root@dn-9-4-xxx-yy 
/tmp]# ss -ant|grep :50075 |grep CLOSE-WAIT|wc -l
16464
[root@dn-9-4-xxx-yy /tmp]# ss -ant|grep :50075 |grep CLOSE-WAIT|head -3
CLOSE-WAIT 123    0                9.4.xxx.yy:50075           9.4.xxx.yy:39706
CLOSE-WAIT 123    0                9.4.xxx.yy:50075           9.4.xxx.yy:51710
CLOSE-WAIT 123    0                9.4.xxx.yy:50075           9.4.xxx.yy:47475

lsof -i:39706
COMMAND    PID USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
java    134304 hdfs *307u  IPv4 429yy7315      0t0  TCP dn-9-4-xxx-yy:50075- dn-9-4-xxx-yy:39706 (CLOSE_WAIT)
 
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp      123      0 9.4.xxx.yy:50075            9.4.xxx.yy:39706            CLOSE_WAIT  134304/java

CLOSE-WAIT 状态是客户端 (curl) 发起关闭 tcp 连接时,服务端 (datanode) 收到了 FIN-ACK,但在关闭 socket 时一直没有完成。正常流程是关闭 socket 完成,然后向客户端发送 FIN

所以问题出在 datanode server 上,与 knox 还是 haproxy 客户端没有关系。并且这个问题调整 os 内核参数是没有用的,除非 kill datanode,否则 close-wait 状态会永久存在。使用网上的 kill_close_wait_connections.pl  能够清理这些 close-wait,之后 webhdfs 请求变得好转。

目前避开的方法就是,不再请求 datanode jmx 做监控,只获取 namenode 上的指标。datanode 上采集 os 级别的指标。

12. knox 无法上传 8G 文件

在官方 jira 里我们提了这个问题  KNOX-2139,当我们使用 webhdfs with knox 上传  8589934592 bytes  大小的文件,会出现  (55) Send failure: Broken pipe,在 hdfs 只能看到一个空文件。而且在版本 knox 1.1, 1.2 中是必现,在 0.8 版本正常。

简单 debug 了一下代码,knox 拿到的请求 contentLength 为 0,8G 以外的情况 contentLength 为 -1。

我们后来使用 haproxy 代替 knox 解决 knox 自身上传速度慢和这个 8G 文件的问题。在   备份系统上传优化:从 knox 到 haproxy  有介绍我们的实现

不过在最新的 1.4 版本,8G 问题又消失了。根据官方的恢复,可能跟 jetty 的升级有关。

13. Unable to load native-hadoop library for your platform

Unable to load native-hadoop library for your platform… using builtin-java classes

经常在执行  hdfs  客户端命令时会有这样的提示,其实是个老生常谈的问题。

简单说就是系统里没有找到原生的 hadoop 库  libhdfs.so,这个库是 C 写的,性能比较好。缺少但不影响使用,因为 hadoop 里有 java 实现的客户端库。

出现这个我总结原因有 3 个:

hadoop 安装包里没有自带  libhdfs.so
这个情况占很大一部分。去到目录 ${HADOOP_HOME}/lib/native/,看下是否有 libhdfs.so,libhdfs.a,libhadoop.so,libhadoop.a。如果没有的话,可以重新下一个完整的二进制包,把 lib/native 拷出来用
这种看到才是正常的

./bin/hadoop checknative
20/05/14 20:13:39 INFO bzip2.Bzip2Factory: Successfully loaded initialized native-bzip2 library system-native
20/05/14 20:13:39 INFO zlib.ZlibFactory: Successfully loaded initialized native-zlib library
Native library checking:
hadoop:  true /data1/hadoop-hdfs/hadoop-dist/target/hadoop-2.6.0-cdh6.4.11-tendata/lib/native/libhadoop.so.1.0.0
zlib:    true /lib64/libz.so.1
snappy:  true /data1/hadoop-hdfs/hadoop-dist/target/hadoop-2.6.0-cdh6.4.11-tendata/lib/native/libsnappy.so.1
lz4:     true revision:10301
bzip2:   true /lib64/libbz2.so.1
openssl: true /usr/lib64/libcrypto.so

实在不行就在自己的 os 上编译一个。

mvn clean package 
-Pdist,native 
-DskipTests 
-Dtar 
-Dbundle.snappy 
-Dsnappy.lib=/usr/local/lib

so 文件存在,但路径不对
现在的版本,默认路径都能找得到 so 库。这个  Hadoop“Unable to load native-hadoop library for your platform”warning  里面介绍的大部分方法,都是在教怎么设置路径。真实原因很少会因为路径不对,不过这个答案靠谱  https://stackoverflow.com/a/30927689 ,也就是我们的情况 3

编译的版本,在我们的 os 上依赖库不全
遇到过这种,glibc 库版本不够:

$ ldd lib/native/libhadoop.so
lib/native/libhadoop.so: /lib64/libc.so.6: version `GLIBC_2.14 not found (required by lib/native/libhadoop.so)
linux-vdso.so.1 =  (0x00007ffd1db6d000)
/$LIB/libonion.so = /lib64/libonion.so (0x00007f5bfd37d000)
libdl.so.2 = /lib64/libdl.so.2 (0x00007f5bfce40000)
libpthread.so.0 = /lib64/libpthread.so.0 (0x00007f5bfcc23000)
libc.so.6 = /lib64/libc.so.6 (0x00007f5bfc88f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5bfd266000)

$ strings /lib64/libc.so.6 |grep GLIBC_
可以看当前系统支持哪些版本的 glibc

但是 glibc 安装升级有风险,如果要安装 2.14 版本务必先做好测试。

14. 处理 missing blocks

hdfs 集群出现 missing block,无非就是 namenode 里还记录的 block 元数据信息,但是所有副本都丢失了。如果是同时挂了多个机器,或者损坏了多个机器上的磁盘,是有可能会出现。
遇到过 2 次人为产生 missing blocks:

kill 一个 datanode 进程,就出现 missing block

先设置所有文件的 replication 为 1,一小段时间后,再设置为 2

这两种情况都算是 bug,对应的文件确实无法 get 下来了。但第 1 中情况还好,经过排除日志,发现实际这些丢失的 blocks 本就接收到了删除命令,过一段时间后,missing block 一般会自动消失。第 2 中情况,是真的意外丢 block 了,比较严重。不要轻易把 replication 设置为 1,再改回去可能丢 block。

如果确认这些 missing block 可以消除,可以通过 fsck 命令手动处理:

// 如果 missing blocks 数不是很多,可以直接逐个 delete
hdfs fsck file_name -delete

// 如果 missing blocks 较多,可以从 namenode 上拿到 corrupt 块
hdfs fsck / -list-corruptfileblocks -openforwrite | egrep ^\.+$ | egrep MISSING|OPENFORWRITE | grep /[^]* | sed s/:$// missing_blocks.txt

15. 应该关注的告警

实际还有些许多问题,比如用户 supergroup 权限问题、rack-aware.sh 文件缺失的问题,限于篇幅就不列举了。
问题是不断会出现的,但及时对大部分场景做到监控工具,能够提前发现问题。下面是整理并上线的关键告警指标:

datanode lastcontact
datanode 与 namenode 心跳监控。心跳时间长意味这这个 dn 没响应了,默认超过 10m30s 没响应,dn 会脱离集群。

namenode and datanode web probe
namenode 50070 与 datanode 50075 从外部探测,并且 datanode 会根据 include 里面的地址自动增减。我们使用修改过了 telegraf http_response 插件, 支持动态读取 url,比如  exec bash get_datanode_urls.sh

dirctory max files
单目录下的文件数告警。hdfs 默认限制单目录下最大的文件数 100 万,由配置项 dfs.namenode.fs-limits.max-directory-items 决定。
这个指标数据来源于 fsimage 目录画像分析。

transactions not merged
standby 未滚动的 editlog 数。长期未 checkpoint 会导致下次 namenode 启动消耗过多内存,甚至启动失败。

missing blocks
异常 blocks 数

test write file
在 2 个 namenode 节点上,定期使用 hdfs put/get 写入文件。如果失败会告警

non-active namenode
hdfs 集群 namenode 有且只有一个 active,一个 standby。其它情况告警

cluster capacity
集群总体容量监控

node usage, ioutil
单个 datanode 磁盘空间使用率预警,ioutil 持续 5 分钟大于 95% 预警。

failover occurs
hdfs namenode 发生 failover

namenode heap size
namenode heap size 使用比率。blocks 数量多,内存使用越多。

到此,关于“怎么处理 HDFS 问题”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-27发表,共计9898字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)