hadoop学习

hadoop学习

学习内容地址:https://www.bilibili.com/video/av23858681?from=search&seid=15317487379960135161

1. Linux简介

1.1 定义

Linux是一套免费使用和自由传播的Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。

1.2 Linux的主要特点

基本思想
Linux的基本思想有两点:1. 一切都是文件;2. 每个软件都有确定的用途。
完全免费
完全兼容POSIX1.0标准
多用户和多任务
一般的界面
支持多种平台

2.3 一些说明

Linux是一个免费的像windows一样的操作系统
linux中几乎一起都是文件,文件几乎没有后缀区分
Linux中有且仅有一个超级用户
Linux一般作为服务器

3 虚拟机的使用

3.1 下载WMWare

WMWare下载地址:https://www.cr173.com/soft/68480.html
下载完毕直接进行安装。

安装步骤中需要密钥的时候在百度上搜索可以得到很多密钥:https://blog.csdn.net/QS_1024/article/details/78277030

3.2 虚拟机的创建

  1. 进入centos官网进行系统包的下载:http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1804.iso其中有个华为云的镜像,下载速度会比较快。
  2. 在WMware中创建一个空的虚拟机。主页中创建一个新的虚拟机,默认操作,在安装客户机操作系统的时候选择稍后安装系统,然后再一直默认下去就创建出了一个空的虚拟机,就像刚买来的电脑一样,只有一个壳没有具体的操作系统内容。这些内容在后续的设置中依然可以进行更改。

4. Linux

4.1 Linux的目录结构

这里写图片描述

这里写图片描述

常用目录作用
/Linux系统的根目录,一般用于存放目录
/etc系统级别的配置文件存放的目录,一般由配置管理员来使用
/home所有普通用户的家目录
/rootroot用户的根目录
/tmp存放应用程序产生的临时数据,不能在此目录存放重要数据
/var系统一般运行时需要改变的数据
/usr应用程序相关目录命令、函数库、共享包、内核源码

4.2 三种常用的网络连接模式

  1. 桥接方式,默认使用Vmnet0,直接连接物理网络,和windows物理主机同等级,连接外网容易
  2. nat方式:Vmnet8,网络地址转化模式,局域网和外网都容易连接
  3. host-only:仅主机模式,局域网简单

4.3 虚拟机网络配置

4.3.1 网络配置

我下载的是本文中给出来连接的系统,和老师讲解的系统存在一定的差异性。最大的差异就是我这里只有命令行的模式,所以这里的网络配置肯定不能照着老师来执行。

参考文章:https://www.cnblogs.com/xixihuang/p/5404517.html
这里我参考了上篇文章中命令模式的方法。

  1. 在终端中输入以下命令,查看安装在本机的网卡:nmcli d
  2. 切换到etc/sysconfig/network-scripts/目录下,打开自己网卡对应的文件:vi xxx
  3. 修改:BOOTPROTO=dhcp ONBOOT=yes
  4. 重启网络服务:systemctl restart network
  5. 测试外网:ping www.baidu.com

CentOS7 Failed to start LSB: Bring up/down解决方法
参考:http://www.mamicode.com/info-detail-2072502.html
解决办法:
停止NetworkManager服务
停止
[root@client01 network-scripts]# systemctl stop NetworkManager
取消开机启动
[root@client01 network-scripts]# systemctl disable NetworkManager
重启网络
[root@client01 network-scripts]# service network restart
Restarting network (via systemctl): [ OK ]

至此,问题解决

4.3.2 查看IP

第一次想查看本机ip的时候,输入ifconfig显示没有该命令,所以需要从网络中下载。为此上一个步骤成功联网后才能在这一步执行所需操作:yum -y install net-tools

4.2 常用命令

4.2.1 常用小命令
常用命令作用
man帮助命令
ctrl+R查找历史输入的命令
CTRL+z退出或者终止
单击tab补全
双击tab显示以输入字符开始的所有名称
q退出
vi编辑
cat将某个文档的内容显示出来
pwd查看当前目录
alias创建命令的临时别名
4.2.3 系统级别的命令
系统级别命令作用
ifconfig查看ip等
uname查看系统信息
ps -ef查看系统的进程
top系统进程和运行情况
grep过滤
reboot重启启动Liux操作系统
shutdown关闭Linux操作系统
kill杀死一个进程
4.2.4 磁盘的操作
磁盘操作命令作用
df -h显示磁盘的分区信息
fdisk -l详细磁盘分区信息
du -h -s查看目录的使用大小
mount -t挂载
umount卸载
fsck修复磁盘

Linux磁盘格式:ext4、ext3、ext2、vfat(fat32)

4.2.5 用户和组的操作
  1. 一些概念
账户uid
超级账户0
普通账户>=500
系统账户1~499
/etc/passwd保存账户的信息
/etc/shadow保存账户的密码信息
/rootroot用户家目录
/home/xxx普通用户xxx家目录
  1. 添加和删除用户
函数用法
useradd创建用户,如果是第一次创建就会创建一个相同名称的组
-u指定uid
-d指定宿主目录
-s指定使用shell
-e指定用户过期时间
-g指定基本组
-G指定附加组
gpasswd -a openlab groupenlab将用户加入到指定组
gpasswd -d openlab groupenlab将用户从组中删除
echo “123456” | passwd --stdin feige不通过交互信息,直接修改用户密码
userdel删除用户不删除用户文件
userdel -r连主目录一起删除
id openlab显示用户信息
  1. 创建用户组
函数用法
groupadd单独创建一个组
groups manager查看用户在哪些组
useradd -G manager tom创建用户时附加到组
su -xxx切换当前用户为xxx
whoami显示当前登陆用户账户
cat查看文件信息
4.2.6 文件操作
  1. 创建文件和目录
函数用法
mkdir /tmp/test01创建空的文件夹
mkdir -p /data1/hadoop/ddfs/name创建递归文件夹
touch /tmp/test01/file.txt创建空文件
vi file.log创建空文件并进入编辑模式
echo"123" >>file.txt创建file.txt并输入字符串到该文件(如果存在一个>为重写,两个>>为追加)
echo “123”屏幕打印123
  1. 文件编辑
函数用法
vi进入文件编辑器。i进入编辑模式;esc退出编辑模式;
:w保存
:q退出
:wq保存并退出
:q!强制性退出
  1. 文件内容查看
函数用法
cat -n查看时显示行号
cat不显示行号
tail -n(默认10行)从后往前读取n行,有监控文档的用途
head -n(默认10行)从前往后读取n行,有监控文档的用途
More :百分比查看,不能回滚看
Less :能往回滚看
  1. 复制、剪切目录和文件
函数用法
cp /tmp/file.txt /opt将tmp目录下的file文件复制到opt目录下
cp -r /tmp/test01 /opt将temp目录下的test01目录复制到opt目录下
mv /tmp/file /opt将file文件或目录剪切到opt目录里面(也可以进行重命名的操作)
rename批量重名名
  1. 删除
函数用法
rm删除一个文件
rm -rf强制递归删除

####4.2.7 打包压缩、查找
10. 打包tar

参数用法
-z压缩
-c打包
-x解包
-f必须要
-C指定解包位置
-v输出信息
/usr/bin/zip
/usr/bin/unzip
/bin/gzip
/bin/gunzip
tar -zcvf ./test.tar ./test/将当前目录下的test文件夹打包成test.tat包
tar -zxvf ./test.tar将当前目录下的tar包进行解压
tar -zxvf ./test.tar -C /root/Desktop/将压缩包解压到root中的desktop目录
4.2.8 文件的查找
函数用法
which cmd查找cmd命令所在路径
whereis cmd查找cmd命令的安装路径
locate文件查找-效率很快(实质是查找数据库)
find -name xxx根据名称类型来进行查找
4.2.9命令的别名和特殊符号等
函数用法
alias cle=clear设置clear的别名为cle,但仅临时有效
进入vi ~/.bashrc,添加alias cle=“clear”文件中修改,永久有效,但仅针对当前用户
~当前目录
cd -退回到上一次的目录
cd …/退回到上一层目录
cd …/…退回到上上层目录
cd ./当前目录
4.2.10 Linux软件的在线安装管理
  1. 二进制程序包的安装
    安装程序包,配置环境变量
  2. RPM程序安装
    RPM类似于windows下的“添加/删除程序”但是功能强大。.rpm结尾
    一个rpm文件:nxserver-2.1.0-22.i386.rpm,其中nxserver表示软件的名称,2.1.0表示软件的版本号,22表示软件更新发行的次数,i386表示适合的硬件平台,.rpm是rpm软件包的标识
  3. yum的在线安装
    yum是一个Shell前端软件包管理器,基于RPM包管理,能够从指定服务器自动下载RPM包并且安装,可以自动处理依赖关系,并且以此安装所有依赖的软件报,无须繁琐的一次次的下载安装,yum提供了查找、安装、删除某一个、一组甚至全部软件包的命令。

