本文主要记录Mac下如何进行Hadoop伪分布模式安装,并经过词频统计Demo程序(WordCount)理解MapReduce的原理。html
Hadoop和Spark是两种不一样的大数据处理框架,以下图所示。java
Hadoop 一般包括2个部分:存储和处理。存储部分就是Hadoop的分布式文件系统(HDFS),处理指的是MapReduce(MP)。node
Hadoop 安装模式分为3种,分别是单机模式,伪分布模式和全分布模式。默认安装是单机模式。能够经过配置文件 core-site.xml
,将默认的单机模式更改成伪分布模式。git
关于Hadoop 3种安装模式和如何使用虚拟机进行分布式安装,能够参考《Hadoop应用技术详解》书籍的第2章节——Hadoop安装。github
Hadoop 的运行方式是由配置文件决定的,所以若是须要从伪分布式模式切换回非分布式模式,须要删除
core-site.xml
中的配置项。算法
下面简单记录,如何经过修改配置文件,在 Mac 上搭建伪分布模式 Hadoop 环境。shell
Hadoop的安装和配置步骤以下(具体细节参考上述参考连接)数据库
ssh localhost
进行验证。hadoop 2.10.0
。将下载的 .tar.gz
压缩包解压并放置到 /Library/hadoop-2.10.0
路径。(1) 打开配置文件apache
vim ~/.bash_profile
复制代码
(2) 设置环境变量vim
HADOOP_HOME=/Library/hadoop-2.10.0
PATH=$PATH:${HADOOP_HOME}/bin
HADOOP_CONF_DIR=/Library/hadoop-2.10.0/etc/hadoop
HADOOP_COMMON_LIB_NATIVE_DIR=/Library/hadoop-2.10.0/lib/native
export HADOOP_HOME
export PATH
export HADOOP_CONF_DIR
export HADOOP_COMMON_LIB_NATIVE_DIR
复制代码
(3) 使配置文件生效,并验证Hadoop版本号
source ~/.bash_profile
hadoop version
复制代码
须要修改的 Hadoop 配置文件都在目录 etc/hadoop
下,包括
hadoop-env.sh
core-site.xml
hdfs-site.xml
mapred-site.xml
yarn-site.xml
下面逐步进行修改
(1) 修改 hadoop-env.sh
文件
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home
export HADOOP_HOME=/Library/hadoop-2.10.0
export HADOOP_CONF_DIR=/Library/hadoop-2.10.0/etc/hadoop
复制代码
(2) 修改 core-site.xml
文件
设置 Hadoop 的临时目录和文件系统,localhost:9000
表示本地主机。若是使用远程主机,要用相应的 IP 地址来代替,填写远程主机的域名,则须要到 /etc/hosts
文件中作 DNS 映射。
<configuration>
<!--localhost:9000 表示本地主机-->>
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
<!--用来指定hadoop运行时产生文件的存放目录 本身建立-->
<property>
<name>hadoop.tmp.dir</name>
<value>/Users/lbs/devfiles/hadoop/hadoop-2.10.0/tmp</value>
<description>Directories for software develop and save temporary files.</description>
</property>
</configuration>
复制代码
(3) 修改 hdfs-site.xml
文件
hdfs-site.xml
指定了 HDFS 的默认参数副本数,由于仅运行在一个节点上(伪分布模式),因此这里的副本数为1。
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<!--不是root用户也能够写文件到hdfs-->
<property>
<name>dfs.permissions</name>
<value>false</value> <!--关闭防火墙-->
</property>
<!--把路径换成本地的name位置-->
<property>
<name>dfs.namenode.name.dir</name>
<value>/Users/lbs/devfiles/hadoop/hadoop-2.10.0/tmp/dfs/name</value>
</property>
<!--在本地新建一个存放hadoop数据的文件夹,而后将路径在这里配置一下-->
<property>
<name>dfs.datanode.data.dir</name>
<value>/Users/lbs/devfiles/hadoop/hadoop-2.10.0/tmp/dfs/data</value>
</property>
</configuration>
复制代码
(4) 修改 mapred-site.xml
文件
复制 mapred-site.xml.template
模板文件,并修改成 mapred-site.xml
文件,而后将 yarn
设置成数据处理框架,并设置 JobTracker 的主机名与端口。
<configuration>
<property>
<!--指定mapreduce运行在yarn上-->
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
复制代码
(5) 修改 yarn-site.xml
文件
配置数据的处理框架 yarn
<configuration>
<!-- Site specific YARN configuration properties -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.address</name>
<value>localhost:9000</value>
</property>
</configuration>
复制代码
(1) 第一次启动Hadoop,须要对 NameNode 进行格式化,后续启动再也不须要执行此步骤。
hadoop namenode -format
复制代码
(2) 启动 HDFS:进入Hadoop 安装目录下的 sbin
目录,并启动HDFS(须要设置Mac容许远程登陆,过程当中共须要3次输入密码)
Tip: 初次安装和启动时,能够执行
./start-all.sh
,进行必要的初始化安装
cd /Library/hadoop-2.10.0/sbin
./start-dfs.sh
复制代码
若出现下述信息,表示启动成功
lbsMacBook-Pro:sbin lbs$ ./start-dfs.sh
Starting namenodes on [localhost]
Password:
localhost: namenode running as process 12993. Stop it first.
Password:
localhost: datanode running as process 32400. Stop it first.
Starting secondary namenodes [0.0.0.0]
Password:
0.0.0.0: Connection closed by 127.0.0.1 port 22
复制代码
须要注意的是,在log
中会显示警告
WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicabled的
复制代码
上述提醒是关于 Hadoop 本地库的——Hadoop本地库是为了提升效率或者某些不能用Java实现的功能组件库。能够参考 Mac OSX 下 Hadoop 使用本地库提升效率 了解详情。
中止 Hadoop 方法以下
cd /Library/hadoop-2.10.0/sbin
./sbin/stop-dfs.sh
复制代码
(3) 在终端执行 jps
,若看到以下信息,证实 Hadoop 能够成功启动。看到 DataNode
,NameNode
和 SecondaryNameNode
信息,代表启动的是一个伪分布模式Hadoop。
lbsMacBook-Pro:sbin lbs$ jps
32400 DataNode
12993 NameNode
30065 BootLanguagServerBootApp
13266 SecondaryNameNode
30039 org.eclipse.equinox.launcher_1.5.700.v20200207-2156.jar
35019 ResourceManager
35117 NodeManager
32926 RunJar
35199 Jps
复制代码
也能够访问 http://localhost:50070/dfshealth.html#tab-overview
来查看 Hadoop的启动状况。看到 Live Node
参数,证实伪分布模式 Hadoop 启动成功。
(4) 启动 yarn:进入Hadoop 安装目录下的 sbin
目录,并启动 yarn
cd /Library/hadoop-2.10.0/sbin
./start-yarn.sh
复制代码
至此,Hadoop的安装,配置和启动就完成啦!接下来能够经过一些 shell 命令来操做 Hadoop 下的文件了,例如
hadoop fs -ls /        查看根目录下的文件及文件夹
hadoop fs -mkdir /test 在根目录下建立一个文件夹 testdata
hadoop fs -rm /.../... 移除某个文件
hadoop fs -rmr /... 移除某个空的文件夹
复制代码
在启动 HDFS时,若看到以下警告
./start-dfs.sh
复制代码
lbsMacBook-Pro:~ lbs$ cd /Library/hadoop-2.10.0/sbin
lbsMacBook-Pro:sbin lbs$ ./start-dfs.sh
20/03/23 08:46:43 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Starting namenodes on [localhost]
Password:
localhost: namenode running as process 93155. Stop it first.
Password:
localhost: datanode running as process 93262. Stop it first.
Starting secondary namenodes [0.0.0.0]
Password:
0.0.0.0: secondarynamenode running as process 93404. Stop it first.
复制代码
上述提醒是关于 Hadoop 本地库的——Hadoop本地库是为了提升效率或者某些不能用Java实现的功能组件库。能够参考 Mac OSX 下 Hadoop 使用本地库提升效率 了解详情。
pom.xml
中添加以下依赖<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.lbs0912</groupId>
<artifactId>wordcount</artifactId>
<version>1.0-SNAPSHOT</version>
<!--添加 apache 镜像源-->
<repositories>
<repository>
<id>apache</id>
<url>http://maven.apache.org</url>
</repository>
</repositories>
<!--添加以下依赖-->
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.2</version>
</dependency>
</dependencies>
</project>
复制代码
WordMapper
类package wordcount;
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class WordMapper extends Mapper<Object, Text, Text, IntWritable> {
IntWritable one = new IntWritable(1);
Text word = new Text();
public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
}
复制代码
WordReducer
类package wordcount;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WordReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
private IntWritable result = new IntWritable();
public 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);
}
}
复制代码
WordMain
驱动类package wordcount;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class WordMain {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
/**
* 这里必须有输入/输出
*/
if (otherArgs.length != 2) {
System.err.println("Usage: WordCount <in> <out>");
System.exit(2);
}
Job job = new Job(conf, "wordcount");
job.setJarByClass(WordMain.class); //主类
job.setMapperClass(WordMapper.class); //Mapper
job.setCombinerClass(WordReducer.class); //做业合成类
job.setReducerClass(WordReducer.class); //Reducer
job.setOutputKeyClass(Text.class); //设置做业输出数据的关键类
job.setOutputValueClass(IntWritable.class); //设置做业输出值类
FileInputFormat.addInputPath(job, new Path(otherArgs[0])); //文件输入
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1])); //文件输出
System.exit(job.waitForCompletion(true) ? 0 : 1); //等待完成退出
}
}
复制代码
选择 Run -> Edit Configurations
, 在程序参数栏目中输入 input/ output
,以下图所示
在 input
目录中添加统计单词个数的测试的文件 wordcount1.txt
Hello,i love coding
are you ok?
Hello, i love hadoop
are you ok?
复制代码
再次运行程序,会看到以下的 output
目录结构
- input
- output
| - ._SUCCESS.crc
| - .part-r-00000.crc
| - ._SUCCESS
| - part-r-00000
复制代码
打开 part-r-00000
文件,便可看到单词出现次数的统计结果
Hello, 1
Hello,i 1
are 2
coding 1
hadoop 1
i 1
love 2
ok? 2
you 2
复制代码
须要注意的是,因为Hadoop的设定,下次运行程序前,须要先删除output文件目录。
File -> Project Structure
选项中,为工程添加 Artifacts
,选择 WordMain
类Build -> Build Artifacts...
,生成 .jar
文件hadoop jar WordCount.jar input/ out/
复制代码
HDFS(Hadoop Distributed File System
)是一个用在普通硬件设备上的分布式文件系统。 HDFS 具备高容错性(fault-tolerant
)和高吞吐量(high throughput
),适合有超大数据集的应用程序,能够实现经过流的形式访问文件系统中的数据。
运行在HDFS之上的应用程序必须流式地访问它们的数据集,它不是典型的运行在常规的文件系统之上的常规程序。HDFS的设计适合批量处理,而不是用户交互式的,重点是数据吞吐量,而不是数据访问的反应时间。
HDFS以块序列的形式存储每个文件,文件中除了最后一个块的其余块都是相同的大小。
HDFS 为Hadoop 这个分布式计算框架一共高性能,高可靠,高可扩展的存储服务。HDFS是一个典型的主从架构,一个HDFS集群是由一个主节点(Namenode
)和必定数目的从节点(Datanodes
)组成。
namespace
)以及客户端对文件的访问。同时肯定块和数据节点的映射。
metadata
信息,包括文件 owership
和 permissions
,文件包含有哪些块,Block
保存在哪一个 DataNode
等metadata
信息在启动后会加载到内存中Rack
):一个 Block 的三个副本一般会保存到两个或者两个以上的机架中,进行防灾容错Block
)是 HDFS 文件系统基本的存储单位,Hadoop 1.X 默认大小是 64MB,Hadoop 2.X 默认大小是 128MB。HDFS上的文件系统被划分为块大小的多个分块(Chunk
)做为独立的存储单元。和其余文件系统不一样的是,HDFS上小于一个块大小的文件不会占据整个块的空间。使用块抽象而非整个文件做为存储单元,大大简化了存储子系统的设计。SecondaryNameNode
)负责镜像备份,日志和镜像的按期合并。使用
hadoop fsk / -files -blocks
能够显示块的信息。
Block 数据块大小设置的考虑因素包括
Block 是 HDFS 文件系统的最小组成单元,它经过一个 Long
整数被惟一标识。每一个 Block 会有多个副本,默认有3个副本。为了数据的安全和高效,Hadoop 默认对3个副本的存放策略以下图所示
这样的策略能够保证对该 Block 所属文件的访问可以优先在本 Rack 下找到。若是整个 Rack 发生了异常,也能够在另外的 Rack 找到该 Block 的副本。这样足够高效,而且同时作到了数据的容错。
RPC(Remote Procedure Call
)即远程过程调用机制会面临2个问题
RPC 架构以下图所示。Hadoop 本身实现了简单的 RPC 组件,依赖于 Hadoop Writable
类型的支持。
Hadoop Writable
接口要求每一个实现类多要确保将本类的对象正确序列化(writeObject
)和反序列化(readObject
)。所以,Hadoop RPC 使用 Java 动态代理和反射实现对象调用方式,客户端到服务器数据的序列化和反序列化由 Hadoop框架或用户本身来实现,也就是数据组装定制的。
Hadoop RPC = 动态代理 + 定制的二进制流
HBase 的特色以下
有句话说得好,“大数据胜于算法”,意思是说对于某些应用(例如根据以往的偏好来推荐电影和音乐),不论算法有多牛,基于小数据的推荐效果每每都不如基于大量可用数据的通常算法的推荐效果。 —— 《Hadoop 权威指南》