美文网首页
hdfs部署笔记

hdfs部署笔记

作者: 异同 | 来源:发表于2020-03-20 16:56 被阅读0次

    hadoop的单机部署没太大的难度,跟着官方指南一路走下来就行了。
    基本操作流程就是

    • 下载hadoop安装包并解压缩
    • 在配置文件etc/hadoop/hadoop-env.sh中修改JAVA-JDK的安装路径
    • 在配件文件etc/hadoop/core-site.xml中加入主机地址信息
    • 在etc/hadoop/hdfs-site.xml中加入副本数量信息(由于是单机所以暂时配置为1),加入"hadoop.tmp.dir"文件保存位置(因为hadoop的文件默认是保存在linux的tmp目录下,这个目录每次重启电脑都会自动清理,因此需要手动指定一个其他的位置)
    • 在配置文件etc/hadoop/slaves中修改主机地址信息
    • 在环境变量~/.bash_profile中添加hadoop运行脚本的路径:
      /hadoop安装路径/hadoop-x.x.x/sbin

    随后进行hdfs格式化工作:hdfs namenode -format
    启动hdfs:start-dfs.sh

    具体的配置代码就不附上来了,下面只讲一下自己遇到的一些问题,以及最后解决的方法。


    DataNode启动失败

    在配置好后,通过start-dfs.sh启动hdfs,使用jps查看运行情况。正常状态下应当是存在NameNode、DataNode、SecondaryNameNode三个运行进程的。但是有时会出现只有NN和SNN,DataNode并没有成功启动。
    这可能是由于多次使用了hdfs namenode -format格式化操作,而你并没有对tmp文件夹做清理,产生了冲突导致dd进程起不来。
    解决办法就是清理tmp,重新启动hdfs:

    1. 关闭hdfs进程
      stop-dfs.shstop-all.sh
    2. 删除tmp文件夹下的内容
      rm -r ./tmp/dfs/
      或cd到tmp文件夹下通过rm -r dfs进行删除
    3. 格式化hdfs hdfs namenode -format
    4. 启动dfs start-dfs.sh

    connect refused

    当hdfs启动完成后,在主机上使用hadoop dfs -command进行文件系统操作成功,但是当使用api进行处理时,发生了连接失败的错误。

    public class HDFSApp {
       public static void main(String[] args) throws Exception {
          URI uri = new URI("hdfs://xxx.xxx.xxx.xxx:9000");
          String user = "xxxxxx";
          Configuration configuration = new Configuration();
          FileSystem fs = FileSystem.get(uri, configuration, user);
    
          System.out.println(fs.mkdirs(new Path("/test-api")));
       }
    }
    
    预排查

    首先看一下域名解析(如果有的话)、ip地址、端口、用户名这些有没有错误,没有则继续进行排查处理。

    host排查

    最开始发生连接拒绝的时候,最开始找到的答案告诉我们可能是host的问题,因为课程上面为了方便,在host中使用某些字符串表示了ip地址,如果自己没有对host进行修改,而依然是跟着教程使用的hadoop000等作为配置文件中的域名信息(如core-site.xml中fs.defaultFS配置为hdfs://hadoop000:9000),那么会因为无法正确解析hadoop000而产生连接失败。
    解决方法:
    在/etc/hosts中修改host内容,添加自己的ip地址,如xxx.xxx.xxx.xxx hadoop000

    端口使用排查

    但是我的配置基本上全是默认配置,不会存在host解析的问题。因此继续查找资料,发现有可能是存在端口没有放通这一情况。
    使用jps查看hfds的进程信息,记一下进程id:


    截屏2020-03-2015.31.14.png

    使用netstat -ntpla查看端口信息


    截屏2020-03-2015.32.33.png

    可以看到PID为5277的NameNode进程、PID为5561的SecNameNode进程、PID为5400的DataNode进程他们所对应的端口信息,均为127.0.0.1:xxxx,例如上图中NameNode进程对应的端口信息为127.0.0.1:9000,这说明9000端口是在本地机器上才能使用的,外网是无法访问到9000端口的。

    127.0.0.1和0.0.0.0:
    127.0.0.1是回送地址,指本地机,一般用来测试使用。而0.0.0.0是一个缺省地址,表示所有的ip地址。
    所以在netstat中也可以根据某个端口配置的地址是否为0.0.0.0来判断是否对外开放这个端口。例如某个进程使用的是0.0.0.0:8089,表示他将在所有ip地址上对8089端口进行监听。而如果使用的是127.0.0.1:8089,则表示这个进程只对本地网络的8089端口进行监听,当使用外网访问时会出现拒绝访问或访问失败的问题。

    那简单嘛,9000端口没有开放很可能就是网络防火墙拒绝了9000端口的服务。

    网络防火墙排查

    既然有可能是防火墙的问题,那么就把他关掉就好了,或者直接添加端口规则也可以。

    iptables

    添加规则iptables -A INPUT -p tcp --dport 9000 -j ACCEPT
    重启iptables systemctl restart iptables
    我这里直接报错了,经过查看发现我用的是centos7,这个版本使用的防火墙已经改成了firewalld,而不再使用iptables。

    firewalld

    先查看一下防火墙是否开启(之前就没提前看看iptables状态,结果还是浪费了时间):systemctl status firewalldfirewall-cmd --state,发现是关闭着的。

    截屏2020-03-2015.53.06.png
    这没道理啊,我防火墙没有开,但是端口却被限制了。不顾那么多,先配置防火墙看看是否有效吧:
    启动防火墙 systemctl start firewalld
    添加防火墙端口规则 firewall-cmd --zone=public --add-port=9000/tcp --permanent
    重新加载防火墙规则 firewall-cmd --reload
    查看当前配置的防火墙规则 firewall-cmd --zone=public --query-protocol=tcp
    确认配置完毕,再次使用 netstat -ntpla 查看,端口状态信息,发现依旧是没有开放9000端口。
    网上搜索相关问题

    防火墙没开启但是我的端口却被禁用了,这不科学,于是去网上找了一大堆的资料。
    千万不要在百度搜索相关问题!我最开始在百度搜索,所有人都是告诉我“你防火墙有问题,你自己看看防火墙有没有配置好。”然而事实上我系统上防火墙关闭了,vps厂商也没有其他附加的防火墙。
    直到后来我在一个社区网站找到了这句话"firewall is just that, an ACL letting traffic through.If netstat says there is nothing listening on the port that means either the application that consumes the port is not running or it is bound to a different port.",意思是说防火墙只是一个对流量包进行过滤的工具,端口的监听和绑定关键还是要看你程序是怎么写的。

    配置文件

    道理很简单了,linux系统默认监听所有端口,而开启防火墙则会对流量进行过滤,也就是达到了端口限制的功能。
    而另一方面,程序自身也决定了端口的相关信息。如果程序不配置端口的监听信息,那么虽然这个端口是开放的,但是没有相关的进程去对端口的访问进行回应,此时依旧会出现连接失败的问题。
    也就是说即使我的端口是没有任何限制的,但是如果没有任何一个进程进行该端口的监听和处理,那么你对我端口的访问我依旧会认为是非法连接。
    例如我的hdfs程序配置对127.0.0.1:9000进行了监听,那么就只开放了127.0.0.1网络上的9000端口,你通过外网地址进行9000端口访问就是非法的,因此会被拒绝访问。

    那么问题的答案就出来了:hdfs程序的配置文件中,配置的是对localhost/127.0.0.1网络进行监听,即对127.0.0.1:9000进行监听
    解决办法:
    停止dfs服务 stop-dfs.shstop-all.sh
    修改配置文件etc/hadoop/core-site.xml:

    <configuration>
            <property>
                    <name>fs.defaultFS</name>
                   <value>hdfs://0.0.0.0:9000</value>
                  这里改成0.0.0.0或者是真实的ip地址都可以
            </property>
    </configuration>
    

    修改etc/slaves文件:

    0.0.0.0
    这里改成0.0.0.0或者是真实的ip地址都可以
    

    需要注意的是一定不要忘了修改slaves文件,如果只修改了core-site,此时DataNode可以启动,但是通过netstat可以看到DataNode的监听端口为127.0.0.1:xxxx,同时在web端的页面(http://xxxxxxxxxx:50070)也会连接失败。

    配置修改完毕后,重新运行dfs:start-dfs.sh
    查看端口信息:netstat -ntpla(图中使用的是配置真实ip地址的方法。如果配置的是0.0.0.0,此时则会显示0.0.0.0:9000)

    截屏2020-03-2016.45.59.png
    使用api上传一份本地文件到hdfs中:
    public class HDFSApp {
       public static void main(String[] args) throws Exception {
          URI uri = new URI("hdfs://xxxxxxxxx:9000");
          String user = "xxxxxxx";
          Configuration configuration = new Configuration();
          FileSystem fs = FileSystem.get(uri, configuration, user);
    
          Boolean b = fs.mkdirs(new Path("/test-api"));
          fs.copyFromLocalFile(new Path("/Users/michealki/nohup.out"),new Path("/test-api/test-nohup.out"));
       }
    }
    

    打开hdfs的web页面,在Utilities中选择Browse Directory,进入到上传的目录"/test-api"中,可以看到数据已经上传成功


    截屏2020-03-2016.54.25.png

    集群部署DN监控失败

    一开始我的集群配置基本过程如下:
    1. 在core-site.xml配置好nn的地址(hdfs://xxxx:9000)
    2. 在hdfs-site.xml中配置好副本数量、自定义临时文件存放路径、namenode数据存放路径、datanode数据存放路径
    3. 在yarn-site.xml中配置好nodemanager的数据存放位置、resourcemanager的域名地址、将yarn.nodemanager.aux-services设置为mapreduce_shuffle
    4. 在mapred-site.xml中将mapreduce.framework.name配置为yarn,表示mr任务将会在yarn集群上执行。(默认为local,即在本地执行mr任务)
    5. 在hadoop-env中配置好java的环境变量
    6. 在slaves中添加slave节点的域名(由于机器数量有限,我将master机器同时也用作slave机器了)
    7. 启动集群start-all.sh

    由于我是通过域名连接而不是ip连接,我的域名提供商本身就提供了dns服务,所以开始的时候我就没有去配置host。因为考虑到host也是做个域名解析而已,我已经有了解析服务了就不需要修改host了

    debug

    在启动之后,最开始出现的问题是namenode页面(http://xxxx:50070/dfshealth.html#tab-overview)中只能看到一个DataNode节点。而通过jps命令在各台机器上都能看到datanode是开启的。

    尝试1

    查询资料得知由于我其他机器上的hadoop软件是从master机器拷贝过去的,配置文件基本上一样。而DataNode的文件存放路径配置的也是一样的,因此会导致master无法区分各个DataNode。所以就产生了 页面上无法正常显示其他DataNode的问题。
    方法:
    修改hdfs-site.xml中dfs.datanode.data.dir的路径,让各个集群的DataNode存放路径有所区分
    效果:
    修改后依旧是无法在50070页面看到其他的DataNode。而且后续查看了多篇文章,这种方法只适用于一些特殊情况。在某些状况下,各个节点的datanodeUuid会出现一样的情况,NN监控和管理的依据就是这个uuid,可以在/xxxx/tmp/dfs/data/current中VERSION文件中查看到当前机器DataNode的uuid情况。我的机器上各个uuid都是不一样的,而且我也好奇几台机器之间数据交互肯定都是"域名加文件路径",怎么会存在因为DN路径配置的一样就无法正常监控的问题呢?所以说这种解释和处理方式在我这里是没有效果的。

    尝试2

    既然是节点问题,那NN上的日志肯定是有相关记录的。查看NN的日志文件,拉倒最下面看到了一个出错记录
    hadoop-namenode-0.myhadoopcluster/10.100.81.42:8020 Datanode denied communication with namenode because hostname cannot be resolved (ip=xx.xx.xx.xx, hostname=xx.xx.xx.xx)
    好像大致的意思是获取不到hostname。猜想,内部大致存在这么一个检查机制:hadoop的slaves配置文件中配置了集群其他机器的域名或hostname,无论是域名还是自己配置的hostname总会对应一个ip地址,因此NN就可以根据这个ip地址通过ssh的方式连接到其他机器上。连接后会对ip做一个反解析,与连接时的hostname或域名进行匹配判断,如果不一致就拒绝访问。

    例如:
    我的各个机器都是有单独域名的,通过域名运营商提供的解析服务来解析到具体的ip地址。而我各个机器上/etc/host与/etc/hostname都是默认配置,即host文件内容:127.0.0.1 localhost,hostname文件内容:localhost。此时NameNode通过域名连接到各台slave时,通过域名运营商得到了ip,因此可以正常建立连接,但是由于host和hostname都是默认配置,此时反解析ip时无法在host中找到对应的hostname,此时可能就以ip地址或域名作为了hostname,而机器上的hostname是localhost,这时就出现了不一致的情况,产生Datanode denied communication错误。

    解决方法1:
    直接在hdfs-site.xml中配置

            <property>
                      <name>dfs.namenode.datanode.registration.ip-hostname-check</name>                   
                      <value>false</value>
            </property>
    

    即不对hostname进行一致性检查,允许直接通过ip进行连接。
    解决方法2:
    配置好host和localhost
    连接流程大致是:a机器在slaves文件中找到要连接的hostname或域名,通过/etc/host文件或运营商的域名解析服务得到ip地址,连接到指定的机器上,将hostname与连接机器上的/etc/hostname中的名称进行一致性检查,如果一致则建立连接,否则拒绝连接。

    /etc/host文件一般是做自定义域名解析用的。基本格式是每一条记录一行,每行可以有三段内容,用tab或空格区分开,第一段是ip地址,第二段是域名或hostname,第三段是别名
    /etc/hostname文件是用于指定当前机器名称的,只有一行,内容是什么就代表当前机器叫什么,或者说当前机器的hostname是什么。例如如果配置的是hadoop0123,那么如果以a用户连接到这台机器,那么连接符号就会变成a@hadoop0123,a表示用户名,hadoop0123表示机器名。

    根据以上逻辑,我们在各台机器上的/etc/host文件中将其他机器的ip hostname添加进去,并检查各个机器的/etc/hostname文件是否和host文件是对应的。因为修改过hostname文件,因此我们需要重启服务器”shutdown -s -t now“才能使配置生效

    例如:
    集群有三台机器abc,ip地址分别为1.1.1.1,2.2.2.2,3.3.3.3。
    首先在各个机器上做host和hostname配置,a机器配置host为"1.1.1.1 a 换行 2.2.2.2 b 换行 3.3.3.3 c",a机器的hostname文件修改内容为"a",同理bc机器做相同的操作,他们各自的hostname文件内容分别修改为"b"和"c"。
    我们令a做master,因此需要再各个机器的core-site.xml中配置好NameNode地址:hdfs://a:9000(或hdfs://1.1.1.1:9000)。abc作为DataNode,在slave文件中添加"a 换行 b 换行 c"
    在yarn-site.xml中添加yarn.resourcemanager.hostname并配置为a(或1.1.1.1)

    配置完成以后最好进行全面的初始化再启动集群:

    1. 删除自定义的临时文件目录
    2. 创建自定义临时文件目录
    3. hdfs namenode -format
    4. start-all.sh
    5. 登录页面查看节点信息:
      http://xxxx:8088/cluster/cluster
      http://xxxx:50070/dfshealth.html#tab-overview

    reference:
    community.cloudera.com
    www.javaear.com
    www.itread01.com
    blog-yxs1112003

    相关文章

      网友评论

          本文标题:hdfs部署笔记

          本文链接:https://www.haomeiwen.com/subject/wkyjyhtx.html