安装

安装用法
yum install安装全部
yum install package1安装指定的程序包
yum groupinstall group1安装程序包group1

更新

更新用法
yum -y update升级所有包,改变软件设置和系统设置,系统版本内核都升级
yum -y upgrade升级所有报,不改变软件设置和系统设置,系统版本升级,内核不改变
yum update package1更新指定程序包package
yum check-update检查可更新的程序
yum upgrade package1升级指定程序包package1
yum groupupdate group1升级程序组goup1

查找和显示

更新用法
yum info package1显示安装包的信息
yum list显示所有已经安装和可安装的程序包
yum list package显示指定程序包安装情况
yum groupinfo group1显示程序组1的信息
yum grouplist显示所有的可以安装和已经安装的组
yum search string根据关键字string查找安装包

删除程序

删除用法
yum -y remove/erase package1删除程序包package1
yum groupremove group1删除程序组group1
yum deplist package1查看程序package依赖情况

清除缓存

清除用法
yum clean packages清除缓存目录下的软件包
yum clean headers清除缓存目录下的headers
yum clean oldheaders清除缓存目录下旧的headers
yum clean,yum clean all清除缓存目录下的软件包和旧的headers
yum makecache重新构建缓存

4.3 Shell编程

4.3.1 shell介绍

shell是一个用c语言编写的程序,被称为用户使用linux的桥梁

shell既是一个命令语言,也是一个程序设计语言

shell脚本(shell script),是一种为shell编写的脚本程序

4.3.2 shell运行环境和运行方式
  1. shell编程和java,python等一样,只需要一个文本编辑器和解释工具即可

  2. 运行方式:而可执行权限运行 chmod a+x /home/shell/first…sh使脚本具有可执行的权限;加解释器运行/bin/bash /home/shell/first.sh

