Hadoop实验

Hadoop实验

1. Hadoop安装配置

1.1 单机版

1.1.1下载安装

浏览器前往https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/,下载hadoop-3.3.6.tar.gz ,默认下载到~/Downloads文件夹。使用sudo tar -zxf ~/Downloads/hadoop-3.3.6.tar.gz -C /usr/local将其解压安装到/usr/local中。进入到/usr/local,使用sudo mv hadoop-3.3.6/ hadoop将其目录名改成hadoop,然后使用sudo chown -R $USER /usr/local/hadoop/修改权限(注意使用绝对路径,相对路径不会影响到/usr/local导致后续出现权限问题),将hadoop目录及其子目录的所有者改为hadoop用户,避免后续操作因权限不足无法读写文件。

image-20251108171220365

使用./bin/hadoop version检查Hadoop可用性。

image-20251108182601168

1.1.2 Hadoop伪分布式配置

Hadoop可以在单节点上以伪分布式的⽅式运⾏,Hadoop进程以分离的Java进程来运⾏,单个节点既作为NameNode,也作为DataNode,同时读取的是HDFS中的⽂件。

Hadoop的运行方式是由配置⽂件决定的(运行Hadoop时会读取配置⽂件)。Hadoop的配置⽂件位于/usr/local/hadoop/etc/hadoop/ 中,伪分布式需要修改2个配置⽂件core-site.xmlhdfs-site.xml。Hadoop配置⽂件是xml格 式 ,每个配置以声明propertynamevalue的⽅式来实现。

(1)修改core-site.xml
<configuration>
	<property>
		<name>hadoop.tmp.dir</name>
		<value>file:/usr/local/hadoop/tmp</value>
		<description>A base for other temporary directories.</description>
	</property>
	<property>
		<name>fs.defaultFS</name>
		<value>hdfs://localhost:9000</value>
	</property>
</configuration>

hadoop.tmp.dir:指定了Hadoop临时⽬录的路径 。临时⽬录被设置为/usr/local/hadoop/tmp,临时⽬录⽤于存储Hadoop运行时产生的临时文件,如本地数据块、中间结果等。

fs.defaultFS:指定了默认的⽂件系统的URI。⽂件系统URI被设置为hdfs://localhost:9000, 表示使⽤Hadoop分布式⽂件系统(HDFS)作为默认⽂件系统,并且HDFS的NameNode服务器运⾏在本地主机的端口9000上。

image-20251109090750517

(2)修改hdfs-site.xml
<configuration>
	<property>
		<name>dfs.replication</name>
		<value>1</value>
	</property><property>
		<name>dfs.namenode.name.dir</name>
		<value>file:/usr/local/hadoop/tmp/dfs/name</value>
	</property>
	<property>
		<name>dfs.datanode.data.dir</name>
		<value>file:/usr/local/hadoop/tmp/dfs/data</value>
	</property>
</configuration>

dfs.replication:对于分布式⽂件系统HDFS⽽⾔, —般都是采⽤冗余存储,冗余因⼦通常为3,即—份数据保存三份副本。在伪分布式配置中,只有本机作为DataNode节点,数据只能保存—份,所以dfs.replication的值设置为1。

dfs.namenode.name.dir:⽤于配置主(Primary)NameNode的⽬录路径,表示主NameNode的数据将存储在本地⽂件系统的/usr/local/hadoop/tmp/dfs/name路径下。

dfs.datanode.data.dir:⽤于配置数据节点(DataNode)的⽬录路径,表示数据节点的数据将存储在本地⽂件系统的/usr/local/hadoop/tmp/dfs/data路径下。

image-20251109090939933

伪分布式虽然只需要配置fs.defaultFSdfs.replication就可以运⾏(官⽅教程如此)。不过若没有配置hadoop.tmp.dir参数,则默认使⽤的临时⽬录在重启时有可能被系统清理掉,导致必须重新执⾏format才⾏,所以我们进⾏了设置;同时也指定dfs.namenode.name.dirdfs.datanode.data.dir,否则在接下来的步骤中可能会出错。

(3)初始化NameNode元数据目录

