springboot集成hadoop实现hdfs功能

pom.xml:

<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.8.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.8.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.8.5</version>
        </dependency>

application.properties: 


server.port=8569

#hdfs
hadoop.name-node: hdfs://192.168.4.252:9000
hadoop.namespace: /bestdir

HadoopConfig:

package com.zkaw.hadoop.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.hadoop.fs.FileSystem;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.URI;

@Configuration
@ConditionalOnProperty(name="hadoop.name-node")
@Slf4j
public class HadoopConfig {
    @Value("${hadoop.name-node}")
    private String nameNode;
    /*** Configuration conf=new Configuration();
     * 创建一个Configuration对象时,其构造方法会默认加载hadoop中的两个配置文件,
     * 分别是hdfs-site.xml以及core-site.xml,这两个文件中会有访问hdfs所需的参数值,
     * 主要是fs.default.name,指定了hdfs的地址,有了这个地址客户端就可以通过这个地址访问hdfs了。
     * 即可理解为configuration就是hadoop中的配置信息。
     * @return
     */
    @Bean("fileSystem")
    public FileSystem createFs() throws Exception{
        //读取配置文件
        org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration();
        conf.set("fs.defaultFS", nameNode);
        conf.set("dfs.replication", "1");
        conf.set("dfs.client.use.datanode.hostname", "true");
        FileSystem fs = null;
        // 指定访问hdfs的客户端身份
        fs = FileSystem.get(new URI(nameNode), conf, "root");
        // 文件系统// 返回指定的文件系统,如果在本地测试,需要使用此种方法获取文件系统
        try {
            URI uri = new URI(nameNode.trim());
            fs = FileSystem.get(uri,conf,"root");
        } catch (Exception e) {
            log.error("", e);
        }
        System.out.println("fs.defaultFS: "+conf.get("fs.defaultFS"));
        return  fs;
    }
}

HdfsController:

package com.zkaw.hadoop.controller;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

/**
 * @Author: best_liu
 * @Description:
 * @Date Create in 14:20 2023/4/21
 * @Modified By:
 */
@RequestMapping("/hdfs")
@RestController
@Slf4j
public class HdfsController {
    @Value("${hadoop.name-node}")
    private String nameNode;
    @Value("${hadoop.namespace:/}")
    private String nameSpace;

    @Autowired
    private FileSystem fileSystem;


    /*** 将本地文件srcFile,上传到hdfs
     * @param srcFile
     * @return
     */
    @PostMapping("/upload")
    public String upload( String srcFile){
        srcFile = "D:\\test.txt";
        uploadFile(srcFile);
        return "upload";
    }

    public void uploadFile(String srcFile){
        this.copyFileToHDFS(false,true,srcFile,nameSpace);
    }
    public  void copyFileToHDFS(boolean delSrc, boolean overwrite,String srcFile,String destPath) {
        // 源文件路径是Linux下的路径,如果在 windows 下测试,需要改写为Windows下的路径,比如D://hadoop/djt/weibo.txt
        Path srcPath = new Path(srcFile);
        // 目的路径
        if(StringUtils.isNotBlank(nameNode)){
            destPath = nameNode + destPath;
        }
        Path dstPath = new Path(destPath);
        // 实现文件上传
        try {
            // 获取FileSystem对象
            fileSystem.copyFromLocalFile(srcPath, dstPath);
            fileSystem.copyFromLocalFile(delSrc,overwrite,srcPath, dstPath);
            //释放资源//
//            fileSystem.close();
        } catch (IOException e) {
            log.error("", e);
        }
    }

    @PostMapping("/delFile")
    public String del(String fileName){
        rmdir(nameSpace,"test.txt") ;
        return "delFile";
    }

    public void rmdir(String path,String fileName) {
        try {
            // 返回FileSystem对象
            if(StringUtils.isNotBlank(nameNode)){
                path = nameNode + path;
            }
            if(StringUtils.isNotBlank(fileName)){
                path =  path + "/" +fileName;
            }
            // 删除文件或者文件目录  delete(Path f) 此方法已经弃用
            fileSystem.delete(new Path(path),true);
        } catch (IllegalArgumentException | IOException e) {
            log.error("", e);
        }
    }

