docker部署hadoop集群

打印 上一主题 下一主题

主题 847|帖子 847|积分 2541

下载资源

java华为镜像下载地址:Index of java-local/jdk (huaweicloud.com)
hadoop历史版本下载:Index of /dist/hadoop/common (apache.org)
构建镜像

编写Dockerfile文件:
  1. FROM centos:centos7
  2. # 配置resove.conf解决软件包获取不到的问题
  3. RUN curl -O http://mirrors.aliyun.com/repo/Centos-7.repo
  4. RUN mv -f Centos-7.repo /etc/yum.repos.d/CentOS-Base.repo
  5. RUN yum makecache
  6. # 安装openssh-server和sudo软件包,并且将sshd的UsePAM参数设置成no  
  7. RUN yum install -y openssh-server sudo
  8. RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
  9. #安装openssh-clients
  10. RUN yum install -y openssh-clients
  11. # 添加测试用户root,密码3238,并且将此用户添加到sudoers里  
  12. RUN echo "root:3238" | chpasswd
  13. RUN echo "root   ALL=(ALL)       ALL" >> /etc/sudoers
  14. RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
  15. RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
  16. # 启动sshd服务并且暴露22端口  
  17. RUN mkdir /var/run/sshd
  18. EXPOSE 22
  19. CMD ["/usr/sbin/sshd", "-D"]
  20. ADD jdk-8u202-linux-x64.tar.gz /usr/local
  21. RUN mv /usr/local/jdk1.8.0_202 /usr/local/jdk1.8
  22. ENV JAVA_HOME /usr/local/jdk1.8
  23. ENV PATH $JAVA_HOME/bin:$PATH
  24. ADD hadoop-3.1.3.tar.gz /usr/local
  25. RUN mv /usr/local/hadoop-3.1.3 /usr/local/hadoop
  26. ENV HADOOP_HOME /usr/local/hadoop
  27. ENV PATH $HADOOP_HOME/bin:$PATH
复制代码
构建镜像:
  1. docker build -t hadoop .
复制代码
  注:
  

  • 低版本docker会出现使用mv下令时报错:can’t remove : Directory not empty,可以先用COPY下令而不用ADD下令将压缩包复制到容器内,然后本身背面到容器内去解压。
  • 该Dockerfile文件构建出来的镜像体积有些痴肥,可以拉取我优化过体积的镜像,也可以参考文章 减小docker镜像体积的方法-CSDN博客 修改Dockerfile文件来优化体积。
  假如觉得这些操作太麻烦了,想要更省事点,我还提供了已经构建好的两个不同版本的镜像。(你就说我够不敷贴心吧)


  • 由Dockerfile文件构建出来的初始版本:docker pull biluoer/hadoop:3.1.3-base
  • 已经把文章里所有内容都设置好的完全版:
    1. docker pull biluoer/hadoop:3.1.3
    2. # 给拉取过来的镜像创建个新的tag
    3. docker tag biluoer/hadoop:3.1.3 hadoop
    4. # 然后删除旧tag
    5. docker rmi biluoer/hadoop:3.1.3
    6. # 运行三台容器后,进入hadoop2,就可以一键运行了
    7. docker exec -it hadoop2 bash
    8. # 一键运行,回车走你
    9. my-hadoop start
    复制代码
    注:若拉取失败,可参考文章 docker的安装和常用下令-CSDN博客 的设置镜像源部分。
启动容器

  1. # 创建桥接网络,bridge是默认驱动,可以不加
  2. docker network create [--driver bridge] hadoop-net
  3. #创建桥接网络,并指定子网配置,范围:192.168.1.1-192.168.1.254
  4. docker network create --subnet=192.168.1.0/24 hadoop-net
  5. # 启动三台(一主二从)并指定网络,文件下载端口9864、DataNode客户端访问端口9866
  6. # hadoop2,开放nn-web端口9870、历史服务器web端口19888,NameNode客户端连接端口8020
  7. docker run -itd --hostname hadoop2 --name hadoop2 --net hadoop-net --ip 192.168.1.2 -p 9870:9870 -p 9864:9864 -p 19888:19888 -p 8020:8020 -p 9866:9866 hadoop
  8. # hadoop3,开放yarn-web端口8088
  9. docker run -itd --hostname hadoop3 --name hadoop3 --net hadoop-net --ip 192.168.1.3 -p 8088:8088 hadoop
  10. # hadoop4,开放2nn-web端口9868(根据hdfs-site.xml配置,非必须)
  11. docker run -itd --hostname hadoop4 --name hadoop4 --net hadoop-net --ip 192.168.1.4 -p 9868:9868 hadoop