初始化NameNode元数据目录(创建fsimage等文件),仅需执行一次;若多次执行,会导致元数据版本不一致,DataNode无法连接(需删除tmp目录后重新格式化)。

#NameNode的格式化
./bin/hdfs namenode -format
#开启NameNode和DataNode守护进程
./sbin/start-dfs.sh
#检查是否成功启动
jps

实验时发现即使~/.bashrc配置好了JAVA_HOME,运行./sbin/start-dfs.sh时仍然会提示ERROR: JAVA_HOME is not set and could not be found.。为此需要编辑./etc/hadoop/hadoop-env.sh,添加export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64然后source ./etc/hadoop/hadoop-env.sh,之后即可正常启动。

image-20251109095616306

image-20251109094830225

image-20251109095000780

1.2 集群版

集群环境规划:以“1个Master+2个Slave”为例,节点配置为:

Master:CPU4核、内存4GB、硬盘20GB(20G在后续安装IDEA时不够,可以的话最好40G,但这里为了方便直接克隆就用20G的)

Slave1/Slave2:CPU2核、内存4GB、硬盘20GB

1.2.1 环境配置

通过单机版实验时的快照克隆虚拟机为master,修改配置为4核4G。该快照已换源,但还未安装Java,使用sudo apt install openjdk-8-jdk进行安装,使用sudo update-alternatives --config java获取JDK根目录,然后配置~/.bashrc添加下面的内容然后source。

#set oracle jaca environment
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 
export JRE_HOME=$JAVA_HOME/jre
export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin

image-20251109102309855

关机后通过克隆得到slave1和slave2。分别修改三台虚拟机的hostname,分别为master,slave1,slave2(/etc/hosts127.0.1.1的主机名不用管,后续直接删除或注释),修改完后重启。

#修改主机名
sudo gedit /etc/hostname # 或使用sudo hostnamectl set-hostname master
#重启虚拟机,主机名修改生效
sudo reboot

重启后执行hostname,输出新主机名,说明修改成功。

执行sudo apt-get install net-tools安装网络工具,运行ifconfig查看inet地址处的虚拟机内网IP。主机名映射如下:

# Hadoop hosts
192.168.26.130 master
192.168.26.131 slave1
192.168.26.132 slave2

将其添加到/etc/hosts,同时注释或删除127.0.1.1的映射。

image-20251109115345816

hosts文件作用:将主机名映射到IP地址,避免集群节点间通过IP地址通信(便于记忆与维护),所有节点的hosts文件需配置相同的映射关系。

1.2.2 ssh配置

Hadoop集群节点间通过SSH通信(如Master向Slave发送启动命令),SSHServer需在所有节点安装,SSHClient默认已安装。

#安装SSH Server
sudo apt install openssh-server -y
# 启动ssh
sudo service ssh start 
# 设置开机⾃启
sudo systemctl enable ssh
# 确认是否设置开机⾃启成功
sudo systemctl is-enabled ssh

设置免密连接登录,通过生成RSA密钥对(公钥+私钥),将公钥复制到目标节点的authorized_keys文件中,后续登录时无需输入密码。仅在master节点执行下面命令即可。

# 生成RSA密钥对
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
# 注意master节点自己也要添加公钥(启动dfs时会用到)
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

分别在两台slave虚拟中执行以下两条命令,两台slave虚拟机都需要执行,注意是在slave虚拟机执行,其中hadoop@master @前面是用户名,后面是主机名hostname。

scp hadoop@master:~/.ssh/id_rsa.pub ~/.ssh/master_rsa.pub
cat ~/.ssh/master_rsa.pub >> ~/.ssh/authorized_keys

image-20251109122244752

1.2.3 安装Hadoop

安装hadoop 只需要在master主机中安装即可,后面会通过节点复制。

安装链接: https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common

# cd到Downloads目录,可以看到下载的hadoop包
cd ~/Downloads
ls
# 解压
tar -zxvf hadoop-3.3.6.tar.gz -C ~/

安装完成后编辑~/.bashrc修改环境变量,添加以下内容然后source。

# set Hadoop environment
export HADOOP_HOME=/home/hadoop/hadoop-3.3.6
export HADOOP_COMMON_LIB_NATIVE=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

image-20251109125508289

image-20251109125606059

