使用Docker安装Hadoop,遇到的问题
# File /** could only be replicated to 0 nodes instead of minReplication (=1). There are 2 datanode(s) running and 2 node(s) are excluded in this operation.
# 1.问题描述
使用的Hadoop版本2.9.2,在Docker上部署了Hadoop集群,通过JavaAPI进行文件上传时报错,如下:
org.apache.hadoop.ipc.RemoteException: File /file/1704421744181BG8wB could only be replicated to 0 nodes instead of minReplication (=1). There are 2 datanode(s) running and 2 node(s) are excluded in this operation.
# 2.排查错误
在报错中明显提到错误消息提到文件只能复制到0个节点,而不是所需的最小复制数(minReplication = 1)。在这个操作中,有2个数据节点正在运行,同时还有2个节点被排除在此操作之外。
# 1.查看datanode是否都启动成功
进程都启动成功
# 2.查看web界面
可以看出都是正常运行的,集群运行时正常的,也不存在防火墙给拦截了之类的,要是拦截了,web界面肯定是看不到活的节点的。
# 4.通过shell命令测试上传和下载
准备数据1.txt在/home下
查看HDFS上的目录信息
测试就在master直接将文件上传到HDFS的/目录下,并查看
通过ssh连接到slave1上进行下载,并查看
可以看到,没有问题!
# 5.Java使用的Hadoop jar包的问题
因为我以前使用三台虚拟机部署集群,并使用JavaAPI进行操作没有出现任何问题,所以排除jar包的问题。
# 6.那为什么日志中说文件复制只能复制到0个节点呢?
现在已知没有问题的是容器之间的网络和集群状态,通过shell上传和通过API进行上传有什么区别呢?
# 7.通过shell上传和通过API进行上传有的区别
通过Shell上传原理:使用
hdfs dfs -put
命令时,Hadoop会将文件划分为数据块,并将这些数据块分布式地复制到HDFS上的DataNode。命令执行时,NameNode会记录文件的元数据(文件名、权限等),而数据块的实际位置信息则会被存储在NameNode的元数据中。这样,用户就可以通过HDFS路径访问文件,而Hadoop会负责管理文件的分布式存储和复制。通过Java API上传原理: 使用Java API时,用户通过Java代码创建一个Hadoop的
FileSystem
对象,然后使用该对象调用copyFromLocalFile
等方法将本地文件上传到HDFS。在这个过程中,Hadoop API会与NameNode通信,获取文件元数据,然后将数据块传输到合适的DataNode上,并在NameNode上更新文件的元数据。
可以得出如下所示的原理:
客户端向NameNode发起上传请求,NameNode返回对应的元数据信息,客户端拿着元数据信息将文件存储在对应的DataNode上
可以确认元数据已经存了,但是数据没有真正存到Datanode上。
# 8.现在可以确定是客户端与Docker容器之间的通信的问题了
客户端与Datanode进行(通讯)的端口是50010,我这里并没有对Datanode的50010端口做映射。所以才会出现问题?
# 9.验证端口映射
对datanode的50010端口做映射行不通,在主机上的映射端口只能有一个50010。通过映射的方法行不通。
再次查看错误,突然发现我的客户端(程序)请求的ip不是本机的ip而是处于docker network下的datanode的ip!!所以做端口映射是行不通的。
# 3.总结问题
通过对于HDFS上传原理的分析,得出问题主要是在于客户端无法与datanode建立网络连接导致
# 4.解决方案
将后端程序也放入Docker容器中进行运行,处于同一个Docker network下,后端在主机上做端口映射提供服务的端口暴露出来。
成功解决问题,和分析的一样。