4.3.3 shell的变量
  1. 变量的定义:name=“12345A”;注意变量和等号之间不能有空格
  2. 变量的赋值:name=‘expr 2 + 2’这里通过语句赋值,必须有空格
  3. 变量的取值${name}
  4. 变量类型
  5. shell字符串:双引号,单引号,没有都可以。但是单引号不会识别内部的变量。反引号认为是linux中可执行命令
  6. 获取字符串长度:${#name}
4.3.4 shell的数组

bash支持一维数组,并没有限定数组的大小。和C语言类似,数组元素的下标是从0开始的。

4.3.5 shell的注释

以“#”开头的行就是注释,会被解释器忽略。sh里没有多行注释,只能每一行加#。如果大段代码需要注释,可以把这一段代码用一个花括号括起来,定义为一个函数,没有地方调用这个函数就和注释一样的效果。

4.3.6 shell的基本运算符

数学运算符

4.4 XShell连接Linux服务器

  1. 本人是直接从腾讯的软件管家下载的,真香。

  2. 新建一个会话框,alt+N新建,alt+o显示已有的连接。下面就是新建会话框的窗口,其中名称由我们自己随意填写,主机就是我们要连接的Linux的ip地址,然后端口号默认即可。
    在这里插入图片描述

  3. 点击确定之后会出现输入用户名和密码,选中记住密码可以在下次直接登陆。

  4. 至此就会连接上Linux的主机了。

5. hadoop

5.1 hadoop介绍

Apache平台是一个框架,允许使用简单的编程模型。在计算机集群中对大型数据集进行分布式处理。该平台被设计成可以从单个服务器扩展到数千台服务器,每个服务器都提供本地计算。该平台也被设计成可检测和处理应用层的故障(高可靠,高容错)。

5.2 hadoop安装

5.2.1 hadoop安装文件的挂载

这里本人已经在hadoop官网下载好相应的hadoop安装包,但是由于保存在windows硬盘中,不能在Linux中得到。利用wm系统中的共享文件夹的方式来实现挂载以及后续安装。

问题:

  1. 安装VmTools用来共享文件夹:
    参考:https://www.cnblogs.com/lin3615/p/5602108.html

  2. hgfs的目录下没有文件
    参考:https://blog.csdn.net/wear_/article/details/39896775

3.这里出错,

[root@localhost /]# mount -t vmhgfs .host:/share /mnt/hgfs
Error: cannot mount filesystem: No such device

这里看了网上很多的解决办法都没有解决
通过下面来解决,成功实现挂载

[root@localhost /]# vmhgfs-fuse .host:/share /mnt/hgfs/
5.2.2 hadoop安装
  1. 解压缩:利用tar -zxvf hadoop-3.1.1.tar.gz -C /usr/local/将文件解压缩到local目录下就好了

  2. 添加环境变量:到/etc/profile中进行添加,如图所示
    在这里插入图片描述
    进行环境变量的测试:which hadoop
    发现问题:
    ERROR: JAVA_HOME is not set and could not be found.
    在网络上找了一些资料,但都不能解决我的问题,也都没有说的很明白。这里记录一下。
    2.1 java -version检查java是否安装好,如果安装好which java查看java的路径
    2.2 进入/usr/local/hadoop/etc/hadoop-env.sh。添加,注意是添加,该文件里面的内容基本都是被注释掉的,我们需要单独添加而不是像网络上说的进行修改就可以的。我这里添加的是export JAVA_HOME=/usr。
    !!注意这里的等号两侧不能存在空格。
    2.3 source确保修改。

  3. 测试hadoop:Hadoop version查看hadoop的版本号,如果没有报错就行了。

5.2.3 举例运用

下面的例子是计算input目录下所有xml文件中,字符出现的次数
在这里插入图片描述

5.2 分布式文件系统HDFS

  1. 三大核心:HDFS、MapReduce、YARN
  2. 四大模块:
    Hadoop Common:为其他Hadoop模块提供基础设施。
    Hadoop DFS:一个高可靠、高吞吐量的分布式文件系统
    Hadoop MapReduce:一个分布式的离线并行计算框架
    Hadoop YARN:一个新的MapReduce框架,任务调度与资源管理

5.3 克隆服务器

5.3.1 克隆虚拟机

由于Hadoop的集群需要多台服务器,因此尝试对原有的Linux服务器进行克隆得到。在Vmware中右键虚拟机名称,点击管理,然后点击克隆。选择克隆完整克隆,接着选择存储位置即可。

等待一段时间克隆结束,就会多出来新的一个虚拟机。就是我们刚刚取的名字。

5.3.2 修改克隆虚拟机的配置
  1. 我看了下自己克隆出来的虚拟机,发现和老师得到的不一样,因为我克隆的虚拟机的ip和原来的并不一样,因此ip地址不需要修改了。

  2. 为了区分两个主机的不一样,分别设置主机名为centos01和centos02。我的Vmware是14.x可能和老师的不一样。vi /etc/sysconfig/network永久性的修改主机名

  3. 但是笔者发现,在ifconfig后并没有出现我的ens33网卡。因此应该是网卡的配置出了问题

    (vi /etc/udev/rules.d/70-persistent-ipoib.rules 查看网卡信息,网卡的mac地址没有出现问题。
    vi /etc/sysconfig/network-scripts/ifcfg-ens33
    进入我的网卡配置,发现网卡中的uuid和我之前的uuid相同,前面的肯定已经被占用了,所以这里修改不一样
    但是这个时候依然不能找到ens33网卡

    解决:
    这个时候笔者,点击网络适配器,选择高级,发现每次的mac地址都是不一样的。也就是说克隆出来的虚拟机的mac地址和原来的mac地址是不一样的,这里要进行更换,将上面两个文件中的mac信息进行 更换好了

  4. 然后我直接用xshell尝试对服务器进行连接。新建一个连接用来连接centos02,发现已经可以连接。
    问题:
    当一个会话进行中的时候,就无法连接另外一个服务器。不能同时对两个服务器进行连接。但是笔者,再次尝试的时候就突然可以了,难道是因为开始的时候还不稳定??先就这么理解吧,能通就好。

  5. 进行两者之间的通信,ping通。

5.3.2 克隆第二个虚拟机

重复以上操作,再次克隆出来一个虚拟机。三个虚拟机用于服务器集群。

相互通信,成功便可以。

5.4 搭建Hadoop集群

5.4.1 Hadoop全分布式环境搭建

在这里插入图片描述

  1. 规划服务器与服务
    在这里插入图片描述
主机名称IP地址功能
centos01192.168.85.129NameNode、DataNode、resourcemanger、nodemanager
centos02192.168.85.128DataNode、nodemanager
centos03192.168.85.130DataNode、nodemanager

所有机子都需要配置JDK、SSH免登陆(后面说)、Hadoop集群

配置hadoop的相关配置文件

  1. vi ./etc/hadoop/hadoop-env.sh配置java的路径
  2. vi ./etc/hadoop/core-site.xml
<configuration>
<!--配置hdfs文件系统的命名空间-->
<peooperty>
<name>fs.defaultFS</name>
<value>hdfs://centos01:9000</value>
</property>

<!--配置操作hdfs的缓冲大小-->
<property>
<name>io.file.buffer.size</name>
<value>131072</value>
</property>
<!--配置临时数据存储目录-->
<property>
<name>hadoop.tmp.dir</name>
<value>/home/bigdata/tmp</value>
</property>

</configuration>

  1. vi ./etc/hadoop/hdfs-site.xml
<configuration>
<!--副本数目-->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>

<!--块大小-->
<property>
<name>dfs.block.size</name>
<value>268435456</value>
</property>

<!--hdfs元数据存储的位置-->
<property>
<name>dfs.namenode.name.dir</name>
<value>/home/hadoopdata/dfs/name</value>
</property>

<!--hdfs数据存储的位置-->
<property>
<name>dfs.datanode.data.dir</name>
<value>/home/hadoopdata/dfs/data</value>
</property>

<!--hdfs的namenode的web ui地址-->
<property>
<name>dfs.http.address</name>
<value>centos01:50070</value>
</property>

<!--hdfs的snn的web ui地址-->
<property>
<name>dfs.secondary.http.address</name>
<value>centos01:50090</value>
</property>

<!--是否开启web操作hdfs-->
<property>
<name>dfs.webhdfs.enabled</name>
<value>false</value>
</property>

<!--是否-启用hdfs的权限(acl控制列表)->
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>

</configuration>
  1. vi ./etc/hadoop/mapred-site.xml
<configuration>

<!--指定mapreduce的运行框架-->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
<final>true</final>
</property>

<!--历史服务的通信地址-->
<property>
<name>mapreduce.jobhistory.address</name>
<value>centos01:10020</value>
</property>

<!--历史服务的web ui地址-->
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>centos01:19888</value>
</property>

</configuration>
  1. vi ./etc/hadoop/yarn-site.xml
<configuration>

<!--指定resourcemanager的服务主机名-->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>centos01</value>
</property>

<!--指定rm的shuffle-->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>

<!--指定rm的内部通信地址-->
<property>
<name>yarn.resourcemanager.address</name>
<value>centos01:8032</value>
</property>

<!--指定rm的shceduler的内部通信地址-->
<property>
<name>yarn.resourcemanager.scheduler.address</name>
<value>centos01:8030</value>
</property>

<!--指定rm的resource-tracker的内部通信地址-->
<property>
<name>yarn.resourcemanager.resource-tracker.address</name>
<value>centos01:8031</value>
</property>

<!--指定rm的admin的内部通信地址-->
<property>
<name>yarn.resourcemanager.admin.address</name>
<value>centos01:8033</value>
</property>

<!--指定rm的web ui监控地址-->
<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>centos01:8088</value>
</property>

</configuration>
  1. vi ./etc/hadoop/workers,不是老师说的slaves
centos01
centos02
centos03
5.4.2 hadoop的分发

由于在centos01中对hadoop进行了编辑,想要将centos01中的hadoop分发到其他计算机中。

  1. 将centos02和centos03中的hadoop进行删除。
rm -rf /usr/local/had**/
  1. 将centos01中的hadoop分发到另外两个服务器中,由于hadoop中的doc帮助文档特别多的html影响分发进程,因此进行删除
rm -rf ./share/doc/

scp -r ../hadoop**/ centos02:/usr/local/

scp -r ../hadoop**/ centos03:/usr/local/
5.4.2 hadoop的启动

启动之前在namenode服务器上先格式化,只需要格式化一次就可以

#hadoop namenode -format

启动namenode、datanode、Resourcemanager、NodeManager

全启动:start-all.sh
模块启动:start-dfs.sh start-yarn.sh
单个进程启动:

hadoop-daemon.sh   start namenode
hadoop-daemons.sh start datanode

yarn-daemon.sh   start namenode
yarn-daemons.sh start datanode

mr-hobhistory-daemon.sh start/stop historyserver

测试:

  1. 查看进程是否启动起来
  2. 查看web ui监控是否正常:http://192.168.85.129:50070
  3. 上传和下载文件(测试hdfs)、跑一个mapreduce作业

问题:
笔者在这里和老师一起进行模块格式化。

报错:

ERROR conf.Configuration: error parsing conf hdfs-site.xml

于是乎笔者机内hdfs文件中,将老师给的一些内容进行了删除。这里是比对这hadoop官网的内容,如果官网的配置没有就删除。主要是删除了一些web相关的配置。

之后进行格式化成功进行没有报错。

接着笔者进行

./sbin/start-dfs.sh 

报错
Starting namenodes on [centos01]
ERROR: Attempting to operate on hdfs namenode as root
ERROR: but there is no HDFS_NAMENODE_USER defined. Aborting operation.

解决方法参考:https://blog.csdn.net/coffeeandice/article/details/78879151?utm_source=copy

(缺少用户定义而造成的)因此编辑启动和关闭

注意这里不是在start-all里面进行修改,只在start-dfs.sh和stop-dfs.sh中

$ vi sbin/start-dfs.sh
$ vi sbin/stop-dfs.sh

顶部空白处

HDFS_DATANODE_USER=root
HADOOP_SECURE_DN_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root

之后再次启动成功解决问题。在这里插入图片描述

然后笔者想要和老师一样jps,查看Linux进程,但是发现我这里找不到jps。百度得知jps是java里面的运行程序,这里就回到我之间java路径的定义了。我的Java路径只是一个软路径,真正的路径并没有找到。

参考:https://blog.csdn.net/m290345792/article/details/79073358
最终找到路径:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.181-3.b13.el7_5.x86_64/jre/bin/java
但是在这些路径下面并没有出现jps的命令

参考:https://blog.csdn.net/qq_40105363/article/details/80081185

yum install -y java-1.8.0-openjdk-devel

对jdk进行补充安装,安装完后就可以查看了。
在这里插入图片描述
这里成功看到我们的datanode、namenode、secondarynamenode启动。

  1. web ui监控没有成功
    因为配置的时候删除了很多关于网络 的东西,所以这里不能正常地通过网络来访问也正常。
    因此通过查看官方文档,查看了一下默认地配置文件。发现由于版本地不同,我默认地文件中一些参数的设置和老师并不一致。为此,在hdfs.xml中添加上相应的namenode的地址和datanode地址,以及secondarynamenode的地址。重新对模块进行启动。

jps查看服务没有报错,接着通过netstat -nltp查看了出现的ip和端口。发现我们的在hdfs中配置的内容在这里作为服务显示了出来。应该是可以通过web来进行访问的,但是呢在web中却没有成功。在网络上翻了一遍,发现是我的Linux中防火墙开着。关闭防火墙:

#关闭防火墙
systemctl stop firewalld.service 
#禁止开机启动
systemctl disable firewalld.service 

再次通过web访问,这次成功。
在这里插入图片描述

问题:这里搭建的系统只有一个datanode,没有将三个计算机统一起来。

  1. 针对该问题,就是dfs系统没有将各个计算机统一起来。肯定是配置文件除了问题,但是仔细看了以下前面4个配置文件,都没有什么错误,那就是在slaves上面了。由于老师的是2.9版本,而我的是3.1.1版本。在网络查了以下,发现3.0版本之后是没有slaves文件的,这也和我一开始为什么自己新建一个slaves文件有关系。在这里是通过workers来识别的,因此只需要在相同目录下的workers中进行修改就好了。
  2. 但是仍然存在问题,明明三个服务器都开启了datanode,但是在在dfs web文件系统访问页面只能看到两个存活的节点。
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

进入web页面的datanode访问页面,发现第三个服务器没有成功连接上dfs系统。但是单独看centos03的内容发现已经启动了datanode节点,那么问题应该就是出现在centos01和cento03的连接上。进入centos03的hosts配置文件中,发现这里面并没有出现centos01的ip映射,进行添加。

关闭,重新开启dfs文件系统服务。发现依然是这样,这个时候尝试在centos03中ping centos01,发现不能ping同,说名centos03的网络存在问题。直接ping ip地址却发现能ping通,那么就是hosts映射出的问题。对hosts进行修改能够ping通centos01后,重启dfs文件系统。成功。

在这里插入图片描述

3、在web网页中点击ulities进入browser界面。在linux中输入。将当前目录下的文件存放到hdfs系统的根目录下面。web中可以显示出来。

hdfs dfs -put ./README.txt /

在这里插入图片描述

5.4.3 yarn服务的使用
  1. 启动yarn服务

    start-yarn.sh

开启服务之后jps发现centos01中多了resourcemanager和nodemanager。而centos02和centos03中则多出来了nodemanager。

  1. web 监控 http://192.168.85.129:8088成功监控

  2. 进行wordcount检测。


     yarn jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.1.jar wordcount /README.txt /out/00

发现在web端已经有了提交的进程。
在这里插入图片描述

但是在进行wordcount的时候出现问题。

 java.net.NoRouteToHostException: No route to host

经百度发现需要将集群下每一个机子都要关闭防火墙。
都关闭后,再次执行wordcount命令。


    Error: Could not find or load main class org.apache.hadoop.mapreduce.v2.app.MRAppMaster

Please check whether your etc/hadoop/mapred-site.xml contains the below configuration:
<property>
  <name>yarn.app.mapreduce.am.env</name>
  <value>HADOOP_MAPRED_HOME=${full path of your hadoop distribution directory}</value>
</property>
<property>
  <name>mapreduce.map.env</name>
  <value>HADOOP_MAPRED_HOME=${full path of your hadoop distribution directory}</value>
</property>
<property>
  <name>mapreduce.reduce.env</name>
  <value>HADOOP_MAPRED_HOME=${full path of your hadoop distribution directory}</value>
</property>

经过在网上的查询:

<property>
<name>mapreduce.application.classpath</name>
<value>
/usr/local/hadoop-3.1.1/share/hadoop/mapreduce/*, 
/usr/local/hadoop-3.1.1/share/hadoop/mapreduce/lib/*,
/usr/local/hadoop-3.1.1/share/hadoop/mapreduce/lib-examples/*

</value>

</property>

这样就能够解决了这个问题了。

但是接下来又出现了内存崩溃的是:

在这里插入图片描述

参考:https://www.cnblogs.com/scw2901/p/4331682.html

解决方法:

<property>
  <name>mapreduce.map.memory.mb</name>
  <value>1536</value>
</property>
<property>
  <name>mapreduce.map.java.opts</name>
  <value>-Xmx1024M</value>
</property>
<property>
  <name>mapreduce.reduce.memory.mb</name>
  <value>3072</value>
</property>
<property>
  <name>mapreduce.reduce.java.opts</name>
  <value>-Xmx2560M</value>
</property>

这样就成功运行了第一个wordcount
在这里插入图片描述

运行成功
在这里插入图片描述

5.4.4 ssh免登陆服务
  1. ssh-keygen -t rsa 一路回车
    在这里插入图片描述

注意:此时直接进行ssh centos01还是需要输入密码的。下面的图片就需要密码的输入。
在这里插入图片描述

要对ssh添加密码
在这里插入图片描述

此时实现ssh的免密登陆
在这里插入图片描述

此时.ssh目录下会多出来免密的文件,authorized_key如下
在这里插入图片描述

  1. 这时想要通过ssh的方式来直接登陆centos02,仿照上面ssh centos02出现错误。

问题:
[root@centos01 .ssh]# ssh centos02
ssh: Could not resolve hostname centos02: Name or service not known

但是直接进行ssh ip地址就是可以的。
这里分析,应该是/etc/hosts下面没有对centos02进行ip和名称的配置。vi hosts将ip centos02加进去,然后出来后发现就能够直接ssh centos02了。

再次通过以上的内容来进行添加密码就可以免密登陆centos02了。

5.4.5 hdfs的shell命令
hdfs dfs -
进行查看常用的命令

Usage: hadoop fs [generic options]
	[-appendToFile <localsrc> ... <dst>]
	[-cat [-ignoreCrc] <src> ...]
	[-checksum <src> ...]
	[-chgrp [-R] GROUP PATH...]
	[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
	[-chown [-R] [OWNER][:[GROUP]] PATH...]
	[-copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
	[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
	[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] [-e] <path> ...]
	[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
	[-createSnapshot <snapshotDir> [<snapshotName>]]
	[-deleteSnapshot <snapshotDir> <snapshotName>]
	[-df [-h] [<path> ...]]
	[-du [-s] [-h] [-v] [-x] <path> ...]
	[-expunge]
	[-find <path> ... <expression> ...]
	[-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
	[-getfacl [-R] <path>]
	[-getfattr [-R] {-n name | -d} [-e en] <path>]
	[-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
	[-head <file>]
	[-help [cmd ...]]
	[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [<path> ...]]
	[-mkdir [-p] <path> ...]
	[-moveFromLocal <localsrc> ... <dst>]
	[-moveToLocal <src> <localdst>]
	[-mv <src> ... <dst>]
	[-put [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
	[-renameSnapshot <snapshotDir> <oldName> <newName>]
	[-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
	[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
	[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
	[-setfattr {-n name [-v value] | -x name} <path>]
	[-setrep [-R] [-w] <rep> <path> ...]
	[-stat [format] <path> ...]
	[-tail [-f] <file>]
	[-test -[defsz] <path>]
	[-text [-ignoreCrc] <src> ...]
	[-touchz <path> ...]
	[-truncate [-w] <length> <path> ...]
	[-usage [cmd ...]]


6. maven

6.1 windows中安装maven

官网镜像目录:http://maven.apache.org/download.cgi

  1. 下载windows中的zip压缩包,下载完成之后直接进行解压即可。

  2. 配置环境变量。

  3. 配置setting.xml文件,(指定本地仓库位置)。并创建一个本地仓库的空目录。

  4. 参考:https://blog.csdn.net/jiruirui213/article/details/78494085
    运行命令行mvn help:system完成对本地仓库文件的下载

  5. 和java的编辑工具整合(eclipse)
    window-preference-搜索maven,然后添加add,directory自己的maven安装目录,finish。继续user setting-global settings选择自己配置的setting文件。

6.2 Java操作hdfs文件系统

  1. new-project-maven -maven project-next
  2. 这里我没有和老师一样对pom.xml文件进行其他的配置,而是直接进行run as-maven install.竟然下载完成了。但是有问题
  3. 这里进行依赖的填写:http://mvnrepository.com,搜索hadoop
  4. 关于没有org.apache.hadoop.conf的包,这里的包是在pom.xml依赖后进行下载的,由于下载速度比较慢,在还没有完全下载好的时候是没有这些包的,需要耐心等待下载完成。

maven报错Missing artifact jdk.tools:jdk.tools:jar:1.8解决方案
参考:https://blog.csdn.net/qy20115549/article/details/53004779
添加tool.jar包到库中就可以了。

然后遇到问题:HADOOP_HOME and hadoop.home.dir are unset.

Could not locate Hadoop executable: D:\hadoop3.1.1\hadoop-3.1.1\bin\winutils.exe
-see https://wiki.apache.org/hadoop/WindowsProblems

然后进入解决方案网站,跳转到github对相应的内容进行下载,之后放到电脑的hadoop/bin目录就ok了。

依然报错:/D:/apache-maven-3.5.4-bin/apache-maven-3.5.4/MavenRepository/org/apache/hadoop/hadoop-core/1.2.1/hadoop-core-1.2.1.jar

我到相应的目录下却发现存在我们需要的jar包。
参考:https://blog.csdn.net/yhao2014/article/details/45578355
网络上说是jar包的冲突所致,需要在build path中删除hadoop-core.xxx.jar。我这里是在pom.xml依赖项里面把相应的dependency去掉。

然后报错和解决办法参考如下:https://www.cnblogs.com/huxinga/p/6868074.html

接着说url不是一个absolute url这里我检查了一下url发现是fs.default写错误。然后进行修改即可。正确代码如下:

package com.tj.hdfs;

import java.io.IOException;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.log4j.BasicConfigurator;

/**
 * 用java操作hdfs
 * */
public class hdfs {
	public static void main(String[] args) throws IOException{
		
		BasicConfigurator.configure(); //自动快速地使用缺省Log4j环境。
		
		readFileToConsole("/test.txt");
		
	}
	
	
	public static void readFileToConsole(String path) throws IOException{
		
		//获取配置
		Configuration conf = new Configuration();
		//配置
		conf.set("fs.defaultFS", "hdfs://192.168.85.129:9000");
	
		//获取hdfs文件系统的操作对象
		FileSystem fs = FileSystem.get(conf);
		
		FSDataInputStream fis = fs.open(new Path(path));
			
		IOUtils.copy(fis, System.out);
		
	}
}

输出为test.txt文件的内容

在这里插入图片描述
至此成功使用eclipse在windows中读取相应的文件内容。

同理上传和保存本地等操作

	public static void readFileToLocal(String path) throws IOException, InterruptedException, URISyntaxException {
		
		//获取配置
		Configuration conf = new Configuration();
		//配置
//		conf.set("fs.defaultFS", "hdfs://192.168.85.129:9000");
	
		//获取hdfs文件系统的操作对象
		FileSystem fs = FileSystem.get(new URI("hdfs://192.168.85.129:9000"), conf, "root");
		
		FSDataInputStream fis = fs.open(new Path(path));
		
		OutputStream out = new FileOutputStream(new File("D:\\hadoop3.1.1\\testFromHdfs.txt"));
		
		
		
		IOUtils.copy(fis, out);
		
	}
	
	
	public static void copyFromLocal() throws IOException, InterruptedException, URISyntaxException{
		//获取配置
		Configuration conf = new Configuration();
		//配置
//		conf.set("fs.defaultFS", "hdfs://192.168.85.129:9000");
	
		//获取hdfs文件系统的操作对象
		FileSystem fs = FileSystem.get(new URI("hdfs://192.168.85.129:9000"), conf, "root");
		
		fs.copyFromLocalFile(new Path("D:\\hadoop3.1.1\\testFromHdfs.txt"), new Path("/test/fromlocal"));
		
		System.out.println("finished");
		

6.3 RPC

6.3.1 概念

远程过程调用(RPC)是一个协议,程序可以使用这个协议请求网络中另一台计算机上某程序的服务而不需要知道网络的细节。

必备知识:
网络七层模型
网络四层模型

RPC模式:
C/S模式
基于传输层协议(TCP/IP)
事件处理模型(请求、计算、响应)

RPC设计目的:
调用非本机的方法
不同语言程序之间的通讯
不了解底层通讯,像本地方法一样调用

RPC的作用:
分布式程序的基础(分布式操作系统,分布式计算,分布式软件设计)
垂直应用服务化拆分

RPC的特点:
封装网络交互
远程调用对象的代理
支持容器(Spring、Jetty等)
可配置、可扩展

7. zookeeper

7.1 基本概念

是什么:
分布式服务的协调服务

能做什么:
管理分布式服务
通过分布式服务的一致性、对分布式服务做协调
强一致性

zookeeper架构:
zk集群一般需要奇数台服务器,当n/2台zk服务ok,则整个zk集群可用。
leader:老大,管理小弟。然后负责来自client的数据读写请求,先把数据写到内存,然后持久化到本地,然后通知followers及时同步
follower:小弟,负责数据的同步,还会参与选举等
所有的leader和follower都称为server。

快速选举机制:当leader挂掉之后,快速从其余的follower中选举出一个leader
原子广播协议(保证数据一致性):leader广播所有follower同步数据

zookeeper的数据模型:
类似文件系统的一个树形结构,用于携带少量数据。
每一个数据节点(树中的每一个分支节点或者叶子节点)称之为znode,每一个节点与传统树形文件系统的区别。
目标:传统文件系统设计用于大量数据,而zk用于存储少量数据来进行协调服务,每一个znode节点既是目录又是文件。

znode节点有四种:
普通znode:
普通序列化znode: /name000001
临时znode:当session退出或者失效,则该节点消失
临时序列化znode:

watcher:事件(节点可以注册事件)节点、更新节点、创建子节点。(事件具有一致性)

7.2 zookeeper集群安装

  1. 下载网址:http://mirror.bit.edu.cn/apache/zookeeper/stable/

  2. 解压安装:tar -zxvf XXX。这里笔者解压到/usr/local/目录下面。删除docs文件,方便后续移动

  3. 配置环境变量:vi /etc/profile。修改完成source

  4. 修改 ./conf/zoosample.cfg名称和内容

 mv ./conf/zoo_sample.cfg ./conf/zoo.cfg
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/home/zkdata/
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

#2888为通信端口,3888为选举端口
server.1=centos01:2888:3888
server.2=centos02:2888:3888
server.3=centos03:2888:3888
  1. 分发到centos02和centos03中:scp -r ../zookerxxx centos02:/usr/local。并分别配置相应的环境变量
  2. 每一个服务器上创建mkdir /home/zkdata目录。并且创建相应的myid。vi /home/zkdata/myid。分别为1、2、3.
  3. 启动zk。zkServer.sh start
    在这里插入图片描述这里在三台服务器中都进行相同的操作,全部开启。

7.3 zk中的shell

  1. zkCli.sh [-server centos02:2181]。接连到某一个主机下面的server。默认为当前主机

在这里插入图片描述随便敲,进入shell提示界面
ls查看节点
create -e 创建临时节点,-s为序列节点。
set为修改节点内容。
get查看节点内容
rmr递归删除,delete删除单节点

在server.1中创建一个文件,可以在server.2中直接检查到该文件。强一致性。

8.hdfs的ha高可用

8.1 介绍

每一个namenode的上面都有一个zookeeper fail转移控制。在hadoop2.x中通常由两个namenode组成,一个处于activity状态,一个处于standby状态。Active NameNode对外提供服务,而Standby NameNode则不对外提供服务,仅同步active namenode的状态,以便能够在它失败的时候快速进行切换。

hadoop2.0官方提供两种HDFS HA的解决方案,一种是NFS,另一种是QJM(由cloudra JournalNode提出。类似于zookeeper)。这里使用QJM完成。主备NameNode之间通过一组JournalNode同步元数据信息,一条数据只要成功写入多数JournalNode即认为写入成功。通常配置奇数个journalNode。
在这里插入图片描述

8.2 配置

机器规划:
centos01 namenode datanode journalnode QuroumPeerMain zkfc
cnetos02 namenode datanode journalnode QuroumPeerMain zkfc
centos03 datanode journalnode QuroumPeerMain zkfc

免登陆:
两个老大之间,老大对小弟的免登陆

配置:普通集群进行备份,三台机器

mv /usr/local/hadoop-3.1.1/ /usr/local/hadoop-3.1.1_backup

再次解压安装hadoop

8.2.1 notepad远程连接的配置

打开notepad,选中插件-NppFTP-showNppFTPWindow。 没有该选项的到网络上进行下载,然后将nppftp.dll放置到notepad安装目录下的plugin目录下,再次启动notepad就有了。

选择设置中,profile那一项进行如下设置。主机名端口都要和自己的对应上去。

!!注意:这里的连接方式是SFTP,并非默认方式。

在这里插入图片描述

连接成功后的效果
在这里插入图片描述

此时便可以通过notepad来直接对Linux中的文件进行 操作了。

8.2.2 文件的配置

  1. hadoop_env.sh 配置java路径
  2. core_site.xml
<configuration>
<!--指定hdfs的虚拟命名空间-->
<property>
  <name>fs.defaultFS</name>
  <value>hdfs://tj</value>
</property>

<property>
  <name>hadoop.tmp.dir</name>
  <value>/home/hahadoopdata/tmp</value>
</property>

<property>
  <name>io.file.buffer.size</name>
  <value>4096</value>
</property>

</configuration>
  1. hdfs-site.xml
<configuration>

<!--指定hdfs的虚服务名-->
<property>
  <name>dfs.nameservices</name>
  <value>tj</value>
</property>

<!--指定hdfs的虚拟服务下的namenode名字-->
<property>
  <name>dfs.ha.namenodes.tj</name>
  <value>nn1,nn2</value>
</property>

<property>
  <name>dfs.namenode.rpc-address.tj.nn1</name>
  <value>centos01:8020</value>
</property>

<property>
  <name>dfs.namenode.rpc-address.tj.nn2</name>
  <value>centos02:8020</value>
</property>

<!--指定namenode的web ui通信地址-->
<property>
  <name>dfs.namenode.http-address.tj.nn1</name>
  <value>centos01:9870</value>
</property>
<property>
  <name>dfs.namenode.http-address.tj.nn2</name>
  <value>centos02:9870</value>
</property>

<!--指定journalnode数据共享目录-->
<property>
  <name>dfs.namenode.shared.edits.dir</name>
  <value>qjournal://centos01:8485;centos02:8485;centos03:8485/tj</value>
</property>

<!--指定journalnode本地共享目录-->
<property>
  <name>dfs.journalnode.edits.dir</name>
  <value>/home/hahadoopdata/journal/data</value>
</property>

<!--指定namenode失败进行自动切换的子类-->
<property>
  <name>dfs.client.failover.proxy.provider.mycluster</name>
  <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

<!--防止多个namenode通过active(脑裂),采用某种方式杀死其中一个-->
<property>
    <name>dfs.ha.fencing.methods</name>
    <value>sshfence</value>
</property>

<property>
    <name>dfs.ha.fencing.ssh.private-key-files</name>
    <value>/home/root/.ssh/id_rsa</value>
</property>

<property>
    <name>dfs.ha.fencing.ssh.connect-timeout</name>
    <value>30000</value>
</property>

<!--开启naomenode是否失败进行自动切换-->
 <property>
   <name>dfs.ha.automatic-failover.enabled</name>
   <value>true</value>
 </property>
 
 <!--指定zk集群地址,用来协调namenode的服务-->
  <property>
   <name>ha.zookeeper.quorum</name>
   <value>centos01:2181,centos02:2181,centos03:2181</value>
 </property>

</configuration>
  1. workers
centos01
centos02
centos03

  1. 分发:
scp -r ../hadoop-3.1.1 centos02:/usr/local/
  1. 免登陆配置,centos01和centos02对外免登陆

  2. 启动zk

  3. 启动journalnode服务
    单个启动 ./sbin/hadoop-daemon.sh start journalnode
    多个启动 ./sbin/hadoop-daemons.sh start journalnode
    在这里插入图片描述

  4. 挑选两个namenode之中的一台来格式化,

hdfs namenode -format

格式化的时候存在问题
在这里插入图片描述
观察可以发现我们在hdfs.xml中配置的好几个都在,但是namenode的name文件夹却没有格式化出来。
报错:

2018-10-07 22:24:45,804 INFO ipc.Client: Retrying connect to server: centos03/192.168.35.130:8485. Already tried 1 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1000 MILLISECONDS)
2018-10-07 22:24:45,805 INFO ipc.Client: Retrying connect to server: centos02/192.168.35.129:8485. Already tried 1 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1000 MILLISECONDS)

解决:参考
https://blog.csdn.net/u014729236/article/details/44944773/
解决方法:先用./zkServer.sh start 启动各个zookeeper,再用./ hadoop-daemon.sh start journalnode启动各个NodeName上的 JournalNode进程,确保所有都启动。然后再进行格式化即可。

  1. 然后启动centos01中启动namenode。 hadoop-daemons.sh start namenode这句代码是老师给的,但是在我这里报错。并且提醒 hdfs --daemon start namenode我这里使用这句话成功启动。
    在这里插入图片描述

  2. 在另外一台namenode机子上拉元数据(也可以是复制)hdfs namenode -bootstrapStandby。拉取完毕后在centos02的时候也有dfs/name文件

  3. 格式化zkfc。hdfs zkfc -formatZK
    在这里插入图片描述

  4. 启动start-all.sh
    分别在start-dfs.shstart-yarn.sh;stop-dfs.sh,stop-yarn.sh中添加相应内容。
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 测试:先看对应的进程是否启动;再看web ui是否正常;
    这里由于我在学习过程中重装过系统,虚拟机也是重新装的,因此后来的ip和之前略微有些不同,这里在浏览器中输入http://192.168.35.128:9870和http://192.168.35.129:9870分别会看到下面的内容
    在这里插入图片描述

在这里插入图片描述

  1. 在hdfs中读写文件;
    报错:-ls: java.net.UnknownHostException: tj
    参考:https://blog.csdn.net/shirdrn/article/details/6562292
    我这里是跟着老师后面的qf,我就随便弄了一个,但是这里报不知道的主机异常,百度发现是tj在hosts文件中的映射不存在。添加相应的就好了。但是这个也存在问题,明明是一个虚拟的nameservice,这样就把这个内容给具体化了。

继续百度:https://blog.csdn.net/xjping0794/article/details/78552922
这里说hdfs-site.xml文件缺少配置,加上就可以了。修改后记得分发到另外两个主机中。

<property> 
                   <name>dfs.client.failover.proxy.provider.testcluster</name>
                   <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value></property>
                   

添加内容

hdfs dfs -put /usr/local/hadoop-3.1.1/etc/hadoop/workers /

成功添加。

  1. 然后关闭一个namenode,查看是否能够自动切换;在centos01中kill namenode进程。此时进不去centos01的web ui界面。但是进入namenode2的界面还是standby的页面没有成功转化为active,这里失败了。

解决:这里是通信的问题,下面的配置采用的是ssh的通信,我们需要找到.ssh文件下面,笔者一开始没有对应正确,由于笔者一直是root用户登陆,因此文件应该保存在/root/目录下面。

<property>
    <name>dfs.ha.fencing.ssh.private-key-files</name>
    <value>/root/.ssh/id_rsa</value>
</property>

这里成功实现自动切换。

8.3 yarn的配置和测试

  1. yarn的规划
  2. 配置:yarn-site.xml和mapred-site.xml
  3. 远程发送,直接启动,web监控,测试
  4. 关闭active,再次检测是否高可用

9. MapReduce分布式并行离线计算框架

9.1 MapReduce编程模型

  1. 一种分布式计算模型,解决海量数据的计算问题
  2. MapReduce将整个并行计算过程抽象到两个函数中
  • Map(映射):对一些独立元素组成的列表的每一个元素进行指定的操作,可以实现高并行。
  • Reduce(化简,归约):对一个列表的元素进行合并
  1. 一个简单的MapReduce程序只需要指定Map(),reduce()、input、output,剩下的事由框架完成。

在这里插入图片描述

  1. MapReduce相关概念
    Job,用户的每一个计算请求,称为一个作业
    Task,每一个作业,都需要拆分开了,交由多个服务器来完成,拆分出来的执行单元,就称为任务
    Task分为MapTask和ReduceTask两种,分别进行Map操作和Reduce操作,依据Job设置的Map类和Reduce类。

9.2 Mapreduce实例–wordcount

  1. 问题:有一批文件(规模是TB或者是PB级),如何统计这些文件中所有单词出现的次数。

方案:
首先,分别统计每个文件中单词出现的次数 map()
然后,累加不同文件中同一个单词出现的次数; reduce()

wordcount示例运行
在dfs中创建input目录 hadoop fs -mkdir /data/input
将conf中的文件拷贝到dfs的input中 hadoop fs -put conf/* /data/input
/
运行wordcount hadoop jar hadoop-example…jar wordcount /data/input /data/output

编写MapReduce程序
实现wordcount程序编写:使用eclipse编写mapreduce程序,打包成jar,上传到集群中,使用hadoop jar命令运行。使用MapReduce eclipse插件程序开发并运行Job

未解决
2. 这里笔者想要重新建立一个maven project,但是新建的工程依赖的Maven库文件并全面。为此我不得不在已经有的project中添加package。
3. java代码

package MapReduce;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class wordcount {
	/*
	 * input 
	 * 
	 * words
	 * hello tj hello world
	 * hi tj hi world 
	 * best hadoop
	 * 
	 * map阶段
	 * KEYIN行偏移量:每一行的第一个字母距离该文件首位置的距离(Map阶段输入key的类型)0
	 * VALUEIN行的值:(Map阶段输入value类型)
	 * KEYOUT:(Map阶段输出Key的类型)
	 * VALUEOUT:(Map阶段输出key类型)
	 * 
	 * map阶段输入:每一行调用一次map方法
	 * 0	hello tj hello world
	 * 20	hi tj hi world
	 * 36	best hadoop
	 * 
	 * map阶段输出:
	 * best	1
	 * hadoop	1
	 * hello	1
	 * hello	1
	 * hi	1
	 * hi	1
	 * tj	1
	 * tj	1
	 * world	1
	 * world	1
	 * 
	 * 
	 * reduce阶段输入:
	 * reduce的输入类型必须和map阶段的输出类型key、value类型相同
	 * best	list<1>
	 * hadoop list<1>
	 * hello	list<1, 1>
	 * hi	list<1, 1>
	 * tj	list<1, 1>
	 * world	list<1, 1>
	 * 
	 * reduce阶段输出:
	 * best	1
	 * hadoop	1
	 * hello	2
	 * hi	2
	 * tj	2
	 * world	2
	 * */
	public static class MyMapper extends Mapper<LongWritable, Text, Text, IntWritable>{	
		public Text K = new Text();
		public IntWritable V = new IntWritable();
		@Override
		protected void map(LongWritable key, Text value,Context context)
				throws IOException, InterruptedException {
			//1. 从输入数据中获取每一个文件中每一行的值
			String line = value.toString();
			
			//2. 每一行数据进行切分
			String []words = line.split(" ");
			//3. 循环处理
			for(String word:words) {
				K.set(word);
				V.set(1);
				context.write(K, V);
			}
			
		}	
	}
		
	public static class MyReduce extends Reducer<Text, IntWritable, Text, IntWritable>{

		@Override
		protected void reduce(Text arg0, Iterable<IntWritable> arg1,
				Reducer<Text, IntWritable, Text, IntWritable>.Context arg2) throws IOException, InterruptedException {
			int count = 0;
			for(IntWritable i:arg1) {
				count += i.get();
			}
			arg2.write(arg0, new IntWritable(count));
		}		
	}
	
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		//1. 获取配置对象信息
		Configuration configuration = new Configuration();
		//2. 对conf进行设置(没有就不用)、
		//3. 获取Job对象
		Job job = Job.getInstance(configuration, "mywordcount");
		//4. 设置job的运行主类
		job.setJarByClass(wordcount.class);
		
		//5. 对map阶段进行设置
		job.setMapperClass(MyMapper.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);
		
		FileInputFormat.addInputPath(job, new Path(args[0]));
		
		//6. reduce阶段进行设置
		job.setReducerClass(MyReduce.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		//7. 提交job作业
		int isOK = job.waitForCompletion(true)?0:1;
		//8. 退出job
		System.exit(isOK);		
	} 
}