1.2.4 核心配置文件

进入~/hadoop-3.3.6/etc/hadoop,修改以下配置文件(修改前建议cp备份):

  • hadoop-env.sh:Hadoop环境变量配置(指定 JAVA_HOME)

  • core-site.xml:Hadoop核心配置(默认文件系统、临时目录)

  • hdfs-site.xml:HDFS配置(副本数、元数据/数据存储路径)

  • mapred-site.xml:MapReduce配置(框架类型、历史服务器地址)

  • yarn-site.xml:YARN配置(资源管理器、节点管理器端口)

  • workers:集群节点列表(指定Slave节点主机名)

编辑hadoop-env.sh,指定JAVA_HOME

image-20251109131801744

编辑core-site.xml,添加如下内容:

<configuration>
	<property>
		<name>fs.defaultFS</name>
		<value>hdfs://master:9000</value>
		<description>hdfs namenode port</description>
	</property>
	<property>
		<name>hadoop.tmp.dir</name>
		<value>/home/hadoop/hadoop-3.3.6/tmp</value>
		<description>A base for other temporary directories</description>
	</property>
</configuration>

编辑hdfs-site.xml,添加如下内容:

<configuration>
	<property>
		<name>dfs.namenode.name.dir</name>
		<value>/home/hadoop/hadoop-3.3.6/dfs/name</value>
		<final>true</final>
	</property>
	<property>
		<name>dfs.datanode.data.dir</name>
		<value>/home/hadoop/hadoop-3.3.6/dfs/data</value>
		<final>true</final>
	</property>
	<property>
		<name>dfs.replication</name>
		<value>2</value>
		<final>true</final>
	</property>
	<property>
		<name>dfs.webhdfs.enable</name>
		<value>true</value>
	</property>
	<property>
		<name>dfs.secondary.http.address</name>
		<value>master:50090</value>
	</property>
</configuration>

编辑mapred-site.xml,添加如下内容:

<configuration>
	<property>
		<name>mapreduce.framework.name</name>
		<value>yarn</value>
	</property>
</configuration>

编辑yarn-site.xml,添加如下内容:

<configuration>
<!-- Site specific YARN configuration property -->
	<property>
		<name>yarn.resourcemanager.hostname</name>
		<value>master</value>
	</property>
	<property>
		<name>yarn.nodemanager.aux-services</name>
		<value>mapreduce_shuffle</value>
	</property>
</configuration>

workers文件作用:指定Hadoop集群中的Slave节点(DataNode与NodeManager运行节点),Master节点默认不运行DataNode(若需Master运行DataNode,可将master添加到workers文件)。

配置workers文件,加入三台主机名主机名必须一致,与在hosts中写入的hostname必须一致。

image-20251109140015074

所有节点的配置文件需完全一致,避免因配置差异导致集群通信失败;路径需使用绝对路径,且确保所有节点的路径存在(如/home/hadoop/hadoop-3.3.6/dfs/name),并设置权限(sudo chown -R $USER /home/hadoop/hadoop-3.3.6)。

1.2.5 向slave虚拟机复制hadoop节点

在master节点执行:

scp -r hadoop-3.3.6 hadoop@slave1:~/
scp -r hadoop-3.3.6 hadoop@slave2:~/

1.2.6 启动Hadoop

在master节点cd到hadoop-3.3.6中,执行以下命令格式化namenode:

./bin/hdfs namenode -format

执行后会自动在master节点启动NameNode/SecondaryNameNode,在slave节点启动DataNode。

image-20251109142259309

#启动hdfs
./sbin/start-dfs.sh
#输入jps查看节点
jps

image-20251109142827121

到slave节点输入jps查看启动情况,若是出现错误,可查看日志文件(位于~/hadoop-3.3.6/logs目录),如hadoop-master-namenode-master.log,日志中“ERROR”信息可定位问题原因。

image-20251109143038855

1.2.7 Web UI访问

在master节点浏览器输入http://master:9870(或http://192.168.26.130:9870)。若需在主机(Windows/Mac)访问,需确保虚拟机与主机在同一局域网,且关闭虚拟机防火墙。

  • Overview:查看集群状态(如启动时间、版本、容量)

  • Datanodes:查看 Slave 节点状态(如IP、存储使用率、是否活跃)

  • Browse the file system:浏览HDFS文件目录

