官网文档
https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/SingleCluster.html
下载hadoop-3.1.3.tar.gz
https://www.apache.org/dyn/closer.cgi/hadoop/common/hadoop-3.1.3/hadoop-3.1.3.tar.gz
hadoop组成
yarn架构
ResourceManager (由多个nodeManager组成),可以理解为内存,cpu的集合。运行多个客户端提交的任务。这些任务运行在独立的容器(container)中。 每个nodeManager可以运行多个container
MapReduce
分为map和reduce两个过程。map将任务划分为多个子任务,分给多台机器执行;reduce是一个汇总结果的过程
HDFS
Hadoop Distribute File System.
HDFS,yarn,MapReduce三者的关系
有一个任务:比如从100T文件中找出xx.avi文件。
如何实现任务:MapReduce先向ResourceManager申请资源,Map到多个NodeManager。然后多个MapTask执行后将结果提交到DataNode最终汇总到HDFS。hadoop由NameNode和SecondryNameNode组成,主从架构。
推荐系统项目框架
安装hadoop
配置环境
vim /etc/profile
export HADOOP_HOME=/opt/hadoop_soft/hadoop-3.1.3
export PATH=$PATH:$HADOOP_HOME/bin
source /etc/profile
机器之间发送文件
scp -r hadoop-3.1.3 root@slave1:/opt/hadoop_soft/
scp 发送的文件 用户@机器:目的文件路径 (推模式)
scp -r root@slave1:/tmp/ ./test (master拉取slave1机器文件,拉模式)
集群
vim etc/hadoop/workers (master结点)
slave1
slave3
同理配置 slave1 的workers文件内容->
master
slave3
slave2 的workers文件 ->
master
slave1
xsync集群分发脚本
1)需求:循环复制文件到所有节点的相同目录下
2)需求分析:
a) rsync命令原始拷贝:
rsync -av /opt/hadoop_soft/hadoop root@slave1:/opt/hadoop_soft/
b) 期望脚本:
xsync 要同步的文件名称
c) 期望脚本在任何路径都能使用(脚本放在了全局环境变量的路径)
[root@master ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:。。。。。。。。。。。。。/root/bin
我打算把脚本放在/root/bin目录下。首先得创建一个/root/bin目录
然后cd /root/bin,新建一个脚本,名字随意取。
vim xsync
#!/bin/bash
# 1, 判断参数个数
if [ $# -lt 1 ]
then
echo Not Enough Arguement!
exit
fi
# 2, 遍历集群所有机器
for host in master slave1 slave3
do
echo ==== $host ====
# 3, 遍历所有目录,挨个发送.比如xsync a.txt b.txt 遍历a.txt和b.txt
for file in $@
do
# 4,判断文件是否存在
if [ -e $file ]
then
# 5, 获取父目录, -P适用于获取软链接的父目录
pdir=$(cd -P $(dirname $file); pwd)
# 6.获取当前文件名称
fname=$(basename $file)
ssh $host "mkdir -p $pdir"
rsync -av $pdir/$fname $host:$pdir
else
echo $file does not exists!
fi
done
done
赋予脚本权限 chmod 777 /root/bin/xsync
测试 (以下命令意思是将文件同步到其他节点, 其他节点存在该文件就覆写)
xsync xxfile1 xxfile2 ...
hadoop配置
启动dfs
sbin/start-dfs.sh
报错
Starting namenodes on [namenode] ERROR: Attempting to operate on hdfs namenode as root ERROR: but there is no HDFS_NAMENODE_USER defined ...
解决办法:
注意: 是在文件开始空白处!
在start-dfs.sh中
HDFS_DATANODE_USER=root
HDFS_DATANODE_SECURE_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root
修改stop-dfs.sh
[root@master sbin]# vi stop-dfs.sh
添加:
HDFS_DATANODE_USER=root
HDFS_DATANODE_SECURE_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root
在start-yarn.sh中
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root
修改stop-yarn.sh
[root@master sbin]# vi stop-yarn.sh
添加:
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root
core-site.xml
<configuration>
<!-- 指定hdfs的nameservice为ns1 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://master:9000</value>
</property>
<!-- Size of read/write buffer used in SequenceFiles. -->
<property>
<name>io.file.buffer.size</name>
<value>131072</value>
</property>
<!-- 指定hadoop临时目录,自行创建 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/hadoop_soft/hadoop-3.1.3/tmp</value>
</property>
</configuration>
fs.defaultFS为NameNode的地址。
hadoop.tmp.dir为hadoop临时目录的地址,默认情况下,NameNode和DataNode的数据文件都会存在这个目录下的对应子目录下。应该保证此目录是存在的,如果不存在,先创建。
hdfs-site.xml
<configuration>
<property>
<name> dfs.namenode.http-address </name>
<value>master:9870</value>
</property>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/opt/hadoop_soft/hadoop-3.1.3/hdfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/opt/hadoop_soft/hadoop-3.1.3/hdfs/data</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
mapreduce.framework.name设置mapreduce任务运行在yarn上。
### yarn-site.xml
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>master:8088</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>master</value>
</property>
</configuration>
hadoop-env.sh
export JAVA_HOME=/opt/jdk1.8.0_161
vi /etc/hosts
文件内,添加如下内容(具体还要看你的三台虚拟机的主机名和ip地址对应分别为,下面的只是我自己的)
192.168.109.11 master
192.168.109.22 slave1
192.168.109.33 slave3
初始化namenode
清理环境: 对三台机器处理:
删除hdfs目录及logs目录,清理历史数据。还有/tmp目录下的hadoop相关文件
如果配置了${hadoop_home}/tmp目录,还要删除该目录下(tmp/*)所有文件。
注意 用netstat -tlnp查看是否有hadoop相关端口未关闭
bin/hdfs namenode -format
启动master
sbin/start-all.sh (only master结点)
在master机器上启动datanode
hdfs --daemon start datanode //seems no necessary !
//扩容启动nodemanager yarn --daemon start nodemanager
关闭 sbin/stop-all.sh
查看状态
[root@master hadoop-3.1.4]# jps
7857 Jps
6934 DataNode
7158 SecondaryNameNode
7558 NodeManager
6796 NameNode
7421 ResourceManager
解决master ssh到slave1节点问题
$ ssh-copy-id -i slave1
访问 http://192.168.109.11:8088
访问 192.168.109.11:9870
查看文件状态
http://192.168.109.11:9870/explorer.html#/
当在该网站删除文件时 报错: Permission denied: user=dr.who, access=WRITE, inode="/":root:supergroup:drwxr-xr-x
vim core-site.xml
<property>
<name>hadoop.http.staticuser.user</name>
<value>root</value>
</property>
添加完成后分发给其他结点。然后重启集群
创建hdfs目录处理MapReduce任务
hdfs dfs -mkdir -p /user/root/input
复制文件到分布式系统
bin/hdfs dfs -put etc/hadoop/*.xml input
查看是否复制成功
hadoop fs -ls /user/root/input
执行任务:
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar grep input output ‘dfs[a-z.]+’
复制结果到本地,并检测
bin/hdfs dfs -get output output
cat output/*
结果错误Exit code: 127 Stack trace: ExitCodeException exitCode=127:
解决:创建软链接
ln -s $JAVA_HOME/bin/java /bin/java
验证 /bin/java -version
分别给slave1,slave3创建软连接
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:
解决:vim etc/hadoop/mapred-site.xml
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
发现是虚拟内存不足。由于我的物理内存为1个G,默认的虚拟内存率为2.1 .即虚拟内存为2.1G。任务需要的虚拟内存2.5G>2.1G,执行失败。
我将默认的虚拟内存率调到了3.1
vim etc/hadoop/mapred.site.xml
<property>
<name>yarn.nodemanager.vmem-pmem-ratio</name>
<value>3.1</value>
<source>yarn-default.xml</source>
</property>
分发给slave1,slave3
配置历史服务器
vim etc/hadoop/mapred-site.xml
mapreduce.jobhistory.address master:10020 mapreduce.jobhistory.webapp.address master:19888分发
一种更加精细化的启动
sbin/start-dfs.sh
sbin/start-yarn.sh
在master启动历史服务器
bin/mapred --daemon start historyserver
查看历史服务器是否启动 jps
发现多了一个JobHistoryserver进程
查看JobHistory
http://master:19888/jobhistory
日志聚集
<!--开启日志聚集-->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<!--设置日志聚集服务器地址-->
<property>
<name>yarn.log.server.url</name>
<value>http://master:19888/jobhistory/logs</value>
</property>
<!--日志保留7天-->
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>
分发
关闭HistoryServer
mapred --daemon stop historyserver
由于修改了yarn配置,关闭yarn 然后重启yarn
sbin/stop-yarn.sh ; sbin/start-yarn.sh
然后重启 HistoryServer : mapred --daemon start historyserver
验证日志是否生效
需要重新启动一个mapReduce任务
启动方式总结
1 整体启动/停止HDFS
start-dfs.hs/stop-dfs.sh
2 整体启动/停止YARN
start-yarn.sh/stop-yarn.sh
各个服务组件逐一启动/停止
1 启动,停止HDFS组件
hdfs --daemon start/stop namenode/datanode/secondarynamenode
2 启动,停止YARN
yarn --daemon start/stop resourcemanager/nodemanager
启动停止脚本
vim bin/myhadoop.sh
#!/bin/bash
if [ $# -lt 1 ]
then
echo "No Args input ...use 'start' or 'stop'"
exit;
fi
case $1 in
"start")
echo "---启动hadoop集群----"
echo "---启动hdfs---"
ssh master "/opt/hadoop_soft/hadoop-3.1.3/sbin/start-dfs.sh"
echo "---启动yarn---"
ssh master "/opt/hadoop_soft/hadoop-3.1.3/sbin/start-yarn.sh"
echo "---启动historyserver---"
ssh master "/opt/hadoop_soft/hadoop-3.1.3/bin/mapred --daemon start historyserver"
;;
"stop")
echo "---关闭hadoop集群---"
echo "---关闭hdfs---"
ssh master "/opt/hadoop_soft/hadoop-3.1.3/sbin/stop-dfs.sh"
echo "---关闭yarn---"
ssh master "/opt/hadoop_soft/hadoop-3.1.3/sbin/stop-yarn.sh"
echo "---关闭historyserver---"
ssh master "/opt/hadoop_soft/hadoop-3.1.3/bin/mapred --daemon stop historyserver"
;;
*)
echo "input Args Error...use 'start' or 'stop'"
;;
esac
配置时间服务器(集群不能连接外网时)
我没有配置,因为我机器能连网
1 主机器配置(必须root用户)
查看ntpd是否启动 systemctl status ntpd
修改ntpd.conf文件 vim /etc/ntp.conf . 内容变更如下
# 允许内网其他机器同步时间 (取消注释)
restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
# (注释掉)
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
# 外部时间服务器不可用时,以本地时间作为时间服务(添加)
server 127.127.1.0 # local clock
fudge 127.127.1.0 stratum 10
修改master的/etc/sysconfig/ntpd文件 vim /etc/sysconfig/ntpd
增加内容如下(让硬件时间与系统时间同步)
SYNC_HWCLOCK=yes
重启ntpd systemctl start ntpd
设置开机自启 systemctl enable ntpd
从机器配置 (必须root用户)
1 关闭所有从节点上ntp服务和自启动(slave1,slave3分别执行以下2条命令)
systemctl stop ntpd
systemctl disable ntpd
2 配置1分钟与时间服务器同步一次
crontab -e
编写定时任务如下:
*/1 * * * * /usr/sbin/ntpdate master
3 修改任意机器时间
date -s “2021-9-11 11:11:11”
4 1分钟后查看机器是否与时间服务器同步
date
hdfs客户端操作
一、下载winutils
winutils.exe主要用于模拟linux下的目录环境。当Hadoop在windows下运行或调用远程Hadoop集群的时候,需要该辅助程序才能运行
下载 https://github.com/s911415/apache-hadoop-3.1.0-winutils
二, 下载hadoop3.1.0.tar.gz解压到D:\hadoop\hadoop-3.1.0
解压hadoop3.1.0.tar.gz 过程出错。
解决:在C:\Program Files\WinRAR下右键点击winrar.exe,选择属性->兼容性,点击勾选以管理员身份运行框,再次解压。
1 将hadoop-3.1.0-winutils 目录下的bin目录copy到hadoop3.1.0.tar.gz解压后的bin目录,选择覆盖。这样winutils.exe等文件就在D:\hadoop\hadoop-3.1.0\bin目录了。
2 配置HADOOP_HOME环境变量
新建HADOOP_HOME变量,然后将HADOOP_HOME加入到PATH
点击PATH选项,新增一项 %HADOOP_HOME%\bin
三,来到HADOOP_HOME\bin目录,双击winutils.exe.如果没有报错,环境就配成功了。
windows本地运行mapReduce任务
linux集群运行mapreduce任务
1 打出jar包放到linux上
2 启动jar
hadoop jar xxx.jar org.yh.wordcount.WordCount /input /output
org.yh.wordcount.WordCount对应一个main函数入口类WordCount.java
/*
* @Description: 如果在linux上运行,将jar包发送。
* 运行命令: hadoop jar xx.jar org.yh.wordcount.WordCount /input /output
* 这里org.yh.wordcount.WordCount指定了main函数入口
*/
public class WordCount {
// static {
// try {
// // 加载库文件
// //解决启动错误 org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z
// System.load("D:\\hadoop\\hadoop-3.1.0\\bin\\hadoop.dll");
// } catch (UnsatisfiedLinkError e) {
// System.err.println("Native code library failed to load.\n" + e);
// System.exit(1);
// }
// }
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(WordCount.class);
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//设置输出的key,value类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//注意导包,使用MapReduce的FileInputFormat
FileInputFormat.setInputPaths(job,
// new Path("E:\\tmp\\hello.txt")
new Path(args[0])
);
FileOutputFormat.setOutputPath(job,
// new Path("E:\\tmp\\res")
new Path(args[1])
);
//提交job
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
/**
* LongWritable: input key type 固定
* Text : input value type 固定
* Text : output key type 相当于java基本类型中的String
* IntWritable : output value type 相当于int
*/
public static class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
private static Text word = new Text();
private static final IntWritable one = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] words = line.split(" ");
for (String w : words) {
word.set(w);
context.write(word, one);
}
}
}
/**
* Reducer<Text, IntWritable, Text, IntWritable>
* 输入kv和输出kv类型对应一致,Text IntWritable->Text IntWritable
*/
public static class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
private static IntWritable result = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
}