导出为jar包,左侧选中相应package,右键-export-java-JAR file。将这个jar包放进linux系统中,进行wordcount运行。
MapReduce为包名,wordcount为类名

yarn jar ./wordcount.jar MapReduce.wordcount /testInput /out/07

问题ConfiguredRMFailoverProxyProvider: Failing over to rm1
原因:没有启动yarn框架的resourceManager。

9.3 MapReduce的数学运算案例

package MapReduce;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.FloatWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

/*
 * 汽车流水线的三个事件段的记录算一个平均值
 * 
 * l_1	393	430	276
 * l_2	388	560	333
 * l_3	450	600	312
 * 
 * */
public class AvgDemo {

	public static class MyMapper extends Mapper<LongWritable, Text, Text, FloatWritable>{	
		public Text K = new Text();
		public FloatWritable V = new FloatWritable();
		@Override
		protected void map(LongWritable key, Text value,Context context)
				throws IOException, InterruptedException {
			//1. 从输入数据中获取每一个文件中每一行的值
			String line = value.toString();
			
			//2. 每一行数据进行切分
			String []words = line.split("\t");
			//3. 业务处理
			String linename = words[0];
			float z = Float.parseFloat(words[1]);
			float w = Float.parseFloat(words[2]);
			float y = Float.parseFloat(words[3]);
			K.set(linename);
			V.set((z+w+y/(words.length - 1)));
			context.write(K, V);
		}	
	}
		