复制代码
注:假如某些功能用不到,就不需要开发相关的端口。
搭建集群

设置ssh免密

起首对主hadoop2设置:
   可以先用ping下令测试下连通性:ping hadoop2
  假如没有ping通,在/etc/hosts文件里加上:
  1. 192.168.1.2     hadoop2
  2. 192.168.1.3     hadoop3
  3. 192.168.1.4     hadoop4
复制代码
  1. docker exec -it hadoop0 bash
  2. #生成秘钥对
  3. ssh-keygen
  4. #剩下的一路回车即可
  5. #分发公钥到其他主机,让hadoop2可以免密登录hadoop2、3、4
  6. ssh-copy-id hadoop2
  7. ssh-copy-id hadoop3
  8. ssh-copy-id hadoop4
  9. #同样的方法,让hadoop3、Hadoop4可以免密登录另外2台主机,其中hadoop4可配可不配,但hadoop2和hadoop3一定要配置
复制代码
节点职责安排

各节点的职责可通过设置文件自定义;NN、2NN、RM在不同服务器上可以减少资源争用、减小单点故障风险,方便扩展和维护。
hadoop2hadoop3hadoop4HDFSNameNode、DataNodeDataNodeSecondaryNameNode、DataNodeYARNNodeManagerResourceManager、NodeManagerNodeManager 修改设置文件

进入/usr/local/hadoop/etc/hadoop目次,涉及的设置文件有:hadoop-env.sh、core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml、works(2.x叫slaves)。
默认设置文件位置:
默认设置文件地点位置core-default.xmlhadoop-common-3.1.3.jar/core-defaultxmlhdfs-default.xmlhadoop-hdfs-3.1.3.jar/hdfs-defaultxmlyarn-default.xmlhadoop-yarn-common-3.1.3.jar/yarn-defaultxmlmapred-default.xmlhadoop-mapreduce-client-core-3.1.3.jar/mapred-defaultxml 注:以下操作都是是hadoop2上,设置文件中的其他设置都是可加可不加的,而且除其他设置外的设置大多都有默认值,不是必须要加的,默认值可以通过查看默认设置文件来获取。


  • hadoop-env.sh(末端加上,必须)
  1. export JAVA_HOME=/usr/local/jdk1.8
复制代码


  • core-site.xml
  1. <configuration>
  2.     <!--指定NameNode的地址-->
  3.     <property>
  4.         <name>fs.defaultFS</name>
  5.         <value>hdfs://hadoop2:8020</value>
  6.     </property>
  7.     <!--指定hadoop数据的存储目录-->
  8.     <property>
  9.         <name>hadoop.tmp.dir</name>
  10.         <value>/usr/local/hadoop/data</value>
  11.     </property>
  12.     <!--配置HDFS网页登录使用的静态用户为root,用什么用户启动的集群,就配置什么用户,不然网页上进行删除文件等操作会没有权限-->
  13.     <property>
  14.         <name>hadoop.http.staticuser.user</name>
  15.         <value>root</value>
  16.     </property>
  17.    
  18.     <!--其他配置-->
  19.     <!--
  20. 配置垃圾桶(Trash)的清理时间间隔(以分钟为单位),默认值0,表示禁用垃圾桶功能
  21. (垃圾桶是一个用于存储被删除文件或目录的临时区域)
  22. -->
  23.     <property>
  24.         <name>fs.trash.interval</name>
  25.         <value>1440</value>
  26.     </property>
  27. </configuration>
复制代码


  • hdfs-site.xml
  1. <configuration>
  2.     <!--nn-web端访问地址-->
  3.     <property>
  4.         <name>dfs.namenode.http-address</name>
  5.         <value>hadoop2:9870</value>
  6.     </property>
  7.     <!--2nn-web端访问地址-->
  8.     <property>
  9.         <name>dfs.namenode.secondary.http-address</name>
  10.         <value>hadoop4:9868</value>
  11.     </property>
  12.    
  13.     <!--其他配置-->
  14.     <!--设置HDFS中文件的副本数,默认值3-->
  15.     <property>
  16.         <name>dfs.replication</name>
  17.         <value>1</value>
  18.     </property>
  19.     <!--是否启用文件/目录的权限检查,false任何用户可读写,默认值true-->
  20.     <property>
  21.         <name>dfs.permissions</name>
  22.         <value>false</value>
  23.     </property>
  24. </configuration>
