目录
一、Hadoop介绍
二、HDFS的本地模式
三、伪分布模式
四、Hdfs中的shell命令
五、全分布搭建
六、使用Java代码操作HDFS
1、环境准备
2、单元测试(Junit)编辑
一、Hadoop介绍
Hadoop 分为三部分 : Common、HDFS 、Yarn、MapReduce(有点过时了)
Hadoop生态圈:除了hadoop技术以外,还有hive、zookeeper、flume、sqoop、datax、azkaban等一系列技术。
Hadoop 是 道格·卡丁 本身他是Lucene的创始人。
Lucene 其实是一个jar包。
检索现在主流的是Solr以及ES(Elastic Search)。
比如现在每一个网站,都有一个检索的输入框,底层技术: Solr (稍微有点过时了) , ES (正在流行中)
首先面临的问题是:海量数据如何存储?
根据谷歌推出的三篇论文:
BigTable -- HBase
GFS -- HDFS
MapReduce -- MapReduce
并将这些技术统称为 Hadoop (Logo 大象)。
Hadoop的三个版本:
Apache 版本(开源版本) 3.3.1 非常的新了
Cloudera 版本--商⽤版(道格·卡丁) CDH
Hortonworks --hadoop的代码贡献者在这家公司非常的多。
现在各个大公司都在推出自己的大数据平台--> 大数据平台开发工程师
DataLight --> 国产的CDH平台
二、HDFS的本地模式
hdfs: 分布式文件管理系统
海量数据存储的终极解决方案:整出来一个平台,这个平台的服务器可以无限扩展。
HDFS : 解决海量数据的存储问题 1p = 1024 T
Yarn : 计算的资源基础,所有的MR任务需要运行在Yarn上。
MapReduce:解决计算问题,它是一个计算框架(需要写代码的)
思考一个问题:
淘宝平台:拥有海量商户,每一个商户都有很多商品,每一个商品需要上传很多照片,照片得高清,一张照片5M左右。淘宝如何解决海量图片的储存问题?-- 淘宝拥有一个技术 FastDFS,搭建一个图片集群,这个集群中的服务器,可以无限拓展。而且一张照片存3份。
人类的思想拓展非常快,数据存储在哪里是安全的?任何一家公司都不靠谱,政府不靠谱。全人类最靠谱,能不能将全人类的硬盘全部连起来,变成一个大硬盘。假如一个人贡献自己的硬盘,假如我在你的电脑上放了数据,我就会给你奖励。假如你使用了别人的硬盘,需要付费。 --国家定义为基础设施。
使用虚拟货币结算,而且只支持 fil 这个币。
HDFS三种模式:本地模式,伪分布模式,全分布模式
HDFS-- 分布式文件存储系统
Fil币挖矿
FastDFS(阿里巴巴)
原理都是一样的。
都是将多台电脑,硬盘组合在一起,形成一个文件存储系统,任何人都可以上传下载文件到这个平台上,数据自动备份,自动容灾。
如果文件系统空间不够了,直接添加电脑即可,完美对接之前的服务器。
如果中间服务器坏掉了,也不影响数据的完整性。
配置:
使用一下hadoop这个软件(案例WordCount):
词频统计就是我们大数据中的HelloWorld!
在 /home 下创建了一个文件 wc.txt 命令: touch wc.txt
需要统计的词如下:
hello world spark flink
hello cfxj 2202 laolv
hello suibian suibian hello
接着使用自动的wordCount工具进行统计:
hadoop jar /opt/installs/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.1.jar wordcount /home/wc.txt /home/output
hadoop jar 执行某个jar包(其实就是java代码)
/opt/installs/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.1.jar 这个是jar的地址
/home/wc.txt 要统计的文件
/home/output 统计结果放哪里
如果统计的结果文件夹已经存在,会报错。
上面总结一下:
数据在本地磁盘上 /home/wc.txt
计算的结果也是在本地磁盘上 /home/ouput
案例二:PI的计算
hadoop jar /opt/installs/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.1.jar pi 10 100
10 代表10个任务
100 代表的是100次/每个任务
三、伪分布模式
伪分布:按照分布式的步骤搭建,但是呢,服务器只有一台。
只能用于开发、和学习用。
比如我想搭建一个集群,将集群中的所有磁盘连接在一起形成一个云端的hdfs.
但是公司就买了一台服务器。所以搭建出来的就是伪分布模式。
伪分布的意思:按照全分布的步骤搭建的集群,但是linux服务器只有一台。
进行搭建之前的一些准备工作:
配置开始:
位置: /opt/installs/hadoop/etc/hadoop
以下圈住的都是重要的文件:
<configuration>
<!-- 设置namenode节点 -->
<!-- 注意: hadoop1.x时代默认端⼝9000 hadoop2.x时代默认端⼝8020 hadoop3.x时 代默认端⼝ 9820 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://bigdata01:9820</value>
</property>
<!-- hdfs的基础路径,被其他属性所依赖的⼀个基础路径 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/installs/hadoop/tmp</value>
</property>
</configuration>
<configuration>
<property>
<!--备份数量-->
<name>dfs.replication</name>
<value>1</value>
</property>
<!--secondarynamenode守护进程的http地址:主机名和端⼝号。参考守护进程布局 -->
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>bigdata01:9868</value>
</property>
<!-- namenode守护进程的http地址:主机名和端⼝号。参考守护进程布局 -->
<property>
<name>dfs.namenode.http-address</name>
<value>bigdata01:9870</value>
</property>
</configuration>
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
export JAVA_HOME=/opt/installs/jdk
修改workers 文件:
vi workers
修改里面的内容为: bigdata01 保存
对整个集群记性namenode格式化:
hdfs namenode -format
格式化其实就是创建了一系列的文件夹:
这个文件夹的名字是 logs tmp
假如你想格式化第二次,需要先删除这两个文件夹,然后再格式化
启动集群:
start-dfs.sh
通过网址访问hdfs集群:
http://192.168.233.128:9870/
如果访问不到:检查防火墙是否关闭。
测试一下这个hdfs的文件系统:
目前搭建的这个到底是hdfs的伪分布还是hadoop伪分布?
答案是 hdfs的伪分布,但是hdfs 也是hadoop的一部分。
真正的hadoop伪分布还需要配置yarn 才算真正的伪分布。
使用这个文件系统:
1、将要统计的内容上传至hdfs文件系统
hdfs dfs -mkdir /home
hdfs dfs -put /home/wc.txt /home
2、使用wordcount统计wc.txt
hadoop jar /opt/installs/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.1.jar wordcount /home/wc.txt /home/ouput
3、查看统计结果
hdfs dfs -cat /ouput/*
假如你的环境是伪分布式模式,那么本地模式直接被替换了,回不去了。
此模式跟本地模式有何区别?
这两种方式,首选统计的代码都在本地,但是本地模式,数据和统计的结果都在本地。
伪分布模式,它的数据来源在 hdfs 上,统计结果也放在 hdfs上。
如果此时再执行以前的workcount就会报错,原因是以前是本地模式,现在是伪分布模式,伪分布模式,只会获取hdfs上的数据,将来的结果也放入到hdfs上,不会获取本地数据:
四、Hdfs中的shell命令
假如你想通过web界面查看一个文件的内容,点击报错:
Couldn't preview the file. NetworkError: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'http://bigdata01:9864/webhdfs/v1/output/part-r-00000?op=OPEN&namenoderpcaddress=bigdata01:9820&offset=0&_=1692068863115'.
默认是要报错的,因为这是一种安全机制,可以修改一下:
在hdfs-site.xml 中添加如下配置:
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
在windows本机,修改hosts映射关系。
C:\Windows\System32\drivers\etc\hosts
修改内容如下:
192.168.233.128 bigdata01
关于hdfs文件系统,有三种操作方式:
1、图形化界面 比如 http://IP地址:9870
2、shell命令操作 比如 hdfs dfs -put 上传 -cat 查看
3、通过java代码操作
shell命令操作:东西特别的多,只学其中一些。
hdfs dfs -moveFromLocal 本地文件 hdfs的路径
跟put上传不一样的是,move结束后,本地文件会消失
hdfs dfs -get hdfs的路径 本地文件 此操作要谨慎
hdfs dfs -cp /log.txt /ouput 将hdfs上的一个文件拷贝到另一个文件夹
hdfs dfs -chmod 777 /wc.txt hdfs上的文件也可以赋权限
五、全分布搭建
全分布模式:必须至少有三台以上的Linux。
前期准备工作:
1、准备三台服务器
目前有两台,克隆第二台(因为第二台没有安装mysql), 克隆结束后,进行修复操作
1) 修改IP 2) 修改主机名 3)修改映射文件hosts
检查是否满足条件:
环境准备⼯作:
1、安装了jdk
2、设置host映射
192.168.32.128 bigdata01
192.168.32.129 bigdata02
192.168.32.130 bigdata03
远程拷贝:
scp -r /etc/hosts root@bigdata02:/etc/
scp -r /etc/hosts root@bigdata03:/etc/
3、免密登录
bigdata01 免密登录到bigdata01 bigdata02 bigdata03
ssh-copy-id bigdata03
4、第一台安装了hadoop
5、关闭了防⽕墙
systemctl status firewalld
6、修改linux的⼀个安全机制
vi /etc/selinux/config
修改⾥⾯的 SELINUX=disabled
一定要确保三台电脑上的hosts文件都是:
192.168.32.128 bigdata01
192.168.32.129 bigdata02
192.168.32.130 bigdata03
修改一台,长拷贝到其他两台:
scp -r /etc/hosts root@bigdata01:/etc
scp -r /etc/hosts root@bigdata02:/etc
2、检查各项内容是否到位
如果以前安装的有伪分布模式,服务要关闭。 stop-dfs.sh
3、修改bigdata01配置文件
路径:/opt/installs/hadoop/etc/hadoop
跟伪分布一样:不需要修改
<configuration>
<!-- 设置namenode节点 -->
<!-- 注意: hadoop1.x时代默认端⼝9000 hadoop2.x时代默认端⼝8020 hadoop3.x时 代默认端⼝ 9820 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://bigdata01:9820</value>
</property>
<!-- hdfs的基础路径,被其他属性所依赖的⼀个基础路径 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/installs/hadoop/tmp</value>
</property>
</configuration>
<configuration>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<!--secondarynamenode守护进程的http地址:主机名和端⼝号。参考守护进程布局 -->
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>bigdata02:9868</value>
</property>
<!-- namenode守护进程的http地址:主机名和端⼝号。参考守护进程布局 -->
<property>
<name>dfs.namenode.http-address</name>
<value>bigdata01:9870</value>
</property>
</configuration>
跟伪分布一样,不需要修改
export JAVA_HOME=/opt/installs/jdk
# Hadoop3中,需要添加如下配置,设置启动集群⻆⾊的⽤户是谁
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
修改workers
bigdata01
bigdata02
bigdata03
修改完了第一台的配置文件,开始分发到其他两台上去。
假如以前没有将bigdata01上的hadoop 拷贝给 02 和 03
那么就远程拷贝:
scp -r /opt/installs/hadoop/ bigdata02:/opt/installs/
scp -r /opt/installs/hadoop/ bigdata03:/opt/installs/
如果以前已经拷贝过了,只需要拷贝刚修改过的配置文件即可:
只需要复制配置文件即可
scp -r /opt/installs/hadoop/etc/hadoop/ bigdata02:/opt/installs/hadoop/etc/
scp -r /opt/installs/hadoop/etc/hadoop/ bigdata03:/opt/installs/hadoop/etc/
拷贝环境变量:
scp -r /etc/profile root@bigdata02:/etc/
scp -r /etc/profile root@bigdata03:/etc/
在02 和 03 上刷新环境变量 source /etc/profile
4、格式化namenode
hdfs namenode -format
5、启动hdfs
只在第一台电脑上启动
start-dfs.sh
启动后jps,看到
bigdata01 | bigdata02 | bigdata03 |
namenode | secondaryNameNode | x |
datanode | datanode | datanode |
web访问:namenode 在哪一台,就访问哪一台。http://bigdata01:9870
总结:
1、start-dfs.sh 在第一台启动,不意味着只使用了第一台,而是启动了集群。
stop-dfs.sh 其实是关闭了集群
2、一台服务器关闭后再启动,上面的服务是需要重新启动的。
这个时候可以先停止集群,再启动即可。也可以使用单独的命令,启动某一个服务。
hadoop-daemon.sh start namenode # 只开启NameNode
hadoop-daemon.sh start secondarynamenode # 只开启SecondaryNameNode
hadoop-daemon.sh start datanode # 只开启DataNode
hadoop-daemon.sh stop namenode # 只关闭NameNode
hadoop-daemon.sh stop secondarynamenode # 只关闭SecondaryNameNode
hadoop-daemon.sh stop datanode # 只关闭DataNode
3、namenode 格式化有啥用
相当于在整个集群中,进行了初始化,初始化其实就是创建文件夹。创建了什么文件夹:
logs tmp
你的hadoop安装目录下。
六、使用Java代码操作HDFS
上传文件,创建文件夹,删除文件,下载等等
1、环境准备
1)解压hadoop的安装包
2)配置环境变量
;%HADOOP_HOME%\bin;%HADOOP_HOME%\sbin;
如果你出现了如下错误:
他的意思是你的java_home ,需要修改一个地方:
在 /etc/hadoop 下的 hadoop-env.cmd 中大约25行
set JAVA_HOME=C:\PROGRA~1\Java\jdk1.8.0_144
一定确保你的jdk路径是正确的。
Program Files == PROGRA~1
黑窗口先关闭,再打开即可。
最后一项:
粘贴一个补丁文件:
另外,假如你的 java 版本有问题,也会报这个错误,比如我们需要 64 位的操作软件,你安装了一个 32 位的,请卸载 jdk,并重新安装和配置环境变量。
2、单元测试(Junit)
类似于Main方法。
首先需要导入Junit包:
Welcome to Apache Maven – Maven
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
第二步:写单元测试代码
最好写在test 文件夹下(专门写测试的文件夹)
单元测试方法:
1、方法上必须有@Test注解
2、方法必须是public void 开头
3、方法没有参数
4、不要将类名写成Test,后果自负
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestUnit {
@Before // 每次单元测试方法执行前都会执行该方法 该方法一般存放一些初始化的代码
public void init(){
System.out.println("我是开始代码");
}
@After// 每次单元测试方法执行后都会执行该方法 该方法一般都是存放一些连接关闭等收尾工作
public void destory(){
System.out.println("我是结束代码");
}
@Test // 该方法即一个单元测试方法,这个方法是一个独立的方法,类似于Main方法。
public void testA(){
System.out.println("Hello World!");
}
@Test
public void testB(){
System.out.println("Hello World!");
}
}
以下是通过chatgpt帮我生成的代码:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class MyUnitTest {
@Before
public void setUp() {
// 在每个测试方法之前执行的准备工作
System.out.println("setUp() method called");
}
@After
public void tearDown() {
// 在每个测试方法之后执行的清理工作
System.out.println("tearDown() method called");
}
@Test
public void testMethod1() {
// 测试方法1
System.out.println("testMethod1() called");
// 添加测试逻辑和断言
}
@Test
public void testMethod2() {
// 测试方法2
System.out.println("testMethod2() called");
// 添加测试逻辑和断言
}
}
第三步:使用java代码连接hdfs
获取hdfs连接的四种方法:
首先导入需要的jar包:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>3.3.1</version>
</dependency>
代码演示:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
public class Demo01 {
@Test
public void test01() throws IOException {
// 配置的意思
Configuration configuration = new Configuration();
// hdfs的连接地址
configuration.set("fs.defaultFS","hdfs://192.168.32.128:9820");
FileSystem fileSystem = FileSystem.get(configuration);
System.out.println(fileSystem);
}
@Test
public void test02() throws Exception {
// URL 和 URI
// URL 和 URI
// URL = 中华人民共和国
// 指的是互联网上比较具体的第一个内容,地址
// URI = 共和国 员工的编号9527
// cookie session
FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.32.128:9820"), new Configuration());
System.out.println(fileSystem);
}
@Test
public void test03() throws Exception {
// 配置的意思
Configuration configuration = new Configuration();
// hdfs的连接地址
configuration.set("fs.defaultFS","hdfs://192.168.32.128:9820");
FileSystem fileSystem = FileSystem.newInstance(configuration);
System.out.println(fileSystem);
}
@Test
public void test04() throws Exception {
// 配置的意思
Configuration configuration = new Configuration();
FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://192.168.32.128:9820"),configuration);
System.out.println(fileSystem);
}
}
通过代码上传一个文件到hdfs上。
public class Demo02 {
@Test
public void testUpload() throws Exception {
System.setProperty("HADOOP_USER_NAME","root");
Configuration configuration = new Configuration();
configuration.set("fs.defaultFS","hdfs://192.168.32.128:9820");
FileSystem fileSystem = FileSystem.get(configuration);
Path localPath = new Path("D:\\a.txt");
Path hdfsPath = new Path("/");
fileSystem.copyFromLocalFile(localPath,hdfsPath);
System.out.println("上传成功!");
}
}
System.setProperty("HADOOP_USER_NAME","root");
package com.bigdata;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
public class HdfsUtils {
private FileSystem fileSystem;
@Before
public void setUp() throws IOException {
System.setProperty("HADOOP_USER_NAME","root");
// 在每个测试方法之前执行的准备工作
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://bigdata01:9820"); // 设置 HDFS 地址
fileSystem = FileSystem.get(conf);
}
@After
public void tearDown() throws IOException {
// 在每个测试方法之后执行的清理工作
fileSystem.close();
}
@Test
public void testUploadFile() throws IOException {
String localFilePath = "C:\\Users\\admin\\Desktop\\edip";
String hdfsFilePath = "/";
fileSystem.copyFromLocalFile(new Path(localFilePath), new Path(hdfsFilePath));
}
@Test
public void testCreateFile() throws IOException {
String hdfsFilePath = "/newfile.txt";
fileSystem.createNewFile(new Path(hdfsFilePath));
}
@Test
public void testDownloadFile() throws IOException {
String hdfsFilePath = "/newfile.txt";
String localFilePath = "C:\\Users\\admin\\Desktop\\file.txt";
fileSystem.copyToLocalFile(new Path(hdfsFilePath), new Path(localFilePath));
}
@Test
public void testDeleteFile() throws IOException {
String hdfsFilePath = "/newfile.txt";
fileSystem.delete(new Path(hdfsFilePath), false);
}
@Test
public void testMkDir() throws IOException {
fileSystem.mkdirs(new Path("/input"));
System.out.println("创建文件夹成功");
}
@Test
public void testRename() throws IOException {
fileSystem.rename(new Path("/edip"),new Path("/aaa.txt"));
}
// 打印 一个目录下的所有文件,包含文件夹中的文件
@Test
public void testLs() throws Exception {
// rm -r
RemoteIterator<LocatedFileStatus> iterator = fileSystem.listFiles(new Path("/"), true);
while(iterator.hasNext()){
LocatedFileStatus locatedFileStatus = iterator.next();
System.out.println(locatedFileStatus.getPath().getName());
}
}
// 返回当前目录下的所有文件以及文件夹
@Test
public void testList2() throws Exception {
FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));
for (FileStatus fileStatus : fileStatuses) {
System.out.println(fileStatus.getPath().getName());
}
}
}
下载中如果报错了:
需要将hadoop.dll 拷贝到 C:\windows\system32 这个文件夹下一份。