	public static class MyReduce extends Reducer<Text, FloatWritable, Text, FloatWritable>{

		@Override
		protected void setup(Context context)
				throws IOException, InterruptedException {
			context.write(new Text("生产线\t生产平均值"), new FloatWritable());
		}

		@Override
		protected void reduce(Text arg0, Iterable<FloatWritable> arg1,
				Reducer<Text, FloatWritable, Text, FloatWritable>.Context arg2) throws IOException, InterruptedException {
			arg2.write(arg0, new FloatWritable(arg1.iterator().next().get()));
		}		
	}
	
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		//1. 获取配置对象信息
		Configuration configuration = new Configuration();
		//2. 对conf进行设置(没有就不用)、
		//3. 获取Job对象
		Job job = Job.getInstance(configuration, "myAvg");
		//4. 设置job的运行主类
		job.setJarByClass(wordcount.class);
		
		//5. 对map阶段进行设置
		job.setMapperClass(MyMapper.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(FloatWritable.class);
		
		FileInputFormat.addInputPath(job, new Path(args[0]));
		
		//6. reduce阶段进行设置
		job.setReducerClass(MyReduce.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(FloatWritable.class);
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		//7. 提交job作业
		int isOK = job.waitForCompletion(true)?0:1;
		//8. 退出j
		System.exit(isOK);		
	} 
}

9.4 awk的linux中脚本工具

数据源 | awk -F " " ‘BEGIN{} {} {} …END{}’

实例
对passwd文件中第3个数据大于等于500的时候,进行输出

cat /etc/passwd | awk -F ':' 'BEGIN{print "名字\t用户ID"} {if($3>=500) print $1, $3}'

9.5 MapReduce的shuffle过程

意思:洗牌或者弄乱
collections.shuffle(list):随机打乱参数list里的元素顺序
MapReduce里的shuffle:描述着数据从map task输出到reduce task输入的这段过程
在这里插入图片描述
在这里插入图片描述

9.7 分区案例

分片:block的一个逻辑组织。注意:10%的冗余,空文件也会做成一个分片,不可切割的文件会为一个片。
inputSplit的默认实现FileSplit。fileSplit将会被进行RecordReader。
分区:决定map阶段的输出交由哪一方reduce处理。分散map阶段输出的处理数据,将输出多个结果集。

自定义分区

