目标是在3台虚拟机上搭建一个Hadoop完全分布式集群。
集群规划如下:
| 192.168.56.107 | 192.168.56.108 | 192.168.56.109 | |
|---|---|---|---|
| HDFS | NameNode DataNode | SecondaryNameNode DataNode | DataNode |
| YARN | NodeManager | NodeManager | ResourceManager NodeManager |
基础环境
- mac系统
- virtualbox
- ubuntu20.04
- Hadoop3.x
基础环境准备
1. 创建3个虚拟机
- ubuntu-0 192.168.56.107
- ubuntu-1 192.168.56.108
- ubuntu-2 192.168.56.109
2. 开启ssh登陆
刚创建好的虚拟机默认不能ssh登陆,通过如下命令设置:
# 安装openssh
$ sudo apt-get install openssh-server openssh-client
# 启动
$ service ssh start
在mac上可以ssh登陆3台虚拟机,但是需要密码
注意:
这个时候使用iTerm工具,可以在mac上同步分发命令到多个会话,效果如下:
我们后续的命令默认都是操作三个节点,如果需要只在一个节点执行的命令,会单独说明
3. 解决vim问题
刚创建好的系统默认安装的是vim tiny版本,按键与显示不符,解决办法如下:
# Ubuntu预装的是vim tiny版本,需要删除后安装完整版
$ sudo apt-get remove vim-common
$ sudo apt-get install vim
4. Java环境搭建
# 因为我是下载到mac上了,因此需要上传java到ubuntu
$ scp mouse@192.168.1.12:/Users/mouse/Downloads/jdk-8u291-linux-x64.tar.gz /home/mouse/java
配置Java环境
$ vi ~/.bash_profile
加入如下2行代码
export JAVA_HOME=/home/mouse/java/jdk1.8.0_291
export PATH=$PATH:$JAVA_HOME/bin
使得代码生效,需要source一下
$ source ~/.bash_profile
验证java
$ java -version
Hadoop环境搭建
1. 配置ssh免密登陆
ubuntu可以在"设置"->"共享"里更改主机名hostname
这三台虚拟机分别命名为
- master
- slave1
- slave2
此外,在配置下host
# 修改hosts文件
$ vi /etc/hosts
加入如下内容
192.168.56.107 master
192.168.56.108 slave1
192.168.56.109 slave2
生成文件
$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
复制到其他节点
$ ssh-copy-id -i master
$ ssh-copy-id -i slave1
$ ssh-copy-id -i slave2
2. Hadoop四个配置文件
Hadoop有4个包含所有配置的配置文件,分别是:
- core-default.xml
- hdfs-default.xml
- yarn-default.xml
- mapred-default.xml
但有一些配置是需要我们设置的,这4个文件如下:
- etc/hadoop/core-site.xml
- etc/hadoop/hdfs-site.xml
- etc/hadoop/yarn-site.xml
- etc/hadoop/mapred-site.xml
3. etc/hadoop/core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://master:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/mouse/hadoop/log/hadoop_dir</value>
</property>
</configuration>
4. etc/hadoop/hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/home/mouse/hadoop/log/hadoop_dir/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/home/mouse/hadoop/log/hadoop_dir/dfs/data</value>
</property>
<property>
<name>dfs.namenode.http-address</name>
<value>master:9870</value>
</property>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>slave1:9868</value>
</property>
</configuration>
5. etc/hadoop/yarn-site.xml
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>slave2</value>
</property>
<!-- 命令行执行hadoop classpath得到的值-->
<property>
<name>yarn.application.classpath</name>
<value>$hadoop classpath</value>
</property>
</configuration>
6. etc/hadoop/mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
7. hadoop-env.sh
export JAVA_HOME=/home/mouse/java/jdk1.8.0_291
8. workers
master
slave1
slave2
启动
1. 格式化
首次启动需要格式化namenode(注意:只在namenode服务器执行)
$ hadoop namenode -format
2. 启动
# 在namenode服务器执行
$ start-dfs.sh
# 在resourcemanager服务器执行
$ start-yarn.sh
停止
# 在namenode服务器执行
$ stop-yarn.sh
# 在resourcemanager服务器执行
$ stop-dfs.sh
快捷命令(不推荐)
$ start-all.sh
$ stop-all.sh
验证
1. 通过jps验证
$ jps
结果如下图,说明全部启动成功了,符合预期
2. 通过网页验证
# NameNode
http://master:9870
# ResourceManager
http://slave2:8042
上传文件到HDFS
只在namenode节点上执行
# /home/mouse/test.txt是本地路径 /是hdfs路径
$ hadoop dfs -put /home/mouse/test.txt /
访问http://master:9870/查看我们上传的文件,可以发现有3个副本,分别位于三个节点:
提交mapreduce任务并运行
1. 编写程序
程序很简单,代码如下:
public class WordCount {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
if (args.length != 2) {
System.err.println("Usage: WordCount <input path> <output path>");
System.exit(-1);
}
//指定作业执行规范 控制整个作业的运行
Job job = new Job();
job.setJarByClass(WordCount.class);
job.setJobName("Word Count");
//输入数据的路径
FileInputFormat.addInputPath(job, new Path(args[0]));
//输出数据的路径 必须不存在
FileOutputFormat.setOutputPath(job, new Path(args[1]));
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
static class WordCountMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
@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) {
context.write(new Text(w), new LongWritable(1));
}
}
}
static class WordCountReducer extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
long counter = 0;
for (LongWritable l : values) {
counter += l.get();
}
context.write(key, new LongWritable(counter));
}
}
}
2. 打包
使用IDEA工具
打包设置,参考如下截图:
配置完成后,在"Build"->"Build Artifacts"即可
3. 上传并执行
上传jar包
# 上传jar包
$ hdfs dfs -put [jar path] /
执行
# 必须使用全路径类名
# 输出目录必须不存在
$ hadoop jar word-count.jar com.mouse.word.count.WordCount /test.txt /user/mouse/wordcount
Done~