    @PostMapping("/download")
    public String download(String fileName,String savePath){
        getFile(nameSpace+"/"+"test.txt","D:\\work\\lxjTest\\hadoopmaster");
        return "download";
    }
    /*** 从 HDFS 下载文件
     ** @param hdfsFile
     * @param destPath 文件下载后,存放地址
     */
    public void getFile(String hdfsFile,String destPath) {
        // 源文件路径
        if(StringUtils.isNotBlank(nameNode)){
            hdfsFile = nameNode + hdfsFile;
        }
        Path hdfsPath = new Path(hdfsFile);
        Path dstPath = new Path(destPath);
        try {
            // 下载hdfs上的文件
            fileSystem.copyToLocalFile(hdfsPath, dstPath);
            // 释放资源//
            fileSystem.close();
        } catch (IOException e) {
            log.error("", e);
        }
    }
}

遇到的问题

  • 这个时候你可能会高高兴兴的用postMan进行测试,发现报了下面这个错误:
 File /test/test.txt could only be replicated to 0 nodes instead of minReplication (=1).  There are 1 datanode(s) running and 1 node(s) are excluded in this operation.

但是你到回到前面访问过的那个50070web页面,发现目录里是有text.txt的,但是大小却为0

在这里插入图片描述

原因分析:

我们知道,客户端对Hdfs文件系统访问的大概流程是:

客户端通过公网ip+端口与namenode进行通信
namenode返回datanode的地址,注意是hdfs文件系统的内网地址!!!
客户端根据地址去和datanode进行连接
但是,我们是在自己的电脑去访问虚拟机,用的是公网的地址,这样当然是无法访问hdfs的内网地址,也无法和datanode建立正常的输送连接,这也是为什么namenode上有目录,但是大小却为0的原因,也是为什么web界面无法下载文件的原因

所以,我们要去想办法让namenode不要返回datanode的内网地址,而是公网的地址,这样我们才能访问和连接

解决办法:

想办法使本地可以访问到 DataNode。

1.添加一句配置,使 NameNode 返回 DataNode 的主机名而不是 IP:

conf.set("dfs.client.use.datanode.hostname", "true");

另外也可以配置 hdfs-site.xml 文件内容如下:

<property>
	<name>dfs.client.use.datanode.hostname</name>
	<value>true</value>
</property>

2.本地可以拿到了 DataNode 的主机名,要访问还需要配置本地 Hosts 映射:

windows 下 hosts 文件地址:C:\Windows\System32\drivers\etc\hosts
你的虚拟机公网ip master
192.168.4.xx master