  1. 分区需要继承Partitioner<Key, Value>, 其中的key-value需要和map阶段的输出相同。
  2. 实现getPartitioner(key, value, numPartitions)方法,该方法只能返回int类型。
  3. 分区数和reduce个数相同
  4. 默认使用hashPartiotioner

分区:Partitioner
输入数据
Hello Hi Hi
hi hello
163.com
qq.com
189.com
@163.com
@qq.com
*123.com

输出:
首字母为A-Z,a-z,0-9,其他分别放在不同的文件中
class partitionDemo:

package MapReduce;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.FloatWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;


/*
 * 分区:Partitioner
输入数据
Hello Hi Hi
hi hello
163.com
qq.com
189.com
@163.com
@qq.com
*123.com

输出:
首字母为A-Z,a-z,0-9,其他分别放在不同的文件中

结果文件:part-r-00000
Hello 2
Hi	2

结果文件:part-r-00001
hello	1
hi	1
qq.com	1

结果文件:part-r-00002
163.com	1
189.com	1


结果文件:part-r-00003
@163.com	1
@qq.com	1
*123.com	1

 * */

public class PartitionDemo {
	public static class MyMapper extends Mapper<LongWritable, Text, Text, Text>{
		
		@Override
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			
			String line = value.toString();
			String[] words = line.split(" ");
			for(String s:words) {
				context.write(new Text(s), new Text(1+""));
			}
		}
	}
	