复制代码


  • yarn-site.xml
  1. <configuration>
  2.     <!--指定YARN-NodeManager需要运行的辅助服务-->
  3.     <property>
  4.         <name>yarn.nodemanager.aux-services</name>
  5.         <value>mapreduce_shuffle</value>
  6.     </property>
  7.     <!--指定ResourceManager的地址-->
  8.     <property>
  9.         <name>yarn.resourcemanager.hostname</name>
  10.         <value>hadoop3</value>
  11.     </property>
  12.     <!-- 环境变量的继承,3.1的bug,缺少HADOOP_MAPRED_HOME,3.2后就不需要此配置了-->
  13.     <property>
  14.         <name>yarn.nodemanager.env-whitelist</name>                <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME,PATH,LANG,TZ</value>
  15.     </property>
  16.     <!--其他配置-->
  17.     <!--启用YARN的日志聚合功能,把各个节点的日志收集到一起存放-->
  18.     <property>
  19.         <name>yarn.log-aggregation-enable</name>
  20.         <value>true</value>
  21.     </property>
  22.     <!--设置日志聚集服务器地址-->
  23.     <property>
  24.         <name>yarn.log.server.url</name>
  25.         <value>http://hadoop2:19888/jobhistory/logs</value>
  26.     </property>
  27.     <!-- 设置日志保留时间为7天-->
  28.     <property>
  29.         <name>yarn.log-aggregation.retain-seconds</name>
  30.         <value>604800</value>
  31.     </property>
  32. </configuration>
复制代码


  • mapred-site.xml
  1. <configuration>
  2.     <!-- 指定MapReduce程序运行在Yarn上 -->
  3.     <property>
  4.         <name>mapreduce.framework.name</name>
  5.         <value>yarn</value>
  6.     </property>
  7.     <!--其他配置-->
  8.     <!--历史服务器端地址-->
  9.     <property>
  10.         <name>mapreduce.jobhistory.address</name>
  11.         <value>hadoop102:10020</value>
  12.     </property>
  13.     <!--历史服务器web端地址-->
  14.     <property>
  15.         <name>mapreduce.jobhistory.webapp.address</name>
  16.         <value>hadoop102:19888</value>
  17.     </property>
  18. </configuration>
