云计算作业一

目录

0. 前置准备

0.1 安装虚拟机

0.2 Linux统一设置

1. Hadoop安装配置

1.1 环境准备

1.2 Hadoop伪分布式安装

1.3 Hadoop集群安装

2. HDFS实验,包括Shell命令操作和Java接口访问

2.1 HDFS操作命令

2.2 通过Java项目访问HDFS

2.3 使用winutils解决警告信息

3. 实现MapReduce的WordCount

3.1 MapReduce的运算过程

3.2 WordCount示例

3.3 可能遇到的bug

4.Hbase安装配置实验

4.1 HBase的安装

4.1.1 HBase的单节点安装

4.1.2 HBase的伪分布式安装


0. 前置准备

0.1 安装虚拟机

(若已安装则可跳过)

· 使⽤VMware安装CentOs7
· 通过自定义配置
· 内存配置2GB
· 硬盘30GB
· 处理器数量为2
· 在安装过程中,创建一个非root用户,并选择属于管理员组,如图。

· 接下来设置静态IP地址。打开终端,先通过ifconfig命令查询IP地址,在ens33处,并记住

然后在使用vim /etc/sysconfig/network-scripts/ifcfg-ens33

vim /etc/sysconfig/network-scripts/ifcfg-ens33
进入编辑界面后,需要将BOOTPROTO改成static,然后在下面添加需要修改的配置,如下图所示。( 注:IPADDR根据自己主机IP配置,GATWAY最后一部分与IPADDR的不同)

0.2 Linux统一设置

步骤01 配置主机名称。

将主机名取为server+IP最后一部分作为主机名称,下面例子取主机名为server201,是因为本主机的IP地址设置为192.168.56.201。若是xxx.xxx.xxx.22,则改为server22

hostnamectl set-hostname server201

步骤02 修改hosts文件。

在hosts文件的最后,添加以下的配置,可以通过vim /etc/hosts进行修改。(根据自己主机修改)
    192.168.56.201  server201

步骤03 关闭且禁用防火墙。

systemctl stop firewalld
systemctl disable firewalld

步骤04 禁用SELinux,需要重新启动。

vim /etc/selinux/config
SELINUX=disabled

步骤05 在/usr/java目录下,安装JDK1.8.x。

首先在Oracle官网下载JDK1.8的Linux版本,如图所示。

可通过winscp上传到Linux中的/usr/java/目录下并解压:

tar -zxvf jdk-8u281-linux-x64.tar.gz -C /usr/java/

步骤06 配置JAVA_HOME环境变量。

vim /etc/profile

在profile文件最后,添加以下配置:

export JAVA_HOME=/usr/java/jdk1.8.0_281
export PATH=.:$PATH:$JAVA_HOME/bin

让环境变量生效:

source /etc/profile

检查Java版本:

    [root@localhost bin]# java -version
    java version "1.8.0_281"
    Java(TM) SE Runtime Environment (build 1.8.0_192-b12)
    Java HotSpot(TM) 64-Bit Server VM (build 25.192-b12, mixed mode)

至此,基本的环境就配置完成了。

1. Hadoop安装配置

1.1 环境准备

步骤01 关闭防火墙。

以下命令检查防火墙的状态:

sudo firewall-cmd --state
running

running表示防火墙正在运行。以下命令用于停止和禁用防火墙:

systemctl stop firewalld.service
systemctl disable firewalld.service

 步骤02 配置免密码登录。

配置免密码登录的主要目的,就是在使用Hadoop脚本启动Hadoop的守护进程时,不需要再提示用户输入密码。SSH免密码登录的主要实现机制,就是在本地生成一个公钥,然后将公钥配置到需要被免密码登录的主机上,登录时自己持有私钥与公钥进行匹配,如果匹配成功,则登录成功,否则登录失败。

可以使用ssh-keygen命令生成公钥和私钥文件,并将公钥文件复制到被SSH登录的主机上。以下是ssh-keygen命令,输入后直接按两次回车即可生成公钥和私钥文件:

如上面所说,生成的公钥和私钥文件将被放到~/.ssh/目录下。其中id_rsa文件为私钥文件,rd_rsa.pub为公钥文件。现在我们再使用ssh-copy-id将公钥文件发送到目标主机。由于登录的是本机,所以直接输入本机名即可:

    [hadoop@server201 ~]$ ssh-copy-id server201
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/hadoop/.
ssh/id_rsa.pub"
    The authenticity of host 'server201 (192.168.56.201)' can't be established.
    ECDSA key fingerprint is SHA256:KqSRs/H1WxHrBF/tfM67PeiqqcRZuK4ooAr+xT5Z4OI.
    ECDSA key fingerprint is MD5:05:04:dc:d4:ed:ed:68:1c:49:62:7f:1b:19:63:5d:8
e.
    Are you sure you want to continue connecting (yes/no)? yes 输入yes
    /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filt
er out any that are already installed
    /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are pro
mpted now it is to install the new keys

输入密码然后按回车键,将会提示成功信息:

    hadoop@server201's password:
    Number of key(s) added: 1
    Now try logging into the machine, with:   "ssh 'server201'"
    and check to make sure that only the key(s) you wanted were added.

此命令执行以后,会在~/.ssh目录下多出一个用于认证的文件,其中保存了某个主机可以登录的公钥信息,这个文件为~/.ssh/authorized_keys。

现在再使用ssh server201命令登录本机,将会发现不用再输入密码,即可以直接登录成功。

[hadoop@server201 ~]$ ssh server201
Last login: Tue Mar  9 20:52:56 2021 from 192.168.56.1

