Hadoop

HDFS文件系统

HDFS是一个分布式文件系统,采用分而治之的设计思想,将大文件、大批量文件,分布式存放在大量服务器上,为各类分布式运算框架(MapReduce,spark,tez等)提供数据存储服务。首先,它是一个文件系统,用于存储文件,通过统一的命名空间目录树来定位文件,对用户来说,DataNode是透明的,HDFS相当于是提供了一个统一的目录结构,用户上传的文件的适合,只需要和这个统一的目录结构打交道,虽然实际上用户的文件被切成不同的block存放在了不同的DataNode上,这部分元信息被存放在NameNode中;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。

虚拟机网络配置

HDFS

基本特性

适合用来做数据分析,并不适合用来做网盘应用,因为,不便修改,延迟大,网络开销大,成本太高

  1. HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数(dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M;
  2. HDFS文件系统会给客户端提供一个统一的抽象目录树,客户端通过路径来访问文件,形如:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data
  3. 目录结构及文件分块信息(元数据)的管理由NameNode节点承担。NameNode是HDFS集群主节点,负责维护整个hdfs文件系统的目录树,以及每一个路径(文件)所对应的block块信息(block的id,及所在的DataNode服务器);
  4. 文件的各个block的存储管理由DataNode节点承担。DataNode是HDFS集群从节点,每一个block都可以在多个DataNode上存储多个副本(副本数量也可以通过参数设置dfs.replication);
  5. HDFS是设计成适应一次写入,多次读出的场景,且不支持文件的修改;

常见命令

// 列出文件
hadoop fs -ls /

// 创建目录
hadoop fs -mkdir 目录名称

// 查看文件
hadoop fs -cat 文件名称

// 删除文件或文件夹
hadoop fs -rm -r /aaa/bbb/

// 从本地文件系统中拷贝文件到hdfs路径去
hadoop  fs  -copyFromLocal  ./jdk.tar.gz  /aaa/
// 上传,等同于copyFromLocal
hadoop  fs  -put  /aaa/jdk.tar.gz  /bbb/jdk.tar.gz.2

// 从hdfs拷贝到本地
hadoop fs -copyToLocal /aaa/jdk.tar.gz
// 从hdfs下载文件到本地,等同于copyToLocal 
hadoop fs -get  /aaa/jdk.tar.gz

// 统计文件系统的可用空间信息
hadoop  fs  -df  -h  /

// 统计文件夹的大小信息
hadoop  fs  -du  -s  -h /aaa/*

// 统计一个指定目录下的文件节点数量
hadoop fs -count /aaa/

// 设置hdfs中文件的副本数量,这里设置的副本数只是记录在NameNode的元数据中,是否真的会有这么多副本,还得看DataNode的数量
hadoop fs -setrep 3 /aaa/jdk.tar.gz

常用参数

hdfs-site.xml

// 每个block块的大小,默认128M
dfs.blocksize

// 文件副本个数
dfs.replication

工作机制

  1. HDFS集群分为两大角色:NameNode、DataNode;
  2. NameNode负责管理整个文件系统的元数据;
  3. DataNode负责管理用户的文件数据块;
  4. 文件会按照固定的大小(blocksize)切成若干块后分布式存储在若干台DataNode上;
  5. 每一个文件块可以有多个副本,并存放在不同的DataNode上;
  6. DataNode会定期向NameNode汇报自身所保存的文件block信息,而NameNode则会负责保持文件的副本数量;
  7. HDFS的内部工作机制对客户端保持透明,客户端请求访问HDFS都是通过向NameNode申请来进行;

NameNode机制

NameNode职责:负责客户端请求的响应;元数据的管理(查询,修改);

NameNode对数据的管理采用了三种存储形式:

  • 内存元数据(NameSystem);
  • 磁盘元数据镜像文件;
  • 数据操作日志文件(可通过日志运算出元数据);
元数据管理机制
  • 内存中有一份完整的元数据:内存meta data
  • 磁盘有一个“准完整”的元数据镜像:fsimage,文件存在于NameNode的工作目录中;
  • 用于衔接内存metadata和持久化元数据镜像fsimage之间的操作日志:edits文件,当客户端对HDFS中的文件进行新增或者修改操作,操作记录首先被记入edits日志文件中,当客户端操作成功后,相应的元数据会更新到内存meta.data中;
元数据checkpoint

每隔一段时间,会由SecondaryNameNode将NameNode上积累的所有edits和一个最新的fsimage下载到本地,并加载到内存进行merge,这个过程称为checkpoint。
NameNode和SecondaryNameNode的工作目录存储结构完全相同,所以,当NameNode故障退出需要重新恢复时,可以从SecondaryNameNode的工作目录中将fsimage拷贝到NameNode的工作目录,以恢复NameNode的元数据。

checkpoint参数
dfs.namenode.checkpoint.check.period=60  #检查触发条件是否满足的频率,60秒
dfs.namenode.checkpoint.dir=file://${hadoop.tmp.dir}/dfs/namesecondary
#以上两个参数做checkpoint操作时,secondary namenode的本地工作目录
dfs.namenode.checkpoint.edits.dir=${dfs.namenode.checkpoint.dir}

dfs.namenode.checkpoint.max-retries=3  #最大重试次数
dfs.namenode.checkpoint.period=3600  #两次checkpoint之间的时间间隔3600秒
dfs.namenode.checkpoint.txns=1000000 #两次checkpoint之间最大的操作记录

DataNode机制

Datanode工作职责:存储管理用户的文件块数据;定期向NameNode汇报自身所持有的block信息(通过心跳信息上报),这点很重要,因为当集群中发生某些block副本失效时,集群如何恢复block初始副本数量的问题。

<property>
    <name>dfs.blockreport.intervalMsec</name>
    <value>3600000</value>
    <description>Determines block reporting interval in milliseconds.</description>
</property>
DataNode掉线判断时限参数

DataNode进程死亡或者网络故障造成DataNode无法与NameNode通信,NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。HDFS默认的超时时长为10分钟+30秒。如果定义超时时间为timeout,则超时时长的计算公式为:

timeout  = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval

而默认的heartbeat.recheck.interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。
需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。所以,举个例子,如果heartbeat.recheck.interval设置为5000(毫秒),dfs.heartbeat.interval设置为3(秒,默认),则总的超时时间为40秒。

<property>
    <name>heartbeat.recheck.interval</name>
    <value>2000</value>
</property>
<property>
    <name>dfs.heartbeat.interval</name>
    <value>1</value>
</property>

文件上传机制

用户上传的文件,被切成诺干个block块存放在不同的DataNode中,并且每个文件都会在集群中存储多个文件副本,副本的数量可以由用户指定。至于文件被切成多少个block快,每个块在哪台DataNode上,这部分元信息存储在NameNode中。
客户端要向HDFS写数据,首先要跟NameNode通信以确认可以写文件并获得接收文件block的DataNode,然后,客户端按顺序将文件逐个block传递给相应DataNode,并由接收到block的DataNode负责向其他DataNode复制block的副本。

  1. 根NameNode通信请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在;
  2. NameNode返回是否可以上传;
  3. client请求第一个block该传输到哪些datanode服务器上;
  4. NameNode返回3个DataNode服务器ABC;
  5. client请求3台dn中的一台A上传数据(本质上是一个RPC调用,建立pipeline),A收到请求会继续调用B,然后B调用C,将真个pipeline建立完成,逐级返回客户端;
  6. client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,A收到一个packet就会传给B,B传给C;A每传一个packet会放入一个应答队列等待应答;
  7. 当一个block传输完成之后,client再次请求NameNode上传第二个block的服务器;

文件下载机制

客户端将要读取的文件路径发送给NameNode,NameNode获取文件的元信息(主要是block的存放位置信息)返回给客户端,客户端根据返回的信息找到相应DataNode逐个获取文件的block并在客户端本地进行数据追加合并从而获得整个文件。

  1. 跟NameNode通信查询元数据,找到文件块所在的DataNode服务器;
  2. 挑选一台DataNode(就近原则,然后随机)服务器,请求建立socket流;
  3. DataNode开始发送数据(从磁盘里面读取数据放入流,以packet为单位来做校验);
  4. 客户端以packet为单位接收,现在本地缓存,然后写入目标文件;

HDFS客户端编程场景

  • 数据采集

YARN

运算资源调度。
MapReduce程序应该是在很多机器上并行启动,而且先执行MapTask,当众多的MapTask都处理完自己的数据后,还需要启动众多的ReduceTask,这个过程如果用用户自己手动调度不太现实,需要一个自动化的调度平台,hadoop中就为运行MapReduce之类的分布式运算程序开发了一个自动化调度平台:YARN。

YARN集群中有两个角色:1台 ResourceManager 和 N台 NodeManager。ResourceManager一般安装在一台专门的机器上,NodeManager应该与HDFS中的DataNode重叠在一起。
yarn-site.xml

<property>
    <name>yarn.resourcemanager.hostname</name>
    <value>hdp-04</value>
</property>

<property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
</property>

Linux环境准备

接下来主要介绍Hadoop集群环境的搭建过程,实际应用中应该不会这样做,而是通过一些管理工具进行安装,比如可视化安装:Ambari。


虚拟机镜像
软件安装包

前置条件

  • CentOS7

  • Oracle VM VirtualBox

安装过程

这就相当于通过虚拟机搭建一个局域网,安装配置过程已经截图并整理成PPT。主要需要注意的地方就是网络的配置,我这里通过配置两个网卡来实现:一个用于访问外部网络(NAT);一个用于和window主机交互(Host-Only)。



我的系统是centos7

vi /etc/sysconfig/network-scripts/ifcfg-enp0s3

配置文件修改成以下内容

TYPE=Ethernet

PROXY_METHOD=none

BROWSER_ONLY=no

BOOTPROTO=static

DEFROUTE=yes

IPV4_FAILURE_FATAL=no

IPV6INIT=yes

NAME=enp0s3

UUID=4704faea-0e23-4ad9-a06c-3e37e577636c

DEVICE=enp0s3

ONBOOT=yes

NM_CONTROLLED=yes

IPADDR=192.168.88.21

虚拟机安装过程

基础配置

添加用户

分别在三台服务器上执行创建 haddop用户,同时设置密码为hadoop

useradd hadoop

passwd hadoop

创建用户之后切换为hadoop用户登录,我们所有的操作都基于hadoop用户

配置host

分别在三台服务器配置host

vi /etc/hosts

添加以下内容

192.168.88.21 master

192.168.88.22 slave1

192.168.88.23 slave2

配置免密登录

分别在三台机器上安装 openssh-server

yum install openssh-server

分别在三台机器上执行以下命令

mkdir .ssh
chmod 700 .ssh
ssh-keygen -t rsa
cp id_rsa.pub authorized_keys
chmod 600 authorized_keys

在 22 服务器执行

scp /home/hadoop/.ssh/id_rsa.pub hadoop@master:/home/hadoop/.ssh/id_rsa.pub.slave1

在 23 服务器执行

scp /home/hadoop/.ssh/id_rsa.pub hadoop@master:/home/hadoop/.ssh/id_rsa.pub.slave2

在 21 服务器执行

cat id_rsa.pub.slave1 >> authorized_keys

cat id_rsa.pub.slave2 >> authorized_keys

scp /home/hadoop/.ssh/authorized_keys hadoop@slave1:/home/hadoop/.ssh/authorized_keys

scp /home/hadoop/.ssh/authorized_keys hadoop@slave2:/home/hadoop/.ssh/authorized_keys

至此配置完成,接下来是测试:

在 21 服务器执行

ssh salve1
ssh salve2

有个问题,之前配置好了之后还是不停提示要输入密钥,然后安装了 openssh-server 之后,再测试就可以了,不知道是不是这个的影响。

配置JDK

jdk-8u171-linux-x64.tar.gz

在/home/hadoop 目录下创建java文件夹

mkdir java

在java 目录内解压安装包

tar -zxvf jdk-8u171-linux-x64.tar.gz

然后分别拷贝到两台slave

scr -r jdk1.8 hadoop@slave1:/home/hadoop
scr -r jdk1.8 hadoop@slave2:/home/hadoop

分别在三台机器上配置JAVA_HOME

export JAVA_HOME=/home/hadoop/jdk1.8

export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar

:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

export PATH=$PATH:$JAVA_HOME/bin

测试:

执行 java -version 看控制台输出

其它配置

修改windos下的hosts文件,因为到时候再浏览器上访问的时候会用到域名

C:\WINDOWS\System32\drivers\etc\hosts

192.168.88.21 master

192.168.88.22 slave1

192.168.88.23   slave2

修改linux系统的hostname,注意不是修改/etc/hoss文件,centos7永久修改hostname使用以下命令

hostnamectl set-hostname 名称

安装Hadoop

下载安装

1、官网下载,这个地址下载有点慢

http://apache.claz.org

2、以下的地址下载更快一些

http://mirror.bit.edu.cn/apache/

http://mirror.bit.edu.cn/apache/

https://mirrors.tuna.tsinghua.edu.cn/apache/

我最终下载的版本是:hadoop-2.7.6.tar.gz

安装过程很简单,只需要直接解压就可以了。

三台机器机器最终的配置基本一样,所以我们只需要在一台机器上配置好,然后拷贝到其它机器就好, 这里是在master机器上配置。

在master上执行以下命令

cd /home/Hadoop

mkdir -p cludata/hadoop

cd cludata/hadoop

mkdir -p hdfs/data hdfs/name temp

tar -zxvf hadoop-2.7.6.tar.gz

HADOOP_HOME

就是配置hadoop环境变量,这个需要在三台机器上分别执行

vi ~/.bash_profile

export HADOOP_HOME=/home/hadoop/hadoop-2.7.6

export PATH=$PATH:$JAVA_HOME/bin::$HADOOP_HOME/bin:$HADOOP_HOME/sbin

配置文件

主要需要配置以下几个配置文件:core-site.xml、hdfs-site.xml、mapred-site.xml和yarn-site.xml、slaves。然后可能还需要再hadoop-env.sh中添加JAVA环境变量。

以下配置文件可作为参考,还有很多其它配置项。

  • core-site.xml

该配置文件主要用于定义系统级别的参数,如HDFS、URL、hadoop的临时目录

<configuration>
  <property>
    <name>fs.default.name</name>
    <value>hdfs://master:9000</value>
    <description>文件系统主机和端口</description>   
  </property>
  <property>
    <name>io.file.buffer.size</name>
    <value>131072</value>
    <description>每个block的大小</description>
  </property>
  <property>
    <name>hadoop.tmp.dir</name>
    <value>file:/home/hadoop/cludata/hadoop/temp</value>
    <description>临时目录</description>   
  </property>
</configuration>
  • dfs-site.xml
<configuration>
  <property>
    <name>dfs.namenode.secondary.http-address</name>
    <value>master:9001</value>
    <description>通过web界面来查看HDFS状态</description>
  </property>
  <property>
    <name>dfs.namenode.name.dir</name> 
    <value>file:/home/hadoop/cludata/hadoop/hdfs/name</value>
  </property>
  <property>
    <name>dfs.datanode.data.dir</name>  
    <value>file:/home/hadoop/cludata/hadoop/hdfs/data</value>
  </property>
  <property>
    <name>dfs.replication</name>
    <value>3</value>
    <description>每个Block有2个备份</description>
  </property>
  <property>
    <name>dfs.webhdfs.enabled</name>
    <value>true</value>
    <description>是否通过http协议访问hdfs文件</description>
  </property>
</configuration>
  • mapred-site.xml
<configuration>
  <property>
    <name>mapreduce.framework.name</name>
    <value>yarn</value>
  </property>
  <property>
    <name>mapreduce.jobhistory.address</name>
    <value>master:10020</value>
  </property>
  <property>
    <name>mapreduce.jobhistory.webapp.address</name>
    <value>master:19888</value>
  </property>
</configuration>
  • yarn-site.xml
<configuration>
  <!-- Site specific YARN configuration properties -->
  <property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
  </property>
  <property>
    <name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
    <value>org.apache.hadoop.mapred.ShuffleHandler</value>
  </property>
  <property>
    <name>yarn.resourcemanager.address</name>
    <value>master:8032</value>
  </property>
  <property>
    <name>yarn.resourcemanager.scheduler.address</name>
    <value>master:8030</value>
  </property>
  <property>
    <name>yarn.resourcemanager.resource-tracker.address</name>
    <value>master:8031</value>
  </property>
  <property>
    <name>yarn.resourcemanager.admin.address</name>
    <value>master:8033</value>
  </property>
  <property>
    <name>yarn.resourcemanager.webapp.address</name>
    <value>master:8088</value>
  </property>
  <property>
    <name>yarn.nodemanager.resource.memory-mb</name>
    <value>8192</value>
  </property>
</configuration>
  • slaves

这个配置文件主要是配置 datanode

把localhost去掉,添加以下内容

slave1

slave2

配置完成之后,将整个hadoop文件夹拷贝到其它两台机器

cd /home/hadoop

scp -r hadoop-2.7.6 hadoop@slave1:/home/hadoop/

scp -r hadoop-2.7.6 hadoop@slave2:/home/hadoop/

格式化

在启动hadoop之前,需要先格式化HDFS文件系统,只需要在master上执行即可

hadoop namenode -format
格式化

启动

有关于hadoop的一些脚本命令,存放在根目录下的sbin 文件夹下:即/home/hadoop /hadoop-2.7.6/sbin


脚本命令

所以,先进入sbin目录

cd /home/hadoop /hadoop-2.7.6/sbin
  • 启动NameNode
hadoop-daemon.sh start namenode

执行该命令后可以通过 ps -ef|grep hadoop 命令查看hadoop进程,也可以使用jsp命令查看JVM进行。运行jsp命令之后,可以可能到 Namenode进程。


  • 启动DataNode
hadoop-daemon.sh start datanode

在master上执行该命令后,在两台slave上分别执行 jps 命令查看 datanode是否启动,如果发现 Datanode 进程说明启动成功。


提示:其实以上两个启动过程可以通过一个脚本来启动,hadoop里面也提供了这个脚本,也是在sbin目录中,只要执行这个脚本就可以了

./start-dfs.sh

//对应的停止命令

./stop-dfs.sh
  • 启动ResourceManager
yarn-daemon.sh start resourcemanager

执行该命令之后,使用jsp命令可以查看到ResourceManager说明启动成功。

  • 启动NodeManager
yarn-daemon.sh start nodemanager

同理,通过jpps命令可以看到 NodeManage进程。

注意:以上两个过程也可以通过一个脚本来启动

./start-yarn.sh

//对应的停止命令

./stop-yarn.sh
  • 浏览器访问

http://192.168.88.21:50070

可以看到以下界面


hadoop

http://192.168.88.21:8088

可以看到以下界面


yarn

常见命令

hadoop下有一些常见命令

列出文件:hadoop fs -ls /

创建目录:hadoop fs -mkdir 目录

上传文件:hadoop fs -put filename 目录

查看文件:hadoop fs -cat 文件

测试案例

启动之后,可以用hadoop来处理一个demo,这个demo程序是hadoop在安装包里面已经提供了。

hadoop jar /home/hadoop/hadoop-2.7.6/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.6.jar pi 5 10

Pi 5 10 表示开 5个Map , 10 个 Reduce

执行这命令之后,控制台会有一系列输出,同时在浏览器上也可以看到效果

http://192.168.88.21:8088

MapReducer

其实上面就是一个Map Reducer 程序,这是官方提供的一个Demo,不过我们好像并不是很清楚这个程序的运行机制是什么样的,所以在此之前,有必要了解一下MapReducer。MapReducer可以在任何地方运行程序,访问HDFS上的文件并进行统计运算,并且可以把统计的结果写回HDFS的结果文件中。包括接下来介绍了HIVE,其实内部也是基于MapReducer实现,只不过HIVE内部进行了大量封装,所以我们才可以写SQL语句,其实每条SQL语句,都可以看成是一个MapReducer程序。MapReducer中有两个概念:Map 和 Reducer。

Map阶段: 将每一行文本数据变成<单词,1>这样的kv数据

Reduce阶段:将相同单词的一组kv数据进行聚合:累加所有的v

下面是一个简单WordCount 示例

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>com.hand.sxy</groupId>
    <artifactId>MapReducer</artifactId>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.6</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-core</artifactId>
            <version>2.7.6</version>
        </dependency>
    </dependencies>

</project>

WordCount.java

package com.hand.sxy;

import com.hand.sxy.utils.FileUtil;
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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;

public class WordCount {

    public static void main(String[] args) throws Exception {

        FileUtil.deleteDir("/output");
        Configuration conf = new Configuration();

        String[] otherArgs = new String[]{"hdfs://master:9000/test/dream.txt", "/output"};
        if (otherArgs.length != 2) {
            System.err.println("Usage:Merge and duplicate removal <in> <out>");
            System.exit(2);
        }

        Job job = Job.getInstance(conf, "WordCount");
        job.setJarByClass(WordCount.class);
        job.setMapperClass(WordCount.TokenizerMapper.class);
        job.setReducerClass(WordCount.IntSumReduce.class);
        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);
    }


    public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {

        public static final IntWritable one = new IntWritable(1);
        private 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()) {
                this.word.set(itr.nextToken());
                context.write(this.word, one);
            }
        }

    }

    public static class IntSumReduce 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;
            IntWritable val;
            for (Iterator i = values.iterator(); i.hasNext(); sum += val.get()) {
                val = (IntWritable) i.next();
            }
            this.result.set(sum);
            context.write(key, this.result);
        }
    }
}

这里面就涉及到了一些API,这个可以自己去网上查,这里不做过多介绍。

接下来需要做的就是执行这个程序,首先,将这个程序打包成jar,然后上传服务器

mvn clen install

在hdfs系统上准备好数据,编辑 dream.txt 文件内容如下

Hello bob

I am good

How are you

I am fine

Good good study

上传dream.txt到hdfs系统

hadoop fs -mkdit /test
hadoop fs -put dream.txt /test/dream.txt

执行MapReducer-1.0.jar程序

hadoop jar MapReducer-1.0.jar com.hand.sxy.WordCount

在控制台和浏览器上观察

image.png

浏览器打开:http://master:8088/cluster/apps

image.png

浏览器打开:http://master:50070/explorer.html#/output

程序结果即在hsfs中的 /output/part-r-00000文件中

hadoop fs -cat /output/part-r-00000

输出的就是每个单词出现的次数,这就是一个最简单的MapReducer程序。

HA集群

hadoop的HA集群,即hadoop的高可用集群配置,为了解决hadoop中的NameNode单点故障问题。这个配置的时候比较繁琐,有空再补上

安装HIVE

HIVE是在MapReducer上的一层封装,通过写sql方式来实现MapReducer程序。什么意思?就是说大部分情况下,有了HIVE之后,不需要再开发MapReducer程序了,直接写HQL即可,大大节约了时间成本。HIVE非常强大,在创建hie表的时候,字段类型用的是java里面的数据类型,连Map类型都可以用,很强大。

下载安装

http://mirror.bit.edu.cn/apache/hive/
http://mirrors.hust.edu.cn/apache/hive/
http://mirrors.shu.edu.cn/apache/hive/
http://mirrors.tuna.tsinghua.edu.cn/apache/hive/

安装位置随便安装到那台机器都都可以,先解压

tax -zxvf apache-hive-1.2.2-bin.tar.gz

6.2. 配置文件

添加一个hive-site.xml配置文件

<configuration>
  <property>
    <name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://centos81:3306/hive?
createDatabaseIfNotExist=true</value>
  </property>

  <property>
    <name>javax.jdo.option.ConnectionDriverName</name>
    <value>com.mysql.jdbc.Driver</value>
  </property>

  <property>
    <name>javax.jdo.option.ConnectionUserName</name>
    <value>root</value>
  </property>

  <property>
    <name>javax.jdo.option.ConnectionPassword</name>
    <value>root</value>
  </property>
</configuration>

这里其实就是配置hive元数据的存放位置,即hive中的数据库名、表名、字段等西信息。其实不配置也没关系, hive默认内置了一个其它 的数据库。

这里选择的是mysql数据库,所以还需要提供一个mysql驱动包,这里是:mysql-connector-java-5.1.46.jar

启动

cd hive-1.2.2

bin/hive

如果你已经安装好了mysql,执行这个命令之后,就会在mysql下创建一个hive数据库。如图:


之后,就可以用一些hive的语法了。

常见命令

和我们的sql非常类似

列出数据库:show databases;

创建数据库:create database 数据库名;

使用数据库:use 数据库 名;

创建数据表:create table 表名 (xxx);

创建外部表:create external table 表名 (xxx);

创建分区表:create external table 表名 (xxx) partitioned by (day string);

配置分隔符:在建表语句后面加 row format delimited fields terminated by ',' ;

测试

在hive中新建数据库和表,并在hadoop中上传文件,看看在hivez怎么通过sql查出来。

create database tsdb;
use tsdb;
create table t_test1(id int,name string,age int) row format delimited fields terminated by ',';

执行以上命令之后,观察在hadoop中hdfs的目录



image.png

可以看到,生成了一个和数据库名相同的文件夹子,点进去发现,也生成了一个和表名对应的目录。

vi t_test1.txt

文件内容如下:

1,xiaoyong,20
2,gaoxiao,40
3,liuxin,19

上传这个文件到hdfs

hadoop fs -put t_test1.txt /user/hive/warehouse/tsdb.db/t_test1

在hive控制台查询

select * from t_test1;

[图片上传失败...(image-83e835-1535979338058)]

结果已经查出来了。

这本是一个MapReducer程序做的事情,现在一个SQL就搞定了。Hive中还有很多概念,这里就不做过多结算了。

安装MySQL

这里安装MySQL的目的就一个:保存HIVE中的元数据。在安装MySQL之前,先装一个虚拟机,修改IP,修改四台机器的 /etc/host,这就当作是一台专用数据库服务器。

更新yum源

下载mysql的yum源:

wget -P /home/lisonglin [http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm](http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm)

安装mysql的yum源:

rpm -ivh mysql57-community-release-el7-11.noarch.rpm

安装

执行以下命令,然后一直按y就可以了

yum install mysql-community-server

启动测试

启动服务

systemctl start mysqld

通过mysql客户但登录mysql,默认是不需要密码

mysql -uroot

设置密码

set password = passeord(‘root’);

修改配置文件,这里只修改编码集,配置文件默认在 /etc/my.cnf

show variables lie ‘character%’;

vi /etc/my.cnf

[mysql]

default-character-set = utf8

[mysqld]

character_set_server = utf8

常用命令

常见的 启动、停止、重启等命令

启动:systemctl start mysqld   

停止:# systemctl stop mysqld 

重启:systemctl restart mysqld 

设置开机启动:systemctl enable mysqld 

查看 MySQL Server 状态:systemctl status mysqld   

安装Zookeeper

Zookeeper是一个基础组件,主要功能包括:

可以为客户端管理少量数据,其中在zookeeeper中数据为键值格式。其中key类似于文件目录结构,但不是目录

/aa “valuea”

/aa/cc “valueb”

可以为客户端监听指定数据节点得装填,并在数据节点发生变化时通知客户端。
应用场景:zookeeeper的应用场景可以非常广泛,比如微服务架构中的服务注册中心,用于服务上下线动态感知。zookeeper在hadoop体系中是为了高可用,是为了解决DataNode的单点故障问题;在Hbase中保存了Hbase各个ReginServer和master的信息。

下载安装

生产环境一般是部署zookeeper集群,部署到奇数台服务器,一般3台或者5台。zookeeper有一个投票选举机制,所以有个leader 和 flower概念。

下载地址:http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.12/

解压:tax -zxvf zookeeper-3.4.12.tar.gz

8.2. 配置文件

cd zookeeper-3.4.12/conf

cp zoo_sample.cfg zoo.cfg

vi 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/hadoop/cludata/zkdata
# the port at which the clients will connect
clientPort=2181
# 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
server.21=master:2888:3888
server.22=slave1:2888:3888
server.23=slave2:2888:3888

创建zk数据目录

cd ~
mkdir -p cludata/zkdata

启动

在三台服务器下分别执行以下命令

cd ~/zookeeper-3.4.12/

bin/zkServer.sh start

在启动之后可以查看状态

bin/zkServer.sh status


启动脚本

为了方便启动,提供一个启动脚本

常见命令

进入客户端

cd zookeeper-3.4.12

bin/zkCli.sh

//或者连接到其它服务器

bin/zkCli.sh -server slave1:2181

zookeeper 下提供了一些常见客户端命令

创建节点:create /aa “value”

查看节点:ls /

查看数据:get /aa

修改数据:set /add “vakue2”

删除节点:rmr /aa

监听数据:get /aa watch

安装HBASE

HBase是一个基于HDFS的NoSQL数据库,可以提供数据的实时随机读写,其中包括的概念有:HMaster、HRegionServer、库名、表名、行键、列族等,其中HBase集群中的各个节点信息是维护在zookeeper中的。

下载安装

下载地址:http://apache.claz.org/hbase/1.2.6.1/

tar -zxvf

HBase中包括两个角色:HMaster、HRegionServer。HMaster负责管理HRegionServer,数据读写交给HRegionServer。其中,HRegionServer应该和HDFS中的DataNode安装在一起。

配置文件

主要修改三个配置文件:hbase-env.sh、hbase-site.xml、regionservers

cd hbase-1.2.6.1/conf

修改hbase-env.sh

export JAVA_HOME=/home/hadoop/jdk1.8

//hbase自己有一套zookeeper管理机制,这里不使用自带的,而是使用我们配置的

export HBASE_MANAGES_ZK=false

修改hbase-site.xml

<configuration>
  <!-- 指定hbase在HDFS上存储的路径 -->
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://master:9000/hbase</value>
  </property>

  <!-- 指定hbase是分布式的 -->
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>

  <!-- 指定zk的地址,多个用“,”分割 -->
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>master:2181,slave1:2181,slave2:2181</value>
  </property>
</configuration>

修改regionservers,这里就是配置HRegionServer服务器的

slave1
slave2

然后将安装包拷贝到slave1 和 slave2

scr -r hbase-1.2.6.1 hadoop@slave1:/home/hadoop
scr -r hbase-1.2.6.1 hadoop@slave2:/home/hadoop

启动

启动hbase的时候有个要求,需要各个服务器之间时间差不超过30s,所以在启动之前需要先设置同步一下服务器时间,可以选择时间服务器,这里就直接用命令了

date -s "2018-07-08 16:39:03"

//写入bios,防止重启系统时间又变了

hwclock -w

启动hdfs,不启动yarn也没关系,在master服务器启动

cd hadoop-2.7.6
sbin/start-dfs.sh

启动zookeeper,进入三台服务器启动

cd zookeeper-3.4.12
bin/zkServer.sh start

启动hbase

bin/start-hbase.sh

启动之后,三台服务器上的进程分别如下,可以看到hbase已经启动起来了




启动成功之后,也可以在浏览器上观察效果
http://master:16010

前面已经说过,hbase相关的节点信息和zookeeper已经关联了,所以可以在zookeeper上查看hbase相关信息

cd zookeeper-3.4.12
bin/zkCli.sh

Hbase的文件存储是基于HDFS的,所以也可以在hdfs上看到hbase相关的目录
打开浏览器:http://master:50070/explorer.htm

命令行

Hbase提供了一些交互命令,但是这种情况我们用的不多一般是在程序中通过API来对hbase交互。

进入hbase命令行客户端

cd hbase-1.2.6.1
bin/hbase shell

常用命令如下:


image.png

常见用法

创建表

create 表名, 列族名, 列族名 ……
create 't_user_info','base_info','extra_info'

插入数据

put 't_user_info','001','base_info:username','zhangsan'
put 't_user_info','001','base_info:age','18'

查询数据

scan 't_user_info'
get 't_user_info','001'

删除kv数据

delete 't_user_info','001','base_info:sex'
deleteall 't_user_info','001'

删除表

先禁用,然后删除
disable 't_user_info'

drop 't_user_info'

API

创建一个连接

Connection conn = ConnectionFactory.createConnection(conf);

拿到一个DDL容器

Admin admin = conn.getAdmin();

用表管理器的API去操作表

admin.createTable(HTableDescriptor descriptor);

创建一个连接

Connection conn = ConnectionFactory.createConnection(conf);

安装Flume

Flume用于数据采集。在实际开发中,有各种各样的数据来源,比如:kafka、mysql、hbase等等,而我们的业务系统,往往需要根据不用的数据来源开发不同的程序。Flume就相当一层壳,并且里面提供了一些常用的实现类,有个核心概念就Agent,可以启动Agent程序进行数据采集,大大减少了我们的开发时间。

不过看网上说,Flume在严格场景是不推荐使用的,会有问题。所以简单了解一下吧。

下载安装

下载地址

http://mirror.bit.edu.cn/apache/flume/1.8.0/apache-flume-1.8.0-bin.tar.gz http://mirrors.hust.edu.cn/apache/flume/1.8.0/apache-flume-1.8.0-bin.tar.gz http://mirrors.shu.edu.cn/apache/flume/1.8.0/apache-flume-1.8.0-bin.tar.gz http://mirrors.tuna.tsinghua.edu.cn/apache/flume/1.8.0/apache-flume-1.8.0-bin.tar.gz

解压并拷贝到其它两台机器

tar -zxvf apache-flume-1.8.0-bin.tar.gz

scp -r flume-1.8.0 hadoop@slave1:/home/hadoop

scp -r flume-1.8.0 hadoop@slave2:/home/hadoop

配置文件

使用Flume主要就是配置了,需要编写的配置内容比较多。 这里就不过多介绍了,有兴趣的网上了解一下。

问题总结

DataNode无法启动

多次执行hadoop namenode -format命令,slave 上的执行这个命令之前,我已经清空了三台服务器下的一些目录,并且停掉了所有进程

cd /home/hadoop/hadoop
rm -rf temp/*
rm -rf hdfs/name/* hdfs/data/*
cd hadoop-2.7.6
rm -rf logs/*
sbin/stop-all.sh

然后在master上执行以下命令

sbin/ hadoop-daemon.sh start namenode
sbin/ hadoop-daemon.sh start datanode

执行该命令后,发现在 master节点上找到了 NameNode 和 DataNode 进行,但是在其它两台服务器上未找到 DataNode 进程。

最后的解决方案:

分别在slave1 和 slave2 上执行 以下命令

sbin/ hadoop-daemon.sh start datanode

这时候可以在 slave1 和 slave2 上找到 DataNode进程。

同时,在浏览器上可以发现3个DataNode
http://192.168.88.21:50070/dfshealth.html#tab-datanode

可能应该在三台服务器上把 hdfs目录下的所有文件和文件夹都清空,或者把整个hdfs目录删除。

同理,对于slave1 和slave2 上的没有NodeManager进程情况,就手动在slave1和slave2上启动

yarn-daemon.sh start nodemanager

http://192.168.88.21:8088/cluster/nodes

脚本启动权限问题

执行 sbin/start-dfs.fs 命令,通过ssh的方式启动slave1和slave2节点,提示没有/tmp目录的权限,但是很好奇都是hadoop用户,启动本地的NameNode却没有权限问题。单丝,虽然提示权限问题,两个DataNode却都已经启动了。

为了去除这个警告,尝试是将 /tmp 目录的权限赋给hadoop用户,分别在三台机器上执行以下命令

chown -R hadoop /tmp

再次重启hadoop

sbin/stat-dfs.sh
sbin/stat-yarn.sh

发现警告已经没有了,同时两台DataNode已经启动成功。

这时候,三台机器下分别启动的进程有

**master**:NameNode、SecondaryNameNode、ResourceManager

**slave1**:DataNode、NodeManager、

**slave2**:DataNode、NodeManager、

可以这样理解:NameNode用于管理DataNode,而ResourceManager用于管理NodeManager。

其实这个问题还有另外一种解决方案,就是修改 etc/hadoop/hadoop.env配置文件,里面有那么个选项可以修改。