	public static class MyReduce extends Reducer<Text, Text, Text, LongWritable>{
		
		@Override
		protected void reduce(Text arg0, Iterable<Text> arg1, Reducer<Text, Text, Text, LongWritable>.Context arg2)
				throws IOException, InterruptedException {
			
			int count = 0;
			for(Text num: arg1) {
				count += Integer.parseInt(num.toString());
			}
			arg2.write(arg0, new LongWritable(count));
		}
	}

	public static void setConf(Configuration conf) {
		//对conf属性进行设置
		conf.set("fs.defaultFS", "hdfs://tj");
		conf.set("dfs.nameservices", "tj");
		conf.set("dfs.ha.namenodes.tj", "nn1,nn2");
		conf.set("dfs.namenode.rpc-address.tj.nn1", "centos01:8020");
		conf.set("dfs.namenode.rpc-address.tj.nn2", "centos02:8020");
		conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
	}
	
	public static Configuration getConf() {
		return new Configuration();
		
	}
	
	public static int main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		Configuration configuration = getConf();
		setConf(configuration);
		
		Job job = Job.getInstance(configuration, "job");
		//4. 设置job的运行主类
		job.setJarByClass(PartitionDemo.class);
		
		//5. 对map阶段进行设置
		job.setMapperClass(MyMapper.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		
		//添加分区信息
		job.setPartitionerClass(MyPartioriner.class);
		//设置分区数目,一个reduce对应一个分区
		job.setNumReduceTasks(4);
		
		FileInputFormat.addInputPath(job, new Path(args[0]));
		
		
		//6. reduce阶段进行设置
		job.setReducerClass(MyReduce.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(LongWritable.class);
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		//7. 提交job作业
		int isOK = job.waitForCompletion(true)?0:1;
		//8. 退出j
		System.exit(isOK);		
				
		return 0;
	}

	
	
}

class MyPartitioner

package MapReduce;

import org.apache.hadoop.hdfs.util.StripedBlockUtil.StripeRange;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;

import com.sun.tools.javac.util.Context.Key;

/*
 * 自定以的partitioner
 * */

public class MyPartioriner extends Partitioner<Text, Text>{

	@Override
	public int getPartition(Text arg0, Text arg1, int arg2) {
		// TODO Auto-generated method stub
		
		String firstChar = arg0.toString().substring(0, 1);
		if(firstChar.matches("^[A-Z]")) {
			return 0%arg2;
		}else if(firstChar.matches("^[a-z]")) {
			return 1%arg2;
		}else if(firstChar.matches("^[0-9]")) {
			return 2%arg2;
		}else {
			return 3%arg2;
		}
	}
}

查看分区的运行结果
在这里插入图片描述

9.8 倒排索引

class daopaisuoying

package MapReduce;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;


/*
 * 倒排索引
 * 
 * 输入数据:
 * 1.html:
 * hadoop hadoop hadoop is good
 * 2.html:
 * hadoop hbase hbase is nice
 * 3.html:
 * hadoop hadoop hbase spark spark spark is better
 * 
 * 输出:
 * better 3.html:1
 * good 1.html:1
 * hadoop 1.html:3;2.html:1;3.html:2
 * hbase 2.html:2;3.html:1
 * is 1.html:1;2.html:1;3.html:1
 * nice 2.html:1
 * spark 3.html:3
 * 
 * */

public class daoPaiSuoYing {
	public static class MyMapper extends Mapper<LongWritable, Text, Text, Text>{
		