1.2 Hadoop伪分布式安装

在安装之前,请确定已经安装了JDK1.8,并正确配置了JAVA_HOME、PATH环境变量。

在磁盘根目录下,创建一个app目录,并授权给hadoop用户。然后将会把Hadoop安装到此目录下。先切换到根目录下:

[hadoop@server201 ~]$ cd /

添加sudo前缀使用mkdir创建/app目录:

[hadoop@server201 /]$ sudo mkdir /app

将此目录的所有权授予给hadoop用户和hadoop组:

[hadoop@server201 /]$ sudo chown hadoop:hadoop /app

切换进入/app目录:

[hadoop@server201 /]$ cd /app/

使用ll -d命令查看本目录的详细信息,可看到此目录已经属于hadoop用户:

[hadoop@server201 app]$ ll -d
drwxr-xr-x 2 hadoop hadoop 6 3月  9 21:35 .

下载hadoop:Index of /apache/hadoop/common/stable (tsinghua.edu.cn)

将Hadoop的压缩包通过winscp上传到/app目录下,并解压到此文件中。可用ll命令查看本目录是否上传成功。

[hadoop@server201 app]$ ll
总用量 386184
-rw-rw-r-- 1 hadoop hadoop 395448622 3月  9 21:40 hadoop-3.4.0.tar.gz

使用tar命令-zxvf参数解压此文件:

[hadoop@server201 app]$ tar -zxvf hadoop-3.4.0.tar.gz

以下开始配置Hadoop。Hadoop的所有配置文件都在hadoop-3.4.0/etc/hadoop目录下。首先切换到此目录下,然后开始配置:

[hadoop@server201 hadoop-3.4.0]$ cd /app/hadoop-3.4.0/etc/hadoop/

步骤01 配置hadoop-env.sh文件。

hadoop-env.sh文件是Hadoop的环境文件,在此文件中需要配置JAVA_HOME变量。在此文件的最后一行输入以下配置,然后按Esc键,再输入:wq保存退出即可:

export JAVA_HOME=/usr/java/jdk1.8.0_281

步骤02 配置core-site.xml文件。core-site.xml文件是HDFS的核心配置文件,用于配置HDFS的协议、端口号和地址。注意:Hadoop 3.0以后HDFS的端口号建议为8020,但如果查看Hadoop的官网示例,依然延续使用的是Hadoop 2之前的端口9000,以下配置我们将使用8020端口,只要保证配置的端口没有被占用即可。配置时,需要注意大小写。使用vim打开core-site.xml文件,进入编辑模式:

[hadoop@server201 hadoop]$ vim core-site.xml