复制代码
设置完成上述内容后,可以使用rsync进行设置文件的从hadoop2分发到其余容器。
   rsync是一个同步工具,只会同步发生了变更的文件。
  为了实现一次性分发,可以写一个脚本实现:xsync
  1. #!/bin/bash
  2. #1. 判断参数个数
  3. if [ $# -lt 1 ]
  4. then
  5.         echo Not Enough Arguement!
  6.         exit;
  7. fi
  8. #2. 遍历集群所有机器
  9. for host in hadoop2 hadoop3 hadoop4
  10. do
  11.         echo ==================== $host ====================
  12.         #3. 遍历所有目录,挨个发送
  13.         for file in $@
  14.         do
  15.                 #4. 判断文件是否存在
  16.                 if [ -e $file ]
  17.                 then
  18.                         #5. 获取父目录
  19.          pdir=$(cd -P $(dirname $file); pwd)
  20.          #6. 获取当前文件的名称
  21.          fname=$(basename $file)
  22.          ssh $host "mkdir -p $pdir"
  23.          rsync -av $pdir/$fname $host:$pdir
  24.                 else
  25.              echo $file does not exists!
  26.                 fi
  27.         done
  28. done
复制代码
然后授权其执行权限和复制到/bin中,以便全局使用
  1. chmod +x xsync
  2. cp xsync /bin/
复制代码
  1. #安装(hadoop2、3、4都需要)
  2. yum -y install rsync
  3. #配置xsync脚本,并复制到/bin目录下
  4. #分发
  5. xsync /usr/local/hadoop/etc/hadoop/
  6. #也可以使用相对路径,需要当前路径为/usr/local/hadoop/etc/hadoop
  7. xsync ./
复制代码


  • 设置works文件:
  1. echo "hadoop2" > workers
  2. echo "hadoop3" >> workers
  3. echo "hadoop4" >> workers
  4. xsync workers
复制代码
启动集群

   留意:格式 化 NameNode,会产生新的集群 id,导致 NameNode 和 DataNode 的集群 id 不划一,集群找不到已往数据。假如集群在运行过程中报错,需要重新格式化 NameNode 的话,肯定要先制止namenode 和 datanode 进程,而且要删除所有呆板的 data 和 logs 目次,然后再进行格式化。
  

  • 启动 HDFS(hadoop2上)
  1. #第一次启动,需要格式化NameNode,成功后会在hadoop根目录下生成data目录
  2. hdfs namenode -format
  3. #启动hdfs
  4. /usr/local/hadoop/sbin/start-dfs.sh
  5. #如果报错找不到变量,在sbin/start-dfs.sh、stop-dfs.sh顶部加上以下内容:缺啥加啥
  6. HDFS_NAMENODE_USER=root
  7. HDFS_DATANODE_USER=root
  8. HDFS_SECONDARYNAMENODE_USER=root
  9. #启动成功后,使用jps命令可以在hadoop2上看到DataNode和NameNode,hadoop3上看到DataNode,hadoop4上看到DataNode和SecondaryNameNode
  10. jps
  11. #nn-web页面:192.168.30.3:9870,2nn-web页面:192.168.30.3:9868
  12. #停止hdfs
  13. /usr/local/hadoop/sbin/stop-dfs.sh
复制代码

  • 启动yarn(在设置了 ResourceManager 的节点上启动才行)
  1. #以下所有操作都在:hadoop3上
  2. /usr/local/hadoop/sbin/start-yarn.sh
  3. #如果报错找不到变量,在sbin/start-yarn.sh、stop-yarn.sh顶部加上以下内容:缺啥加啥
  4. YARN_RESOURCEMANAGER_USER=root
  5. YARN_NODEMANAGER_USER=root
  6. #如果报错Permission denied,则hadoop3也要配置对其他主机的免密登录
  7. #启动成功后,使用jps命令可以看到在hadoop2上多了NodeManager,hadoop3上多了ResourceManager和NodeManager,hadoop4上多了NodeManager
  8. #yarn页面:192.168.30.3:8088
  9. #停止yarn
  10. /usr/local/hadoop/sbin/stop-yarn.s
复制代码

  • 便捷启动和便捷检查:在/root/bin/下编写集群启听脚本和jps-all脚本
           最后授权和分发:
       
    1. chmod +x my-hadoop
    2. chmod +x jps-all
    3. #临时将/root/bin目录添加到PATH中
    4. export PATH=$PATH:/root/bin
    5. xsync /root/bin/
    6. # 使用my-hadoop和jps-all
    7. my-hadoop start/stop
    8. jps-all
    复制代码

    • my-hadoop.
    1. #!/bin/bash
    2. if [ $# -lt 1 ]
    3. then
    4.         echo "No Args Input..."
    5.         exit ;
    6. fi
    7. #也可以直接使用 HADOOP_HOME,而不需要新定义一个变量
    8. hadoop_home=/usr/local/hadoop
    9. case $1 in
    10. "start")
    11.         echo "==================== 启动 hadoop 集群 ==================="
    12.         echo " --------------- 启动 hdfs ---------------"
    13.         ssh hadoop2 "$hadoop_home/sbin/start-dfs.sh"
    14.         echo "---------------- 启动 yarn ---------------"
    15.         ssh hadoop3 "$hadoop_home/sbin/start-yarn.sh"
    16.         echo "---------------- 启动 historyserver ---------------"
    17.         ssh hadoop2 "$hadoop_home/bin/mapred --daemon start historyserver"
    18. ;;
    19. "stop")
    20.         echo "==================== 关闭 hadoop 集群 ==================="
    21.         echo "---------------- 关闭 historyserver ---------------"
    22.         ssh hadoop2 "$hadoop_home/bin/mapred --daemon stop historyserver"
    23.         echo "---------------- 关闭 yarn ---------------"
    24.         ssh hadoop3 "$hadoop_home/sbin/stop-yarn.sh"
    25.         echo "---------------- 关闭 hdfs ---------------"
    26.         ssh hadoop2 "$hadoop_home/sbin/stop-dfs.sh"
    27. ;;
    28. *)
    29.         echo "Input Args Error..."
    30. ;;
    31. esac
    复制代码
      

    • jps-all
    1. #!/bin/bash
    2. for host in hadoop2 hadoop3 hadoop4
    3. do
    4.         echo =============== $host ===============
    5.         ssh $host "/usr/local/jdk1.8/bin/jps"
    6. done
    复制代码