3.结果访问正常

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Spring Boot可以通过使用Hadoop的Java API来集成Hadoop。以下是一些步骤: 1. 添加Hadoop依赖项:在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>2.7.3</version> </dependency> ``` 2. 配置Hadoop:在application.properties文件中添加以下配置: ``` # Hadoop configuration hadoop.fs.defaultFS=hdfs://localhost:900 hadoop.tmp.dir=/tmp/hadoop-${user.name} ``` 3. 创建Hadoop配置:创建一个类来设置Hadoop配置: ``` @Configuration public class HadoopConfig { @Value("${hadoop.fs.defaultFS}") private String hdfsUri; @Value("${hadoop.tmp.dir}") private String hdfsTempDir; @Bean public org.apache.hadoop.conf.Configuration configuration() { org.apache.hadoop.conf.Configuration configuration = new org.apache.hadoop.conf.Configuration(); configuration.set("fs.defaultFS", hdfsUri); configuration.set("hadoop.tmp.dir", hdfsTempDir); return configuration; } @Bean public FileSystem fileSystem() throws IOException { return FileSystem.get(configuration()); } } ``` 4. 使用Hadoop:现在可以在Spring Boot应用程序中使用Hadoop了。例如,以下代码将从本地文件系统上传文件到HDFS: ``` @Autowired private FileSystem fileSystem; public void uploadFileToHdfs(String localFilePath, String hdfsFilePath) throws IOException { Path localPath = new Path(localFilePath); Path hdfsPath = new Path(hdfsFilePath); fileSystem.copyFromLocalFile(localPath, hdfsPath); } ``` 这些步骤应该可以帮助你在Spring Boot应用程序中集成Hadoop。 ### 回答2: Spring Boot是一个快速构建基于Spring框架的Java应用程序的开源框架。而Hadoop则是用于处理大数据的分布式环境下的计算框架。Spring BootHadoop 的结合可以使大数据的处理更加方便、高效。 要在Spring Boot集成Hadoop,需要使用Hadoop 的Java API 来连接Hadoop集群。首先,需要在项目的pom.xml文件中添加依赖项,在dependencies标签内,添加如下代码即可: ``` <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-core</artifactId> <version>${hadoop.version}</version> </dependency> ``` 其中${hadoop.version}变量是Hadoop的版本号。 接下来,需要在application.yml文件中添加Hadoop的配置属性,如下所示: ``` fs.defaultFS: hdfs://localhost:9000 dfs.replication: 1 ``` 这里的fs.defaultFS属性设置了连接Hadoop集群的地址,dfs.replication设置了副本数量。 然后,在Spring Boot中编写Hadoop 的代码,只需要调用Hadoop Java API即可。例如,使用Hadoop读写文件的示例代码如下所示: ``` @Autowired private ApplicationContext context; Configuration conf = context.getBean(Configuration.class); FileSystem fs = FileSystem.get(conf); Path inputPath = new Path("/input_file_path"); FSDataInputStream fsDataInputStream = fs.open(inputPath); byte[] data = new byte[fsDataInputStream.available()]; fsDataInputStream.readFully(data); fsDataInputStream.close(); ``` 在以上代码中,使用Spring Boot的@Autowired注解来注入Spring容器中的Configuration对象,以获取Hadoop的配置信息。然后使用FileSystem.get(conf)获取FileSystem对象,接着就可以直接使用Hadoop Java API来操作文件系统。 需要注意的是,Hadoop集群的搭建和部署需要一定的技术要求和专业知识,因此,需要有一定的技术功底并遵循正确的操作流程。同时,在实际应用中,需要根据项目需求来设计并优化Hadoop集群的配置,才能使得数据处理更加高效和稳定。 总的来说,Spring Boot集成Hadoop可以帮助企业更好的利用数据,并有效的提升分析数据效率,并在实际应用中高度自定义。 ### 回答3: Springboot是一个Java开发框架,它提供了快速创建、运行Spring应用程序的方式。同时,Hadoop是一个分布式计算框架,能够对大量数据进行分布式处理。 在实际应用中,Springboot集成Hadoop能够极大地提高数据处理的效率和可靠性。下面,我们就一步步介绍如何实现SpringbootHadoop集成。 1、配置Hadoop环境 在Springboot中与Hadoop集成需要进行相关的配置,首先需要安装Hadoop并进行配置。配置过程包括修改相关配置文件和设置Hadoop环境变量等。 2、导入依赖 接下来需要在Springboot项目中导入相关依赖。这些依赖包括hadoop-core、hadoop-common、hadoop-hdfs等。导入依赖之后,编写相应的代码即可实现基于SpringbootHadoop集成。 3、编写Hadoop客户端代码 针对不同的业务需求,需要编写相关的Hadoop客户端代码。这些代码包括文件上传、文件下载、文件删除、文件列表查询等。 4、编写Springboot业务层代码 在Springboot项目中,需要在业务层编写相关的代码,例如:输入输出类、Mapper类、Reducer类、Driver类等等。 总结: 在Springboot集成Hadoop的过程中,需要足够的代码编写能力以及对Hadoop的深入了解。只有在掌握了相关技术和方法之后,才能够将它们结合在一起,提高数据预处理的效率和可靠性。此外,还可以在集成过程中使用Springboot提供的自动配置功能,简化代码编写过程,加快开发速度。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值