在<configuration></configuration>两个标签之间输入以下内容:(注意修改server201

    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://server201:8020</value>
    </property>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/datas/hadoop</value>
    </property>

配置说明:● fs.defaultFS:用于配置HDFS的主协议,默认为file:///。● hadoop.tmp.dir:用于指定NameNode日志及数据的存储目录,默认为/tmp。

步骤03 配置hdfs-site.xml文件。hdfs-site.xml文件用于配置HDFS的存储信息。使用vim打开hdfs-site.xml文件,并在<configuration></configuration>标签中输入以下内容:

    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
    <property>
        <name>dfs.permissions.enabled</name>
        <value>false</value>
    </property>

配置说明:● dfs.replication:用于指定文件块的副本数量。HDFS特别适合于存储大文件,它会将大文件切分成每128MB一块,存储到不同的DataNode节点上,且默认会每一块备份2份,共3份,即此配置的默认值为3,最大为512。由于我们只有一个DataNode,所以这儿将文件副本数量修改为1。● dfs.permissions.enabled:访问时,是否检查安全,默认为true。为了方便访问,暂时把它修改为false。

步骤04 配置mapred-site.xml文件。

通过名称可见,此文件是用于配置MapReduce的配置文件。通过vim打开此文件,并在<configuration>标签中输入以下配置:

    $ vim mapred-site.xml
    <property>
       <name>mapreduce.framework.name</name>
       <value>yarn</value>
    </property>

配置说明:● mapreduce.framework.name:用于指定调试方式。这里指定使用YARN作为任务调用方式。

步骤05 配置yarn-site.xml文件。由于上面指定了使用YARN作为任务调度,所以这里需要配置YARN的配置信息,同样,使用vim编辑yarn-site.xml文件,并在<configuration>标签中输入以下内容:

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

通过hadoop classpath命令获取所有classpath的目录,然后配置到上述文件中。由于没有配置Hadoop的环境变量,所以这里需要输入完整的Hadoop运行目录,命令如下:

[hadoop@server201 hadoop]$ /app/hadoop-3.4.0/bin/hadoop classpath

输入完成后,将显示所有classpath信息:

    /home/hadoop/program/hadoop-3.2.2/etc/hadoop:/home/hadoop/program/hadoop-3.
2.2/share/hadoop/common/lib/*:/home/hadoop/program/hadoop-3.2.2/share/hadoop/co
mmon/*:/home/hadoop/program/hadoop-3.2.2/share/hadoop/hdfs:/home/hadoop/program
/hadoop-3.2.2/share/hadoop/hdfs/lib/*:/home/hadoop/program/hadoop-3.2.2/share/h
adoop/hdfs/*:/home/hadoop/program/hadoop-3.2.2/share/hadoop/mapreduce/lib/*:/ho
me/hadoop/program/hadoop-3.2.2/share/hadoop/mapreduce/*:/home/hadoop/program/ha
doop-3.2.2/share/hadoop/yarn:/home/hadoop/program/hadoop-3.2.2/share/hadoop/yar
n/lib/*:/home/hadoop/program/hadoop-3.2.2/share/hadoop/yarn/*

然后将上述的信息复制一下,并配置到yarn-site.xml文件中:

    <property>
        <name>yarn.application.classpath</name>
        <value>
    /home/hadoop/program/hadoop-3.2.2/etc/hadoop:/home/hadoop/program/hadoop-3.
2.2/share/hadoop/common/lib/*:/home/hadoop/program/hadoop-3.2.2/share/hadoop/co
mmon/*:/home/hadoop/program/hadoop-3.2.2/share/hadoop/hdfs:/home/hadoop/program
/hadoop-3.2.2/share/hadoop/hdfs/lib/*:/home/hadoop/program/hadoop-3.2.2/share/h
adoop/hdfs/*:/home/hadoop/program/hadoop-3.2.2/share/hadoop/mapreduce/lib/*:/ho
me/hadoop/program/hadoop-3.2.2/share/hadoop/mapreduce/*:/home/hadoop/program/ha
doop-3.2.2/share/hadoop/yarn:/home/hadoop/program/hadoop-3.2.2/share/hadoop/yar
n/lib/*:/home/hadoop/program/hadoop-3.2.2/share/hadoop/yarn/*
        </value>
    </property>

配置说明:

● yarn.resourcemanager.hostname:用于指定ResourceManger的运行主机,默认为0.0.0.0,即本机。

● yarn.nodemanager.aux-services:用于指定执行计算的方式为mapreduce_shuffle。

● yarn.application.classpath:用于指定运算时的类加载目录。

步骤06 配置workers文件。

这个文件在之前的版本叫作slaves,但功能一样。主要用于在启动时启动DataNode和NodeManager。编辑workers文件,并输入本地名称:

server201

步骤07 配置Hadoop环境变量。

编辑/etc/profile文件:

$ sudo vim /etc/profile

并在里面添加以下内容:

export HADOOP_HOME=/app/hadoop-3.4.0

export PATH=$PATH:$HADOOP_HOME/bin

使用source命令,让环境变量生效:

source /etc/profile

然后使用hdfs version查看命令环境变量是否生效,如果配置成功,则会显示Hadoop的版本:

[hadoop@server201 hadoop]$ hdfs version Hadoop 3.4.0 Source code repository Unknown -r 7a3bc90b05f257c8ace2f76d74264906f0f7a932 Compiled by hexiaoqiao on 2024-08-03T09:26Z Compiled with protoc 2.5.0 From source with checksum 5a8f564f46624254b27f6a33126ff4 This command was run using /app/hadoop-3.4.0/share/hadoop/common/hadoop-comm on-3.4.0.jar

步骤08 初始化Hadoop的文件系统。

Hadoop在使用之前,必须先初始化HDFS文件系统,初始化的文件系统将会生成在hadoop.tmp.dir配置的目录下,即上面配置的/app/datas/hadoop目录下。

$ hdfs namenode -format

在执行命令完成以后,请在输出的日志中找到以下这句话,即为初始化成功:

Storage? directory /opt/hadoop_tmp_dir/dfs/name has been successfully formatted.

步骤09 启动HDFS和YARN。

启动和停止HDFS及YARN的脚本在$HADOOP_HOME/sbin目录下。其中start-dfs.sh为启动HDFS的脚本,start-yarn.sh为启动ResourceManager的脚本。以下命令分别启动HDFS和YARN:

[hadoop@server201 /]$ /app/hadoop-3.4.0/sbin/start-dfs.sh

[hadoop@server201 /]$ /app/hadoop-3.4.0/sbin/start-yarn.sh

启动完成以后,通过jps来查看Java进程快照,会发现有5个进程正在运行:

    [hadoop@server201 /]$ jps
    12369 NodeManager
    12247 ResourceManager
    11704 NameNode
    12025 SecondaryNameNode
    12686 Jps
    11839 DataNode

其中:NameNode、SecondaryNameNode、DataNode是通过start-dfs.sh脚本启动的。ResourceManager和NodeManager是通过start-yarn.sh脚本启动的。启动成功以后,也可以通过

http://server201:9870 查看NameNode的信息,如图所示。

可以通过http://server201:8088页面查看MapReduce的信息,如图所示。

步骤10 关闭。

关闭HDFS的YARN可以分别执行stop-dfs.sh和stop-yarn.sh脚本:

    [hadoop@server201 /]$ /app/hadoop-3.4.0/sbin/stop-yarn.sh
    Stopping nodemanagers
    Stopping resourcemanager
    [hadoop@server201 /]$ /app/hadoop-3.4.0/sbin/stop-dfs.sh
    Stopping namenodes on [server201]
    Stopping datanodes
    Stopping secondary namenodes [server201]

至此,Hadoop单机即伪分布式模式安装和配置成功。

1.3 Hadoop集群安装

Hadoop分布式集群配置-CSDN博客

2. HDFS实验,包括Shell命令操作和Java接口访问

2.1 HDFS操作命令

hdfs命令位于$HADOOP_HOME/bin目录下。由于已经配置了HADOOP_HOME和PATH的环境变量,所以此命令可以在任意目录下执行。可以通过直接输入hdfs命令,查看它的使用帮助:

    $ hdfs
    Usage: hdfs [--config confdir] [--loglevel loglevel] COMMAND
           where COMMAND is one of:
    dfs    run a filesystem command on the file systems supported in Hadoop.
    classpath            prints the classpath
    namenode -format     format the DFS filesystem
    secondarynamenode    run the DFS secondary namenode
    namenode             run the DFS namenode
    journalnode          run the DFS journalnode
    zkfc                 run the ZK Failover Controller daemon
    datanode             run a DFS datanode
    debug                run a Debug Admin to execute HDFS debug commands
    dfsadmin             run a DFS admin client
    haadmin              run a DFS HA admin client
    fsck                 run a DFS filesystem checking utility
    balancer             run a cluster balancing utility
    jmxget               get JMX exported values from NameNode or DataNode.
    mover                run a utility to move block replicas across
                           storage types
    oiv                  apply the offline fsimage viewer to an fsimage
    oiv_legacy           apply the offline fsimage viewer to an legacy fsimage
    oev                  apply the offline edits viewer to an edits file
    fetchdt              fetch a delegation token from the NameNode
    getconf              get config values from configuration
    groups               get the groups which users belong to
    snapshotDiff         diff two snapshots of a directory or diff the
                           current directory contents with a snapshot
    lsSnapshottableDir   list all snapshottable dirs owned by the current user
                                Use -help to see options
    portmap              run a portmap service
    nfs3                 run an NFS version 3 gateway
    cacheadmin           configure the HDFS cache
    crypto               configure HDFS encryption zones
    storagepolicies      list/get/set block storage policies
    version              print the version
    Most commands print help when invoked w/o parameters.

在上面的列表中,第一个dfs是经常被使用的命令。可以通过hdfs dfs-help查看dfs的具体使用方法。dfs命令,就是通过命令行操作HDFS目录或是文件 的命令,类似于Linux文件命令一样,只不过dfs操作的是HDFS文件系统中的文件。下表列出HDFS几个常用命令。

完成以下示例:

显示根目录下的所有文件和目录:

[hadoop@server201 ~]$ hdfs dfs -ls /

Found 1 items

drwxr-xr-x - hadoop supergroup 0 2021-03-10 20:41 /test

以递归的形式显示根目录下的所有文件或目录,注意-R参数:

[hadoop@server201 ~]$ hdfs dfs -ls -R /

drwxr-xr-x - hadoop supergroup 0 2021-03-10 20:41 /test

-rw-r--r-- 1 hadoop supergroup 6 2021-03-10 20:41 /test/a.txt

删除HDFS上的文件:

[hadoop@server201 ~]$ hdfs dfs -rm /test/a.txt

将本地文件上传到HDFS上:

[hadoop@server201 ~]$ hdfs dfs -copyFromLocal a.txt /test/a.txt

使用put命令,同样可以将本地文件上传到HDFS上:

[hadoop@server201 ~]$ hdfs dfs -put a.txt /test/b.txt

使用get/copyToLocal选项,可以下载文件到本地:

[hadoop@server201 ~]$ hdfs dfs -get /test/c.txt a.txt

[hadoop@server201 ~]$ hdfs dfs -copyToLocal /test/a.txt a1.txt

2.2 通过Java项目访问HDFS

不仅可以使用hdfs命令操作HDFS文件系统上的文件,还可以使用Java代码访问HDFS文件系统中的文件。在Java代码中,操作HDFS主要通过以下几个主要的类:

● Configuration:用于配置HDFS。

● FileSystem:表示HDFS文件系统。

● Path:表示目录或是文件路径。

首先须在window中配置java环境

1.JAVA jdk安装教程:JDK安装配置教程(保姆级)-CSDN博客

2.Maven安装教程:Maven的安装与配置及IDEA配置(超详细图文讲解)_maven安装及配置教程-CSDN博客

使用IDEA创建Java项目来操作HDFS文件系统。IDEA有两个版本IC和IU两个版本,其中IU为IDEA Ultimate为完全功能版本,此版本需要付费后才能使用,可以选择IC版本, C为Community即社区版本的意思,IC版本为免费版本。后面集成开发环境将选择此IDEA Community版本。IDEA的下载地址为https://www.jetbrains.com/idea/download/#section=windows。选择下载IDEA Community版本,如图所示。

选择下载zip版本即可,下载完成后,解压到任意目录下(建议使用没有中文没有空格的目录)​。运行IdeaIC/bin目录下的idea64.exe即可启动IDEA。接下来,就开始创建Java项目,并通过Java代码访问HDFS文件系统。

步骤01 创建maven项目。

打开IDEA并选择创建新的项目,如图所示。

选择创建Maven项目,如图所示。

选择项目创建的目录,并输入项目的名称,如图所示。

为了方便管理,以模块方式来开发,每一个实验可以为一个模块,而Hadoop是这些模块的父项目。所以,在创建完成Hadoop项目后,修改Hadoop的项目类型为pom。以下Hadoop父项目的pom.xml文件部分内容,父项目的<package>类型为pom。

【代码】hadoop/pom.xml文件

    <groupId>org.hadoop</groupId>
    <artifactId>hadoop</artifactId>
    <version>1.0</version>
    <packaging>pom</packaging>

在父项目中的dependencyManagement添加所需要的依赖后,子模块只需要添加依赖名称,不再需要导入依赖的版本。这样父项目就起到了统一管理版本的功能。

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-client</artifactId>
                <version>3.2.2</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.2</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

再创建第一个模块。选择Hadoop项目,选择创建模块,如图所示。

输入模块的名称,如图2-9所示。

在创建的子模块chapter01中,修改pom.xml文件,添加以下依赖。注意,只输入groupId和artifactId,不需要输入版本,因为Hadoop项目作为父项目管理依赖的版本。

    <dependencies>
       <dependency>
           <groupId>org.apache.hadoop</groupId>
           <artifactId>hadoop-client</artifactId>
       </dependency>
       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <scope>test</scope>
       </dependency>
   </dependencies>

查看hadoop client Aggretator的依赖关系,如图2-10所示。

至此已经可以开发Java代码,访问HDFS文件系统了。

步骤02 HDFS操作示例。

(1)显示HDFS指定目录下的所有目录

显示所有目录,使用fileSystem.listStatus方法。

【代码】Demo01AccessHDFS.java

package org.hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import org.apache.hadoop.fs.FileStatus;

public class Demo01AccessHDFS {

    public static void main(String[] args) {
        System.setProperty("HADOOP_USER_NAME", "hadoop");
        Configuration config = new Configuration();
        config.set("fs.defaultFS", "hdfs://192.168.56.201:8020");//注意修改IP
        FileSystem fs = null;
        try {
            fs = FileSystem.get(config);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        FileStatus[] stas = null;
        try {
            stas = fs.listStatus(new Path("/"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        for (FileStatus f : stas) {
            System.out.println(f.getPermission().toString()+" "
                    +f.getPath().toString());
        }
        try {
            fs.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

输出的结果如下所示:

rwxr-xr-x hdfs://192.168.56.201:8020/test

代码说明:

● 第1行代码用于设置访问Hadoop的用户名。

● 第2行代码用于声明一个新的访问配置对象。

● 第3行代码设置访问的具体地址。

● 第4行代码创建一个文件系统对象。

● 第5行~8行代码为输出根目录下的所有文件或目录,不包含子目录。

● 第9行代码关闭文件系统。

(2)显示所有文件显示所有文件,使用fileSystem.listFiles函数,第二个参数boolean用于指定是否递归显示所有文件。

【代码】Demo02ListFiles.java

package org.hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;
import java.io.IOException;

public class Demo02ListFiles {
    public static void main(String[] args) {
        FileSystem fs = null;
        try {
            // 设置 Hadoop 用户名
            System.setProperty("HADOOP_USER_NAME", "hadoop");
            // 创建 Hadoop 配置对象
            Configuration config = new Configuration();
            config.set("fs.defaultFS", "hdfs://192.168.56.201:8020");
            // 获取 FileSystem 实例
            fs = FileSystem.get(config);
            // 列出 HDFS 上的文件
            RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path("/"), true);
            // 遍历并输出文件信息
            while (files.hasNext()) {
                LocatedFileStatus file = files.next();
                System.out.println(file.getPermission() + " " + file.getPath());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 确保在完成后关闭 FileSystem 实例
            try {
                if (fs != null) fs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

添加了true参数以后,执行的结果如下所示:

rw-r--r-- hdfs://192.168.56.201:8020/test/a.txt

(3)读取HDFS文件的内容

读取HDFS上的内容,可以和fileSystem.open(...)打开一个文件输入流,然后读取文件流中的内容即可。

【代码】Demo03ReadFile.java

package org.hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.DataInputStream;
import java.io.IOException;

public class Demo03ReadFile {
    public static void main(String[] args) {
        String server = "hdfs://192.168.56.201:8020";
        String filePath = "/test/a.txt"; // 文件在 HDFS 中的路径

        System.setProperty("HADOOP_USER_NAME", "hadoop");

        Configuration config = new Configuration();
        config.set("fs.defaultFS", server);

        try (FileSystem fs = FileSystem.get(config);
             DataInputStream in = fs.open(new Path(filePath))) {

            byte[] bs = new byte[1024];
            int len;
            while ((len = in.read(bs)) != -1) {
                String str = new String(bs, 0, len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(4)向HDFS写入数据

向HDFS写入数据,可以使用fileSysten.create/append方法,获取一个OutputStream,然后向里面输入数据即可。

【代码】Demo04WriteFile.java

package org.hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import java.io.OutputStream;

public class Demo04WriteFile {
    public static void main(String[] args) {
        String server = "hdfs://192.168.56.201:8020"; // HDFS 的 URI
        System.setProperty("HADOOP_USER_NAME", "hadoop"); // 设置 HDFS 用户

        Configuration config = new Configuration();
        config.set("fs.defaultFS", server);

        try (FileSystem fs = FileSystem.get(config)) {
            Path filePath = new Path("/test/b.txt"); // 文件路径
            try (OutputStream out = fs.create(filePath)) {
                out.write("Hello Hadoop\n".getBytes());
                out.write("中文写入测试\n".getBytes());
                // No need to explicitly close OutputStream, it's handled by try-with-resources
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代码输入完成以后,通过cat查看文件中的内容:

[hadoop@server201 ~]$ hdfs dfs -cat /test/b.txt

Hello Hadoop

中文写入测试

2.3 使用winutils解决警告信息

Hadoop通常运行在Linux上,而开发程序通常是Windows,执行代码时,为了看到更多的日志信息,需要添加log4j.properties或log4j2的log4j2.xml。通过查看hadoop-client-3.2.2依赖可知,系统中已经包含了log4j 1.2的日志组件,如图所示。

此时只需要添加一个log4j与slf4j整合的依赖即可,所以添加以下依赖:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.26</version>
    </dependency>

同时添加日志文件。直接在classpath下创建log4j.properties文件,即在项目的main/resources目录下添加log4j.properties文件即可:

     log4j.rootLogger = debug,stdout
     log4j.appender.stdout = org.apache.log4j.ConsoleAppender
     log4j.appender.stdout.Target = System.out
     log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
     log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:
ss,SSS} method:%l%n%m%n

再次运行上面访问HDFS的代码,将出现以下问题:

java.io.FileNotFoundException: HADOOP_HOME and hadoop.home.dir are unset

意思为HADOOP_HOME和hadoop.home.dir没有设置。虽然出现上述问题,但程序仍然可以执行成功。出现上述问题的原因是本地没有Hadoop的程序。此时,我们需要在本地,即Windows上解压一个相同的Hadoop版本,并配置HADOOP_HOME环境变量,将hadoop 3.4.0也同时解压到Windows系统的D:/program目录下(可根据实际配置),则配置环境变量为:

HADOOP_HOME=D:\program\hadoop-3.2.2

hadoop.home.dir=D:\program\hadoop-3.2.2

同时还需要添加winutils,可以从GitHub或Gitee网站上找到相关版本的winutils。将下载的文件放到D:\program\hadoop-3.4.0\bin中即可。再次运行,就没有任何警告信息了。

3. 实现MapReduce的WordCount

3.1 MapReduce的运算过程

MapReduce为分布式计算模型,分布式计算最早由Google提出。MapReduce将运算的过程分为两个阶段,map和reduce阶段。用户只需要实现map和reduce两个函数即可。这两个函数参数的形式都是以Key-Value的形式成对出现,Key为输出或输出的信息,Value为输入或输出的值。

如图展示了MapReduce的运算过程。将大任务交给多个机器分布式进行计算,然后再进行汇总合并。

图介绍如下:

第1行,Input为输入源,因为输入源是以分布式形式保存到HDFS上的,所以可以同时开启多个Mapper程序,同时读取数据。读取数据时,Mapper将接收两个输入的参数,第一个Key为读取到的文件的行号,Value为读取到的这一行的数据。

第2~3行,Mapper在处理完成以后,也将输出Key-Value对形式的数据。

第4行,是Reducer接收Mapper输入的数据,在接收数据之前进行排序操作,这个排序操作我们一般称为shuffle。注意,Reducer接收到的Value值是一个数组,多个重复Key的Value会在Reducer程序中合并成数组。

第5行,是Reducer的输出,也是以Key-Value对象的形式对外输出到文件或其他存储设备中。

以WordCount为示例,再理解一下MapReduce的过程,如图所示。

(1)标注为1的部分为Hadoop的HDFS文件系统中的文件,即被处理的数据应该首先保存到HDFS文件系统上。

(2)标注为2的部分,将接收FileInputFormat的输入数据。在处理WordCount示例时,接收到的数据key1为LongWritable类型,即为字节的偏移量。比如,标注为2的部分中第一行输入为0,其中0为字节0下标的开始;第二行为11,则11为文本中第二行字节的偏移量,以此类推。而Value1则为Text即文本类型,其中第一行Hello Jack为读取的第一行的数据,以此类推。然后,此时我们将开发代码对Value1的数据进行处理,以空格或是\t作为分割,分别将Hello和Jack依次输出。此时每一次输出的算是一个字符,所以在Map中的输出格式Key2为Text类型,而Value2则为LongWritable类型。

(3)标注为3的部分,接收Map的输出,所以Key3和Value3的类型应该与Key2和Value2的类型一致。现在只需要将Value中的值相加,就可以得到Hello出现的次数。然后直接输出给Key4和Value4。如果已经理解了这个MapReduce的过程,接下来就可以快速开发WordCount代码了。注意:LongWritable和Text为Hadoop中的序列化类型。可以简单理解为Java中的Long和String。

3.2 WordCount示例

以本地运行和服务器运行的方式分别部署,能更深入了解MapReduce的开发、运行和部署。

使用打包的方式将程序打包后放到Hadoop集群上运行。

步骤01 创建Java项目并添加依赖。

创建Java项目,并添加以下依赖。注意,本次以添加的依赖为hadoop-mincluster,且设置scope的值为provided(意思是,在打包时将不会被打包到依赖的jar包中)​。

      <dependency>
          <groupId>org.apache.hadoop</groupId>
          <artifactId>hadoop-minicluster</artifactId>
          <scope>provided</scope>
      </dependency>

步骤02 开发WordCount的完整代码。

【代码】WordCount.java

package org.hadoop;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
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;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import java.io.IOException;
public class WordCount extends Configured implements Tool {
    public static void main(String[] args) throws Exception {
        int result = ToolRunner.run(new WordCount(), args);
        System.exit(result);
    }
    //声明嗠顺地址
    private static String server = "hdfs://server201:8020";
    public int run(String[] args) throws Exception {
        if (args.length != 2) {
            System.err.println("usage: " + this.getClass().getSimpleName() + " <inPath> <outPath>");
            ToolRunner.printGenericCommandUsage(System.out);
            return -1;
        }
        Configuration config = getConf();
        config.set("fs.defaultFS", server);
        //指定resourcemanger的地址
        config.set("yarn.resourcemanager.hostname", "server201");
        config.set("dfs.replication", "1");
        config.set("dfs.permissions.enabled", "false");
        FileSystem fs = FileSystem.get(config);
        Path dest = new Path(server + args[1]);
        if (fs.exists(dest)) {
            fs.delete(dest, true);
        }
        Job job = Job.getInstance(config,"WordCount");
        job.setJarByClass(getClass());
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);
        FileInputFormat.addInputPath(job, new Path(server + args[0]));
        FileOutputFormat.setOutputPath(job, dest);
        boolean boo = job.waitForCompletion(true);
        return boo ? 0 : 1;
    }

    public static class WordCountMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
        private LongWritable count = new LongWritable(1);
        private Text text = new Text();
        @Override
        public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String str = value.toString();
            String[] strs = str.split("\\s+");
            for (String s : strs) {
                text.set(s);
                context.write(text, count);
            }
        }
    }

    public static class WordCountReducer extends Reducer<Text, LongWritable, Text, LongWritable> {
        @Override
        public void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
            long sum = 0;
            for (LongWritable w : values) {
                sum += w.get();
            }
            context.write(key, new LongWritable(sum));
        }
    }
}

上例代码中,由于我们声明了完整的地址,所以可以在本地运行测试。在本地运行测试需要输入两个参数。选择IDEA的run > Edit Configurations,并在Program Arguments位置输入读取文件的地址和输出结果的目录,如图所示。

在本地环境下直接运行,并查看HDFS上的结果目录,WordCount程序已经将结果输出到指定的目录中。

[hadoop@server201 ~]$ hdfs dfs -ls /out001

Found 2 items

-rw-r--r-- 1 mrchi supergroup 0 2024-09-13 22:14 /out001/_SUCCESS

-rw-r--r-- 1 mrchi supergroup 520 2024-09-13 22:14 /out001/part-r-00000

步骤03 使用Maven打包程序。

在IDEA右侧栏的Maven视图中,单击package并运行,可以得到一个jar包,如图所示。

打完的包可以在target目录下找到,将jar包上传到server201服务器的/root目录下,并使用yarn jar执行。

使用yarn jar执行,使用以下命令:

$ yarn jar chapter04-1.0.jar org.hadoop.WordCount /test/a.txt /out002

查看执行结果,即为单词统计的结果。根据处理的文件不同,这个结果文件的内容会有所不同。

[root@server201 ~]# hdfs dfs -cat /out002/* | head

-> 4

0 2

1 4

至此,已经学会如何在本地及打包到服务器上运行MapReduce程序了。

3.3 可能遇到的bug

注意:在本地运行时,有可能会出现以下错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.Nati veIO$Windows.access0(Ljava/lang/String;I)Z

解决方案是:将hadoop.dll文件放到windows/system32目录下即可。

4.Hbase安装配置实验

HBase是Hadoop DataBase的意思。HBase是一种构建在HDFS之上的分布式、面向列的存储系统。在需要实时读写、随机访问超大规模数据集时,可以使用HBase。HBase是Google Bigtable的开源实现,与Google Bigtable利用GFS作为其文件存储系统类似,HBase利用Hadoop HDFS作为其文件存储系统,也是利用HDFS实现分布式存储的。Google运行MapReduce来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据,Google Bigtable利用Chubby作为协同服务,HBase利用ZooKeeper作为协同服务。

HBase具有如下特点:

● 大:一个表可以有上亿行,上百万列。

● 面向列:面向列表(族)的存储和权限控制,列(族)独立检索。

● 稀疏:对于为空(NULL)的列,并不占用存储空间,因此表可以设计得非常稀疏。

● 无模式:每一行都有一个可以排序的主键和任意多的列,列可以根据需要动态增加,同一张表中不同的行可以有截然不同的列。

● 数据多版本:每个单元中的数据可以有多个版本。默认情况下,版本号自动分配,版本号就是单元格插入时的时间戳。

● 数据类型单一:HBase中的数据都是字符串,没有类型。

4.1 HBase的安装

HBase可能独立运行在一台主机上。此时HBase将只会有一个进程,即HMaster(这个HMaster内含HRegionServer和HQuorumPeer两个服务)​。虽然只有一个进程,但也可以提供HBase的大部分功能。首先需要了解HBase的版本信息,可以在HBase的官方网站上,通过hbase documents查看HBase对JDK、Hadoop版本的兼容性,尤其是对Hadoop版本具有较强依耐性。下载的地址为https://mirrors.tuna.tsinghua.edu.cn/apache/hbase

4.1.1 HBase的单节点安装

HBase单节点安装可以快速学会HBase的基本使用。HBase的单节点安装不需要Hadoop,数据保存到指定的磁盘目录下。在hbase-site.xml文件中,通过“hbase.rootdir=file:///”来指定数据保存的目录。也不需要ZooKeeper,启动后HBase将使用自带的ZooKeeper。只有一个进程Hmaster(内部包含:HRegionServer和HQuorumPeerman两个子线程)​。以下是HBase单节点安装的过程。

步骤01 上传并解压HBase(通过winscp)。

同样地,使用tar将HBase解压到/app/目录下:

$ tar -zxvf hbase-2.3.4-bin.tar.gz -C /app/

步骤02 修改配置文件。首先修改的是hbase-env.sh文件,此文件中保存了JAVA_HOME环境变量信息。配置如下:

$ vim /app/hbase-2.3.4/conf/hbase-env.sh

export JAVA_HOME=/usr/java/jdk1.8.0_281

export HBASE_MANAGES_ZK=true

再修改hbase-site.xml配置文件,此配置文件中,需要指定HBase数据的保存目录,由于目的是快速入门,所以可以先将HBase的数据保存到磁盘上。具体的配置如下:

    $ vim /app/hbase-2.3.4/conf/hbase-site.xml
    <configuration>
        <property>
            <name>hbase.rootdir</name>
            <value>file:///app/datas/hbase</value>
        </property>
        <property>
            <name>hbase.zookeeper.property.dataDir</name>
            <value>/app/datas/zookeeper</value>
        </property>
        <!--以下配置是否检查流功能-->
        <property>
            <name>hbase.unsafe.stream.capability.enforce</name>
            <value>false</value>
        </property>
    </configuration>

修改regionservers文件,此文件用于指定HRegionServer的服务器地址,由于是单机部署,所以指定本机名称即可。添加本机主机名:

$ vim regionservers server201

步骤03 启动/停止HBase。

启动HBase,只需要在HBase的bin目录下,执行start-hbase.sh即可。

     [hadoop@server201 app]$ hbase-2.3.4/bin/start-hbase.sh
    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]

启动完成以后,通过jps查看进程,会发现HMaster进程已经运行:

[hadoop@server201 app]$ jps

7940 Jps

7785 HMaster

停止HBase只需要执行stop-hbase.sh即可:

[hadoop@server201 app]$ hbase-2.3.4/bin/stop-hbase.sh

stopping hbase...

步骤04 登录HBase Shell。

在bin目录下,使用hbase shell命令登录HBase Shell,即可操作HBase数据库。登录成功后,将显示hbase >命令行。

        [hadoop@server201 app]$ hbase-2.3.4/bin/hbase shell
        HBase Shell
        Use "help" to get list of supported commands.
        Use "exit" to quit this interactive shell.
        For Reference, please visit: http://hbase.apache.org/2.0/book.html#shell
        Version 2.3.4, rafd5e4fc3cd259257229df3422f2857ed35da4cc, Thu Jan 14 21:32:2
    5 UTC 2021
        Took 0.0006 seconds
        hbase(main):001:0>

步骤05 HBase数据操作。

快速创建一个表,保存一些数据,以了解HBase是如何保存数据的。首先,如果不了解HBase命令,可以直接在HBase的命令行输入help,此命令将会显示HBase的帮助信息。

创建一个命名空间,可以理解成创建了一个数据库:

hbase(main):009:0> create_namespace 'ns1'

Took 0.1776 seconds

查看所有命名空间,可以理解成查看所有数据库:

    hbase(main):010:0> list_namespace
    NAMESPACE
    default
    hbase
    ns1
    3 row(s)
    Took 0.0158 seconds

创建一个表,在指定的命名空间下,并指定列族为“f”​。可以理解为创建一个表,并指定一个列名为f:

    hbase(main):011:0> create 'ns1:stud','f'
    Created table ns1:stud
    Took 0.8601 seconds
    => Hbase::Table - ns1:stud

向表中写入一行记录,其中R001为主键,即Row Key,f:name为列名,Jack为列值。此处与关系型数据库有很大的区别,注意区分。

    hbase(main):012:0> put 'ns1:stud','R001','f:name','Jack'
    Took 0.3139 seconds
    hbase(main):013:0> put 'ns1:stud','R002','f:age','34'
    Took 0.0376 seconds

查询表,类似于关系型数据库中的select:

    hbase(main):014:0> scan 'ns1:stud'
    ROW                              COLUMN+CELL
    R001                  column=f:name, timestamp=1568092417316, value=Jack
    R002                  column=f:age, timestamp=1568092435076, value=34
    2 row(s)
    Took 0.0729 seconds

4.1.2 HBase的伪分布式安装

HBase的伪分布式安装,是将HBase的数据保存到伪分布式的HDFS系统中。此时Hadoop环境为伪分布式,HBase的节点只有一个,HBase使用独立运行的ZooKeeper。以下步骤将配置一个HBase的伪分布式运行环境。需要:

● 配置好的Hadoop运行环境。

● 独立运行的ZooKeeper,只有一个节点即可。

● 将Hadoop的ZooKeeper指向这个独立的ZooKeeper。

步骤01 准备Hadoop和ZooKeeper。

配置好Hadoop的伪分布式运行环境。

配置好ZooKeeper的独立节点运行环境:ZooKeeper集群安装-CSDN博客

测试以上两个环境正常运行并可用。

步骤02 修改HBase配置文件。

首先修改HBase的配置文件hbase-env.sh文件,在此配置文件中,重点配置ZooKeeper选项,配置为使用外部的ZooKeeper即可。具体配置如下:

$ vim /app/hbase-2.3.4/conf/hbase-env.sh

export JAVA_HOME=/usr/java/jdk1.8.0-281

export HBASE_MANAGES_ZK=false

修改HBase配置文件hbase-site.xml文件,重点关注hbase.rootdir用于指定在Hadoop中存储HBase数据的目录。ZooKeeper用于指定ZooKeeper地址。

    <configuration>
        <property>
            <name>hbase.cluster.distributed</name>
            <value>true</value>
        </property>
        <property>
            <name>hbase.tmp.dir</name>
            <value>/app/datas/hbase/tmp</value>
        </property>
        <property>
            <name>hbase.unsafe.stream.capability.enforce</name>
            <value>false</value>
        </property>
        <property>
            <name>hbase.rootdir</name>
            <value>hdfs://server201:8020/hbase</value>
        </property>
        <property>
            <name>hbase.zookeeper.quorum</name>
            <value>server201:2181</value>
        </property>
    </configuration>

步骤03 启动HBase。

直接使用start-hbase.sh启动HBase:

$ /app/hbase-2.3.4/bin/start-hbase.sh

查看HBase的进程如下:

    [hadoop@server201 conf]$ jps
    2992 NameNode
    3328 SecondaryNameNode
    5793 Jps
    5186 Main
    3560 ResourceManager
    4120 QuorumPeerMain
    4728 HRegionServer
    3691 NodeManager
    4523 HMaster
    3119 DataNode

同样地,可以通过浏览器查看16010端口,如图所示。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值