测试

上传

文件生存位置为:/usr/local/hadoop/data/dfs/data/current/
  1. #创建文件夹(fs-FileSystem),是否成功可以访问9870,去查看菜单Utilities下的“Browse the file system”页面
  2. hadoop fs -mkdir /input
  3. #上传文件,上传成功后可以到页面上去预览和下载
  4. hadoop fs -put /bin/xsync /input
复制代码
下载

  1. #方式1:在浏览器页面下载
  2. #方式2:通过get命令下载(到当前路径)
  3. hadoop fs -get /input/xsync
复制代码
发现欣赏器方式预览和下载文件会失败,是因为没有设置hostname和ip的对应关系,需要设置。(留意容器肯定开放了端口:9864)
打开C:\Windows\System32\drivers\etc\hosts,加上以下内容:
  1. 192.168.30.3 hadoop2
  2. 192.168.30.3 hadoop3
  3. 192.168.30.3 hadoop4
  4. #为了方便访问,还可以加上这个
  5. 192.168.30.3 hadoop
复制代码
执行wordcount步伐

留意:集群模式下,输入路径和输出路径需要都是HDFS的路径。
  1. #统计input目录下所有文件的单词种类和对应的数量
  2. hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount /input /output
  3. #访问ip:8088可以看到程序的执行情况,程序执行完成后访问ip:9870的文件系统,执行结果在output目录下的文件中
复制代码
增补

设置历史服务器

在yarn的web网页上,点击具体步伐的history,发现页面打开失败。为了查看步伐的历史执行情况,就需要设置历史服务器。

  • 在mapred-site.xml中加上如下的设置:
  1. <!--历史服务器端地址-->
  2. <property>
  3.     <name>mapreduce.jobhistory.address</name>
  4.     <value>hadoop102:10020</value>
  5. </property>
  6. <!--历史服务器web端地址-->
  7. <property>
  8.     <name>mapreduce.jobhistory.webapp.address</name>
  9.     <value>hadoop102:19888</value>
  10. </property>
复制代码

  • 分发设置和启动,启动后用jsp检查启动是否成功
  1. xsync etc/hadoop/
  2. /usr/local/hadoop/bin/mapred --daemon start historyserver
  3. jps
  4. #停止历史服务器进程
  5. /usr/local/hadoop/bin/mapred --daemon stop historyserver
复制代码
日记聚集

日记聚集概念:应用运行完成以后,将步伐运行日记信息上传到 HDFS 系统上。这样可以方便的查看到步伐运行详情,方便开发调试。
留意:开启日记聚集功能,需要重新启动 NodeManager 、ResourceManager 和 HistoryServer。

  • 修改yarn-site.xml,加上以下设置:
  1. <!-- 开启日志聚集功能 -->
  2. <property>
  3.     <name>yarn.log-aggregation-enable</name>
  4.     <value>true</value>
  5. </property>
  6. <!-- 设置日志聚集服务器地址 -->
  7. <property>
  8.     <name>yarn.log.server.url</name>
  9.     <value>http://hadoop2:19888/jobhistory/logs</value>
  10. </property>
  11. <!-- 设置日志保留时间为 7 天 -->
  12. <property>
  13.     <name>yarn.log-aggregation.retain-seconds</name>
  14.     <value>604800</value>
  15. </property>
复制代码

  • 分发设置和启动
  1. xsync $HADOOP_HOME/ect/hadoop/
  2. # hadoop2上输入以下命令停止HistoryServer
  3. $HADOOP_HOME/bin/mapred --daemon stop historyserver
  4. # hadoop3上输入以下命令停止NM、RM,然后启动
  5. $HADOOP_HOME/sbin/stop-yarn.sh
  6. $HADOOP_HOME/sbin/start-yarn.sh
  7. # hadoop2上
  8. $HADOOP_HOME/bin/mapred --daemon start historyserver
复制代码
单节点启动

  1. #分别启动/停止 HDFS 组件
  2. hdfs --daemon start/stop namenode/datanode/secondarynamenode
  3. # 启动/停止 YARN
  4. yarn --daemon start/stop resourcemanager/nodemanager
复制代码
Java客户端使用