image-20251109143636684

1.2.8 启动YARN

在master节点执行./sbin/start-yarn.sh,执行后会在Master节点启动ResourceManager,在Slave节点启动NodeManager。

image-20251109145603522

在Master节点执行jps,新增进程:ResourceManagerNodeManager(若Master在workers文件中,会启动NodeManager)。也可通过访问http://master:8088访问查看。

image-20251109145622033

在Slave节点执行jps,新增进程:NodeManager

image-20251109145659500

1.2.9 历史记录服务

历史记录服务用于记录MapReduce作业的运行日志(如提交时间、运行状态、日志链接),便于查看作业历史信息。

仅需在Master节点执行,Slave节点无需启动。

# 启动历史记录服务
./bin/mapred --daemon start historyserver
# 查看服务是否开启
jps

image-20251109195429441

2. MapReduce实验

实验使用MapReduce进行词频统计。

2.1 数据准备

在Linux系统本地创建两个文件,即文件wordfile1.txtwordfile2.txt。在实际应用中,这两个文件可能会非常大,会被分布存储到多个节点上。但是,为了简化任务,这里的两个文件只包含几行简单的内容。

针对这两个小数据集样本编写的MapReduce词频统计程序,不作任何修改,就可以用来处理大规模数据集的词频统计。

image-20251109155820135

在HDFS文件目录中创建/user/hadoop/input ,为后续上传文件准备存储路径。

hdfs dfs -mkdir -p /user/hadoop/input/

通过-p参数递归创建多级目录,确保/user/hadoop/input路径下的所有父目录不存在时自动创建。

使用put命令将本地文件上传到HDFS的指定目录。

hdfs dfs -put ~/Documents/wordfile1.txt /user/hadoop/input
hdfs dfs -put ~/Documents/wordfile2.txt /user/hadoop/input

image-20251109155951837

2.2 编写MapReduce Java程序

前往Eclipse官网下载Eclipse IDE for Java DevelopersPackage,因为installer需要Java 17,所以选择直接下载Package,解压后双击Eclipse运行即可。

image-20251109170043963

新建Project,编辑相关设置。点击Next >后点击界面中的Libraries选项卡,点击Classpath后在右侧点击Add External JARs…按钮,添加如下内容:

  • hadoop-3.3.6/share/hadoop/common/目录下的hadoop-common-3.3.6.jar和haoop-nfs-3.3.6.jar

  • hadoop-3.3.6/share/hadoop/common/lib”目录下的所有JAR包(Ctrl+A全选所有jar包)

  • hadoop-3.3.6/share/hadoop//mapreduce目录下的所有JAR包,不包括jdiff、lib-examples和sources目录

image-20251109170518690

image-20251109171548484

新建Class,编辑packagename均为wordCount后点击Finish

image-20251109173121450

编辑wordCount.java文件内容为词频统计程序代码(详见附录)。

image-20251109192015183

2.3 编译打包Java程序

编译上面编写的代码,可以直接点击Eclipse工作界面上部的运行程序的快捷按钮,当把鼠标移动到该按钮上时,在弹出的菜单中选择“Run as”,继续在弹出来的菜单中选择“Java Application”开始运行程序。程序运行结束后,会在底部的“Console”面板中显示运行结果信息。

image-20251109192305105

运行报错是正常的,因为这是个命令行应用,需要提供命令行参数,因此下面将其导出为jar包。

在Eclipse工作界面左侧的Package Explorer面板中,在工程名称wordCount上点击鼠标右键,在弹出的菜单中选择Export,如下图所示。

image-20251109192732895

在弹出的界面中选择Java-->Runable JAR file,然后点击next

image-20251109192942214

Launch configuration用于设置生成的JAR包被部署启动时运行的主类,需要在下拉列表中选择刚才配置的类wordCount-wordCount。在Export destination中需要设置JAR包要输出保存到哪个目录。在Library handling下面选择Extract required libraries into generated JAR。然后,点击Finish按钮。

image-20251109193656811