		@Override
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			
			//获取文件的名称
			InputSplit iSplit = context.getInputSplit();
			String name =((FileSplit)iSplit).getPath().getName();
			
			String line = value.toString();
			String[] words = line.split(" ");
			for(String s:words) {
				context.write(new Text(s+"_"+name), new Text(1+""));
			}
		}
		/*
		 * 输出:
		 * hadoop_1.html	1
		 * ...
		 * */
	}
	
	public static class MyReduce extends Reducer<Text, Text, Text, Text>{
		
		@Override
		protected void reduce(Text arg0, Iterable<Text> arg1, Reducer<Text, Text, Text, Text>.Context arg2)
				throws IOException, InterruptedException {
			
			/*
			 * hadoop<1.html:3,2.html:1,3.tml:2>
			 * ...
			 * */
			String string="";
			for(Text num:arg1) {
				string += num.toString()+";";
			}
			arg2.write(arg0, new Text(string.substring(0, string.length()- 1)));
		}
	}
	public static void setConf(Configuration conf) {
		//对conf属性进行设置
		conf.set("fs.defaultFS", "hdfs://tj");
		conf.set("dfs.nameservices", "tj");
		conf.set("dfs.ha.namenodes.tj", "nn1,nn2");
		conf.set("dfs.namenode.rpc-address.tj.nn1", "centos01:8020");
		conf.set("dfs.namenode.rpc-address.tj.nn2", "centos02:8020");
		conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
	}
	
	public static Configuration getConf() {
		return new Configuration();
		
	}
	
	public static int main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		Configuration configuration = getConf();
		setConf(configuration);
		
		Job job = Job.getInstance(configuration, "job");
		//4. 设置job的运行主类
		job.setJarByClass(daoPaiSuoYing.class);
		
		//设置combiner
		job.setCombinerClass(MYCombiner.class);
		
		//5. 对map阶段进行设置
		job.setMapperClass(MyMapper.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		
		FileInputFormat.addInputPath(job, new Path(args[0]));
				
		//6. reduce阶段进行设置
		job.setReducerClass(MyReduce.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		return job.waitForCompletion(true)?0:1;
	}
}


class myConbiner

package MapReduce;

import java.io.IOException;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class MYCombiner extends Reducer<Text, Text, Text, Text>{

	@Override
	protected void reduce(Text arg0, Iterable<Text> arg1, Reducer<Text, Text, Text, Text>.Context arg2)
			throws IOException, InterruptedException {
		// TODO Auto-generated method stub
		/**
		 * 输入:
		 * hadoop_1.html	1
		 * ...
		 * */
		
		String str[] = arg0.toString().split("_");
		int count = 0;
		for(Text num:arg1) {
			count = Integer.parseInt(num.toString());
		}
		arg2.write(new Text(str[0]), new Text(str[1] + ":"+count));
	}
}

运行

yarn jar /home/wordcount.jar MapReduce.daoPaiSuoYing /di /out/16

结果

在这里插入图片描述

9.9 TOP-N

  1. 自定义数据结构,类TopNWritable
package MapReduce;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.WritableComparable;

/*
 * 1. 自定义数据类型需要实现writable(不能排序),或者writableComparable(可排序)
 * 2. 实现该接口的相应方法write,readFields,compareTo
 * 3. write,readFields里面的字段个数和顺序要一致,类型需要匹配
 * 4. 可以重写toString,equal,等方法
 * */

public class TopNWritable implements WritableComparable<TopNWritable>{
	
	public String word;
	public int count;
	
	public TopNWritable() {}

	public TopNWritable(String word, int count) {
		super();
		this.word = word;
		this.count = count;
	}
	
	public String getWord() {
		return word;
	}

	public void setWord(String word) {
		this.word = word;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	//反序列化
	public void readFields(DataInput arg0) throws IOException {
		// TODO Auto-generated method stub
		this.word = arg0.readUTF();
		this.count = arg0.readInt();
		
	}

	//序列化
	public void write(DataOutput arg0) throws IOException {
		// TODO Auto-generated method stub
		arg0.writeUTF(this.word);
		arg0.writeInt(this.count);
		
	}

	public int compareTo(TopNWritable o) {
		// TODO Auto-generated method stub
		return o.count - this.count;
	}

//格式化输出
	@Override
	public String toString() {
		return "[" + word + "\t"+  count + "]";
	}
}

  1. 类TopNDemo
package MapReduce;

import java.io.IOException;
import java.util.TreeSet;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

/*
 * 倒排索引
 * 
 * 输入数据:
 * 1.html:
 * hadoop hadoop hadoop is good
 * 2.html:
 * hadoop hbase hbase is nice
 * 3.html:
 * hadoop hadoop hbase spark spark spark is better
 * 
 * 输出:
 * better 3.html:1
 * good 1.html:1
 * hadoop 1.html:3;2.html:1;3.html:2
 * hbase 2.html:2;3.html:1
 * is 1.html:1;2.html:1;3.html:1
 * nice 2.html:1
 * spark 3.html:3
 * 
 * */

public class TopNDemo {
	public static class MyMapper extends Mapper<LongWritable, Text, Text, Text>{
		
		@Override
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
				throws IOException, InterruptedException {
			
			String line = value.toString();
			String[] words = line.split(" ");
			for(String s:words) {
				context.write(new Text(s), new Text(1+""));
			}
		}
	}
	
	public static class MyReduce extends Reducer<Text, Text, TopNWritable, NullWritable>{
		
		//定义一个存储最终输出的容器
		public static final int Top_N = 3;
		
		@Override
		protected void cleanup(Reducer<Text, Text, TopNWritable, NullWritable>.Context context)
				throws IOException, InterruptedException {
			// TODO Auto-generated method stub
			//循环打印ts中的元素
			for(TopNWritable topNWritable:ts) {
				context.write(topNWritable, NullWritable.get());
			}
		}

		TreeSet<TopNWritable> ts=new TreeSet<TopNWritable>();
	
		@Override
		protected void reduce(Text arg0, Iterable<Text> arg1, Reducer<Text, Text, TopNWritable, NullWritable>.Context arg2)
				throws IOException, InterruptedException {
			int count = 0;
			for(Text t:arg1) {
				count += Integer.parseInt(t.toString());
			}
			//构造最终的输出类型
			TopNWritable tNWritable = new TopNWritable(arg0.toString(), count);
			
			//将tn对象添加到ts中
			ts.add(tNWritable);
			
			//如果ts里面的数据大于Top_N的时候将移除最后一个
			if(ts.size()>Top_N) {
				ts.remove(ts.last());
			}	
			
			//可能存在多个文件,每一个文件不能只输出一次,需要将所有的reduce结束后来进行输出
		}
	}
	
	
	
	public static void setConf(Configuration conf) {
		//对conf属性进行设置
		conf.set("fs.defaultFS", "hdfs://tj");
		conf.set("dfs.nameservices", "tj");
		conf.set("dfs.ha.namenodes.tj", "nn1,nn2");
		conf.set("dfs.namenode.rpc-address.tj.nn1", "centos01:8020");
		conf.set("dfs.namenode.rpc-address.tj.nn2", "centos02:8020");
		conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
	}
	
	public static Configuration getConf() {
		return new Configuration();
		
	}
	
	public static int main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		Configuration configuration = getConf();
		setConf(configuration);
		
		Job job = Job.getInstance(configuration, "job");
		//4. 设置job的运行主类
		job.setJarByClass(TopNDemo.class);
		
		
		//5. 对map阶段进行设置
		job.setMapperClass(MyMapper.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		
		FileInputFormat.addInputPath(job, new Path(args[0]));
				
		//6. reduce阶段进行设置
		job.setReducerClass(MyReduce.class);
		job.setOutputKeyClass(TopNWritable.class);
		job.setOutputValueClass(NullWritable.class);
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		return job.waitForCompletion(true)?0:1;
	}
}

运行结果

在这里插入图片描述

9.10 二次排序

结语

至此,对于hadoop框架以及后面的关于hive方面的知识暂时不进行学习,因为目前还不是很用的上这方面的知识。这里大概回顾一下hadoop的内容把。首先就是linux方面的内容,在hadoop的学习中对于linux的简单操作和系统有了初步的了解和入门。其次就是hdfs,hadoop中的分布式文件系统的搭建,然后就是yarn内容以及wordcount的计算方面知识,接着就是高可用ha方面。通过在windows中利用maven来对hdfs文件系统中的内容进行访问,已经通过java编写类似于wordcount这类的程序,对于hadoop的简单应用有了一定的了解。

暂时暂停关于hadoop课程的学习,后续如果继续接触和hadoop相关的内容,我会继续在这里进行更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值