HDFS

使用步骤如下:

  • 需要先下载hadoop3.1.0到本地,并用 cdarlint/winutils: winutils.exe hadoop.dll and hdfs.dll binaries for hadoop windows (github.com) 这内里对应版本的bin目次替换掉原来的bin目次
  • 然后创建环境变量HADOOP_HOME,值为之前下载并解压好的hadoop3.1.0的目次,并在环境变量path里加上%HADOOP_HOME%/bin
  • 双击hadoop的bin目次下的winutils.exe,假如黑窗口一闪而过就没问题
  • 创建一个maven项目,在pom文件里添如下的依赖:
  1. <dependencies>
  2.     <dependency>
  3.         <groupId>org.apache.hadoop</groupId>
  4.         <artifactId>hadoop-client</artifactId>
  5.         <version>3.1.3</version>
  6.     </dependency>
  7.     <dependency>
  8.         <groupId>junit</groupId>
  9.         <artifactId>junit</artifactId>
  10.         <version>4.13.2</version>
  11.         <scope>test</scope>
  12.     </dependency>
  13.     <dependency>
  14.         <groupId>org.slf4j</groupId>
  15.         <artifactId>slf4j-log4j12</artifactId>
  16.         <version>1.7.36</version>
  17.     </dependency>
  18. </dependencies>
复制代码

  • 在resources目次下创建log4j.properties文件,内容如下:
  1. log4j.rootLogger=INFO, stdout
  2. log4j.appender.stdout=org.apache.log4j.ConsoleAppender
  3. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
  4. log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
  5. log4j.appender.logfile=org.apache.log4j.FileAppender
  6. log4j.appender.logfile.File=target/spring.log
  7. log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
  8. log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