之后会弹出一个警告界面,可以忽略该界面的信息,直接点击界面右下角的OK按钮,启动打包过程。打包过程结束后,会出现一个警告信息界面,忽略。

image-20251109193844825

image-20251109193900834

至此,已经顺利把wordCount工程打包生成了wordCount.jar。可以到Linux系统中使用ls ~/myapp查看生成的JAR包文件。

image-20251109194044549

2.4 运行程序

在运行程序之前,需要确保启动Hadoop(./sbin/start-dfs.sh启动)。

在启动Hadoop之后,需要首先删除HDFS中与当前Linux用户hadoop对应的output目录,即HDFS中的/user/hadoop/output目录,这样确保后面程序运行不会出现问题。如果HDFS中已经存在目录/user/hadoop/output,执行hdfs dfs -rm -r /user/hadoop/output进行删除。

在Linux系统中,使用hadoop jar命令运行程序:

cd ~/hadoop-3.3.6
./bin/hadoop jar ~/myapp/wordCount.jar input output
# 或在任意目录下直接使用hadoop(因已配置PATH)
hadoop jar ~/myapp/wordCount.jar input output

image-20251109203711054

词频统计结果已经被写入了HDFS的/user/hadoop/output目录中。使用hdfs dfs -cat output/*查看结果。

image-20251109203857231

3. HDFS实验

3.1 常用HDFS操作

在操作前需明确HDFS的核心组件(NameNode管理元数据、DataNode存储数据块)、数据模型(文件分块存储,默认块大小128MB)、权限模型(与Linux类似,分为所有者、组、其他用户权限),避免操作时因概念混淆导致错误。

执行下面的命令准备操作的文件:

echo testHDFS > ~/Documents/testHDFS.txt
mkdir ~/Documents/localfile
touch ~/Documents/localfile/foo.txt
touch ~/Documents/localfile/asdf.txt

image-20251109190653035

执行下面的命令,前往http://master:9870browse the file system可以实时查看操作效果。

cd ~/hadoop-3.3.6 # 因配置了环境变量,也可直接使用hdfs

# 创建文件夹
./bin/hdfs dfs -mkdir -p /newDir

# 上传文件
./bin/hdfs dfs -put ~/Documents/testHDFS.txt /newDir/

# 批量上传上传本地目录下所有文件
hdfs dfs -put ~/Documents/localfile/* /newDir

# 查看HDFS中的文件和目录
hdfs dfs -ls /

mkdir ~/Documents/download
cd ~/Documents/download

# 从HDFS下载文件
hdfs dfs -get /newDir/testHDFS.txt 

# 删除HDFS中的文件
hdfs dfs -rm /newDir/testHDFS.txt

image-20251109191208518

image-20251109191346381

3.2 HDFS Java API

3.2.1 安装IDEA

进入IDEA官网,下载IDEA社区版。

# 在Downloads文件夹下解压
cd ~/Downloads
sudo tar -zxf ideaIC-2025.2.4.tar.gz -C /opt

# 修改配置文件
gedit ~/.bashrc
#添加如下环境变量
export IDEA_HOME=/opt/idea-IC-252.27397.103
export PATH=${IDEA_HOME}/bin:$PATH

# 更新启用环境变量
source ~/.bashrc

3.2.2 创建项目

cd $IDEA_HOME/bin后执行./idea.sh启动IDEA。新建项目HDFS_JavaAPIbuild system选择Maven。其他配置默认即可。

Maven作用说明:Maven是Java项目管理工具,可自动管理项目依赖(JAR包)、构建项目(编译、打包),避免手动下载与导入JAR包的繁琐操作。

Maven 项目默认结构为:

src/main/java:存放 Java 源代码(如org.example包下的JavaAPI.java)

src/main/resources:存放配置文件(如log4j.properties,用于日志配置)

src/test/java:存放测试代码(如 JUnit 测试类)

pom.xml:Maven 核心配置文件(管理依赖、构建规则)

image-20251109223058430

编辑pom.xml(Maven项目的核心文件)文件,写入以下内容,然后右键-->Maven-->Sync Project导入依赖。

<dependencies>
        <!-- Hadoop所需依赖包 -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.4</version>
        </dependency>
 
        <!-- junit测试依赖 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
</dependencies>

pom.xml作用:定义项目依赖的JAR包(如Hadoop相关JAR包、JUnit测试JAR包),Maven会根据配置自动从中央仓库下载依赖到本地仓库(默认~/.m2/repository)。

image-20251109230111271

右键test/java创建一个类JavaAPI,添加[附录](#HDFS Java API)中内容。注意init函数中的用户名配置正确

image-20251109231641259

3.2.3 测试文件准备

在本地~/Documents/localfile目录下创建text.txt(内容如"Hello HDFS Java API"),用于后续上传测试。

批量创建文件:可通过命令行快速创建(for i in {1..5}; do echo "Test file $i" > ~/Documents/localfile/text$i.txt; done,创建 text1.txt 到 text5.txt)

image-20251109232130223

3.2.4 执行Java API

单独取消testUploadFileToHDFS的注释,运行程序。

image-20251109231614314

image-20251109231712040

单独取消testDownFileToLocal的注释,运行程序。

image-20251109232415871

单独取消testRenameFile的注释,运行程序。

image-20251109232547978

单独取消testDeleteFile的注释,运行程序。

image-20251109232645489

单独取消testCheckFile的注释,运行程序。

image-20251109232849483

4. HBase安装配置实验

4.1 安装HBase

前往https://archive.apache.org/dist/hbase/2.5.4/或华为云镜像https://repo.huaweicloud.com/apache/hbase/2.5.4/下载hbase-2.5.4-bin.tar.gz,使用sudo tar -zxf ~/Downloads/hbase-2.5.4-bin.tar.gz -C /usr/local解压。

cd到/usr/local,为方便后续操作,使用sudo mv ./hbase-2.5.4 ./hbase将文件夹重命名。

使用sudo chown -R $USER ./hbase把hbase目录权限赋予给hadoop用户。

将hbase下的bin目录添加到path中,这样,启动hbase就无需到/usr/local/hbase目录下,大大的方便了hbase的使用。编辑~/.bashrc文件,添加export PATH=SPATH:/usr/local/hbase/bin,保存后source更新环境变量。也可使用下面的命令快速编辑。

echo "export PATH=$PATH:/usr/local/hbase/bin" >> ~/.bashrc
source ~/.bashrc

使用hbase version查看版本,看到输出版本消息表示HBase已经安装成功。

image-20251110100320089

此处执行发现路径中有冲突的jar包,一个在hbase目录下,另一个在hadoop目录下。但是最后面还是有正常输出版本号的。此时先忽略此问题,下一步配置HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP后即可解决。

4.2 HBase配置

编辑/usr/local/hbase/conf/hbase-env.sh文件,配置JAVA_HOMEHBASE_CLASSPATHHBASE_MANAGES_ZKHBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP

HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP:不包含Hadoop的lib,默认为false,这会导致上一步的jar包冲突。

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export HBASE_CLASSPATH=/usr/local/hbase/conf
export HBASE_MANAGES_ZK=true
export HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP=true

image-20251110102119182

编辑/usr/local/hbase/conf/hbase-site.xml,修改hbase.rootdir,指定HBase数据在HDFS上的存储路径;将属性hbase.cluter.distributed设置为true。配置内容如下。

当前Hadoop集群运行在伪分布式模式下,在本机上运行,且NameNode运行在9000端口。

hbase.rootdir指定HBase的存储目录

hbase.cluster.distributed设置集群处于分布式模式。

<configuration>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://master:9000/hbase</value>
  </property>
  <property>
    <name>hbase.unsafe.stream.capability.enforce</name>
    <value>false</value>
  </property>
</configuration>

image-20251110102905027

编辑regionservers,文件内容改为:

master
slave1
slave2

确保已启动Hadoop。输入命令jps,能看到NameNode,DataNodeSecondaryNameNode都已经成功启动,表示Hadoop启动成功。若未启动则在hadoop-3.3.6下使用./sbin/start-dfs.sh./sbin/start-yarn.sh进行启动。

切换目录至/usr/local/hbase,再使用./bin/start-hbase.sh启动HBase。输入jps,伪分布式环境下应新增HMaster进程,集群Master节点新增HMaster,Slave节点新增HRegionServer

image-20251110104704754

使用./bin/hbase shell 进入shell界面,成功进入即代表配置成功。

image-20251110105622910

停止hbase,执行后会自动停止 HMaster、HRegionServer 及内置 ZooKeeper 服务,终端显示 “stopping hbase......” 表示停止中,停止完成后无额外提示。

需先停止 HBase,再停止 Hadoop(避免 HDFS 被占用导致无法正常停止),顺序为:./bin/stop-hbase.shcd ~/hadoop-3.3.6./sbin/stop-yarn.sh./sbin/stop-dfs.sh

4.3 HBase shell使用

使用./bin/hbase shell 进入HBase shell界面,使用create 'student','Sname','Ssex','Sage','Sdept','course'创建表。此时,即创建了一个student表,属性有:Sname,Ssex,Sage,Sdept,course。因为HBase的表中会有一个系统默认的属性作为行键,无需自行创建,默认为put命令操作中表名后第一个数据。创建完student表后,可通过describe 'student'命令查看student表的基本信息。

image-20251110131806512

HBase中用put命令添加数据,注意:一次只能为一个表的一行数据的一个列,也就是一个单元格添加一个数据,所以直接用shell命令插入数据效率很低,在实际应用中,一般都是利用编程操作数据。

当运行命令:put 'student','95001','Sname','LiYing'时,即为student表添加了学号为95001,名字为LiYing的一行数据,其行键为95001。运行下面的命令为其添加数据:

put 'student','95001','Sname','LiYing'
# 为95001行下的course列族的math列添加了一个数据。
put 'student','95001','course:math','80'
# 为95001行下的Ssex列添加了一个数据。
put 'student','95001','Ssex','Male'

image-20251110132312842

HBase中有两个用于查看数据的命令:

  • get命令,用于查看表的某一行数据;
  • scan命令用于查看某个表的全部数据。
# 返回‘student’表‘95001’行的数据。
get 'student','95001'
# 返回‘student’表的全部数据
scan 'student'

image-20251110132642214

在HBase中用delete以及deleteall命令进行删除数据操作,它们的区别是:

  • delete用于删除一个数据,是put的反向操作;

  • deleteall操作用于删除一行数据。

#删除student表中95001行下的Ssex列的所有数据
delete 'student','95001','Ssex'
#删除student表中的95001行的全部数据
deleteall 'student','95001'

image-20251110132808046

删除表有两步,第一步先让该表不可用,第二步删除表。

# 使表不可用
disable 'student' 
# 删除表 
drop 'student'

image-20251110132934203

查询表历史数据。在创建表的时候,指定保存的版本数(假设指定为5)。

create 'teacher',{NAME=>'username',VERSIONS=>5}
# 插入数据然后更新数据,使其产生历史版本数据。
put 'teacher','91001','username','Mary'
put 'teacher','91001','username','Mary1'
put 'teacher','91001','username','Mary2'
put 'teacher','91001','username','Mary3'
put 'teacher','91001','username','Mary4'  
put 'teacher','91001','username','Mary5'
# 查询时,默认会查询出最新的数据,但可指定查询的历史版本数。
get 'teacher','91001',{COLUMN=>'username',VERSIONS=>5}

image-20251110133210938

最后退出数据库操作,输入exit命令即可退出,注意:这里退出HBase数据库是退出对数据库表的操作,而不是停止启动HBase数据库后台运行。

附录

词频统计程序代码

package wordCount;

import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;
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 org.apache.hadoop.util.GenericOptionsParser;

public class wordCount {
    public wordCount() {
    	
    }
     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> [<in>...] <out>");
            System.exit(2);
        }
        Job job = Job.getInstance(conf, "word count");
        job.setJarByClass(wordCount.class);
        job.setMapperClass(wordCount.TokenizerMapper.class);
        job.setCombinerClass(wordCount.IntSumReducer.class);
        job.setReducerClass(wordCount.IntSumReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class); 
        for(int i = 0; i < otherArgs.length - 1; ++i) {
            FileInputFormat.addInputPath(job, new Path(otherArgs[i]));
        }
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[otherArgs.length - 1]));
        System.exit(job.waitForCompletion(true)?0:1);
    }
    public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {
        private static final IntWritable one = new IntWritable(1);
        private Text word = new Text();
        public TokenizerMapper() {
        }
        public void map(Object key, Text value, Mapper<Object, Text, Text, IntWritable>.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 IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
        private IntWritable result = new IntWritable();
        public IntSumReducer() {
        }
        public void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.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);
        }
    }
}

HDFS Java API

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;

public class JavaAPI {

        // 可操作HDFS文件系统的对象
        FileSystem hdfs = null;

        // 测试方法执行前执行,用于初始化操作,避免频繁初始化
        @Before
        public void init() throws IOException {
            // 构造一个配置参数对象,设置一个参数:要访问的HDFS的URI
            Configuration conf = new Configuration();
            // 指定使用HDFS访问
            conf.set("fs.defaultFS","hdfs://master:9000");
            // 进行客户端身份的设置(hadoop为虚拟机的用户名,hadoop集群节点的其中一个都可以)
            System.setProperty("HADOOP_USER_NAME","hadoop");
            // 通过FileSystem的静态get()方法获取HDFS文件系统客户端对象
            hdfs = FileSystem.get(conf);
        }
   /* 上传文件
   @Test
    public void testUploadFileToHDFS() throws IOException {
        // 待上传的文件路径
        Path src = new Path("/home/hadoop/Documents/localfile/text.txt");
        // 上传之后存放的路径(HDFS)
        Path dst = new Path("/text.txt");
        // 上传
        hdfs.copyFromLocalFile(src,dst);
        System.out.println("上传成功");
    }

    */
   /* 下载
    @Test
   public void testDownFileToLocal() throws IOException {
       // 待下载的路径(HDFS)
       Path src = new Path("/text.txt");
       // 下载成功之后存放的路径
       Path dst = new Path("/home/hadoop/Documents/localfile/text1.txt");
       // 下载
       hdfs.copyToLocalFile(false,src,dst,true);
       System.out.println("下载成功");
   }

    */
  /* 重命名
  @Test
   public void testRenameFile() throws IOException {
       // 重命名之前的名字
       Path src = new Path("/text.txt");
       // 重命名之后的名字
       Path dst = new Path("/text1.txt");
       // 重命名
       hdfs.rename(src,dst);
       System.out.println("重命名成功");
   }

   */
   /*删除
   @Test
   public void testDeleteFile() throws IOException {
       // 待删除路径
       Path src = new Path("/text1.txt");
       // 删除
       hdfs.delete(src,true);
       System.out.println("删除成功");
   }

    */
    /*查看目录中的文件信息
   @Test
   public void testCheckFile() throws IOException {
       // 获取迭代器对象("/"表示获取全部目录下的文件)
       RemoteIterator<LocatedFileStatus> listFiles = hdfs.listFiles(new Path("/"), true);
       while (listFiles.hasNext()) {
           LocatedFileStatus fileStatus = listFiles.next();
           // 打印当前文件名
           System.out.println("文件名:" + fileStatus.getPath().getName());
           // 打印当前文件块大小
           System.out.println("文件块大小:" + fileStatus.getBlockSize());
           // 打印当前文件权限
           System.out.println("文件权限:" + fileStatus.getPermission());
           // 打印当前文件内容的长度
           System.out.println("文件内容长度:" + fileStatus.getLen());
           // 获取该文件块的信息(包含长度,数据块,DataNodes的信息)
           BlockLocation[] blockLocations = fileStatus.getBlockLocations();
           for (BlockLocation bl : blockLocations) {
               System.out.println("block-length:" + bl.getLength());
               System.out.println("block-offset:" + bl.getOffset());
               // 获取DataNodes的主机名
               String[] hosts = bl.getHosts();
               for (String host : hosts) {
                   System.out.println(host);
               }
           }
           System.out.println("-----------------分割线-----------------");
       }
   }
   
     */
        // 测试方法执行后执行,用于处理结尾的操作,关闭对象
        @After
        public void close() throws IOException {
            // 关闭文件操作对象
            hdfs.close();

    }

}

posted @ 2025-11-10 16:15  faf4r  阅读(44)  评论(0)    收藏  举报