复制代码

  • 最后编写步伐步伐:
  1. public class HdfsClientTest {
  2.         private FileSystem fs;
  3.         @Before
  4.         public void init() throws Exception {
  5.                 // 客户端地址
  6.                 URI uri = new URI("hdfs://hadoop2:8020");
  7.                 // 配置
  8.                 Configuration config = new Configuration();
  9.         // 让NameNode返回的DataNode地址不用使用ip地址,而是使用主机名,解决上传/下载文件失败的问题
  10.                 // 注意前提是:
  11.                 //                 1.在hosts文件里配置了主机名和ip的映射
  12.                 //                2.主机开放了端口9866,通过“hadoop dfsadmin -report”可以查看DataNode的ip和端口
  13.                 config.set("dfs.client.use.datanode.hostname", "true");
  14.                 // 用户
  15.                 String user = "root";
  16.                 // 创建客户端
  17.                 fs = FileSystem.get(uri, config, user);
  18.         }
  19.        
  20.         public void close() throws IOException {
  21.                 fs.close();
  22.         }
  23.         @Test
  24.         public void testMkdir() throws Exception {
  25.                 fs.mkdirs(new Path("/test"));
  26.         }
  27.        
  28.         /**
  29.          * 参数优先级排序:客户端代码中设置的值 > ClassPath下的用户自定义配置文
  30.          * 件 > 服务器的自定义配置(xxx-site.xml)> 服务器的默认配置(xxx-default.xml)
  31.          */
  32.         @Test
  33.         public void testUpload() throws Exception {
  34.                 // 参数1:上传后是否删除源文件,参数2:是否允许覆盖,参数3:源文件路径,参数4:目标文件路径
  35.                 fs.copyFromLocalFile(false, true, new Path("D:\\Download\\hadoop\\input\\hello.txt"),        }
  36.         @Test
  37.         public void testDownload() throws Exception {
  38.                 // 参数1:是否删除源文件,参数2:源文件路径,参数3:目标文件路径, 参数4:是否开启文件的crc校验
  39.                 fs.copyToLocalFile(false, new Path("/README.md"),
  40.                                 new Path("D:\\Download\"), true);
  41.         }
  42.         @Test
  43.         public void testDelete() throws Exception {
  44.                 // 参数1:要删除的文件路径,参数2:是否递归删除
  45.                 fs.delete(new Path("/test"), true);
  46.         }
  47.         @Test
  48.         public void testRenameAndMove() throws IOException {
  49.                 // 重命名
  50.                 // fs.rename(new Path("/README.md"), new Path("/readme.md"));
  51.                 // 移动
  52.                 fs.rename(new Path("/readme.md"), new Path("/test/README.md"));
  53.         }
  54. }
复制代码
  按照上述步骤操作会发现创建文件夹没有问题,但上传文件会失败。缘故起因是上传文件时Java客户端会直接和DataNode打交道,而NameNode返回的DataNode信息是它的局域网ip和端口,所以Java客户端就没办法毗连上DataNode进行写文件了。办理方法如下:
  

  • 设置类加上设置:config.set("dfs.client.use.datanode.hostname", "true")
  • 通过hadoop dfsadmin -report查看DataNode的ip和端口,在C:\Windows\System32\drivers\etc\hosts设置好ip和主机名的映射和开放端口(默认是9866)。由于我们三个容器部署在一台服务器上,而且之前已经设置好了hostname和ip的映射关系,9866端口也开放了,所以这一步不需要做任何操作。
  增补:这里大概出现报错:Got error, status=ERROR, status message , ack with firstBadLink as 192.168.1.2:9866,这个报错时有时无;当有报错时,通过在网页端查看文件的副本信息可以发现:有两个副本上传成功,而另一个失败了。但成功的两个副本地点DataNode并不是固定的,我把日记级别设置为debug后研究了一番,但照旧没弄清缘故起因,等待有缘人提供办理方法。
  MapReduce

  1. import org.apache.hadoop.io.IntWritable;
  2. import org.apache.hadoop.io.LongWritable;
  3. import org.apache.hadoop.io.Text;
  4. import org.apache.hadoop.mapreduce.Mapper;
  5. import java.io.IOException;
  6. /**
  7. * KEYIN:mapper阶段输入数据的key的类型,LongWritable——偏移量
  8. * VALUEIN:mapper阶段输入数据的value的类型,Text——一行文本内容
  9. * KEYOUT:mapper阶段输出数据的key的类型,Text——单词
  10. * VALUEOUT:mapper阶段输出数据的value的类型,IntWritable——单词出现次数
  11. */
  12. public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
  13.         private final Text outK = new Text();
  14.         private final IntWritable outV = new IntWritable(1);
  15.         @Override
  16.         protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
  17.                 String[] words = value.toString().split(" ");
  18.                 for (String word : words) {
  19.                         outK.set(word);
  20.                         context.write(outK, outV);
  21.                 }
  22.         }
  23. }
  24. /**
  25. * KEYIN:reduce阶段输入的key的类型
  26. * VALUEIN:reduce阶段输入的value的类型
  27. * KEYOUT:reduce阶段输出的key的类型
  28. * VALUEOUT:reduce阶段输出的value的类型
  29. */
  30. public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
  31.         private final IntWritable outV = new IntWritable();
  32.         @Override
  33.         protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
  34.                 int sum = 0;
  35.                 for (IntWritable value : values) {
  36.                         sum += value.get();
  37.                 }
  38.                 outV.set(sum);
  39.                 context.write(key, outV);
  40.         }
  41. }
  42. public class WordCountDriver {
  43.         public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
  44.                 // 1 获取配置信息,或者job对象实例
  45.                 Configuration conf = new Configuration();
  46.                 Job job = Job.getInstance(conf);
  47.                 // 2 设置jar加载路径
  48.                 job.setJarByClass(WordCountDriver.class);
  49.                 // 3 设置map和reduce类
  50.                 job.setMapperClass(WordCountMapper.class);
  51.                 job.setReducerClass(WordCountReducer.class);
  52.                 // 4 设置map输出
  53.                 job.setMapOutputKeyClass(Text.class);
  54.                 job.setMapOutputValueClass(IntWritable.class);
  55.                 // 5 设置最终输出
  56.                 job.setOutputKeyClass(Text.class);
  57.                 job.setOutputValueClass(IntWritable.class);
  58.                 // 6 设置输入和输出路径
  59.                 // FileInputFormat.setInputPaths(job, new Path("D:\\Download\\hadoop\\input"));
  60.                 // FileOutputFormat.setOutputPath(job, new Path("D:\\Download\\hadoop\\output"));
  61.                 FileInputFormat.setInputPaths(job, new Path(args[0]));
  62.                 FileOutputFormat.setOutputPath(job, new Path(args[1]));
  63.                 // 7 提交job
  64.                 boolean result = job.waitForCompletion(true);
  65.                 System.out.println(result ? "job执行成功" : "job执行失败");
  66.         }
  67. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

渣渣兔

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表