大数据问题排查系列-hdfsfilesystemapi的正确打开方式,你get了吗?(代码片段)

明哥的IT随笔 明哥的IT随笔     2022-12-25     641

关键词:

大数据问题排查系列 - HDFS FileSystem API 的正确打开方式,你 GET 了吗?

前言

大家好,我是明哥!

本片博文是“大数据问题排查系列”之一,我们首先会聊聊一个问题的现象原因和解决方法,然后给出 HDFS FileSystem API 常见的两种使用方式,最后来看下 HDFS 源码中是如何根据用户的配置文件创建对应的 FileSystem 对象实例的。

以下是正文。

从一个报错聊起

  • 问题现象:某 JAVA 作业需要读取 HDFS 文件系统中的文件,作业提交后报错如下:
java.io.IOException: No FileSystem for scheme: hdfs
    at org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2584)
    at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2591)
  • 问题原因:类加载路径上缺少 hdfs 相关 Jar包 hadoop-hdfs-*.jar,导致org.apache.hadoop.fs.FileSystem 创建 FileSystem实列 时没有创建 org.apache.hadoop.hdfs.DistributedFileSystem,所以当配置文件中配置 fs.defaultFS 为 hdfs://nameservice1 时,会寻找 hdfs scheme 即org.apache.hadoop.hdfs.DistributedFileSystem,此时自然找不到,就会报上述错误。

  • 问题解决:只需要确保类的 Classpath 下有对应的 hdfs相关 jar报即可解决上述报错(注意在分布式环境中可能会涉及到不同 classloader下不同的加载机制),具体来讲:

  1. 可以在 pom中添加相关依赖:
        <dependency>
        <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.7.4</version>
        </dependency>
  1. 在linux上提交时,可以通过类似以下命令确保类加载路径上包含相关 hdfs jar包:
java -cp ./test-1.0-SNAPSHOT-jar-with-dependencies.jar:`hadoop classpath` com.hundsun.HdfsTest core-site-test.xml hdfs-site-test.xml

HDFS FileSystem api 常见的两种方式

粗略来看,通过 HDFS FileSystem api 创建 FileSystem 实例时,主要有两种方式,两者在如何配置访问不同集群的 HDFS 上略有差异。以下是示例代码。

  1. 方式一:代码使用原生JAVA,目标 hdfs 集群的配置信息,通过导出目标集群中的配置文件core-site 和 hdfs-site.xml并放到特定路径下加载进来
package com.mingge.hdfs.demo;

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

import java.io.IOException;

public class HdfsTest 

    /**
     *
     1. If there are configuration files in the classpath with default names like core-site.xml, hdfs-site.xml,
     The Configuration class will automatically load them;
     2. If your configuration files are not following the default names like core-site.xml, hdfs-site.xml,
     you must load them explicitly;
     3. If the configuration files are already in the classpath, you can load them this way:
     conf.addResource(Thread.currentThread().getContextClassLoader().getResourceAsStream(coreConfPath));
     4. If the configuration files are not in the classpath, you can load them this way:
     conf.addResource(new Path(coreConfPath));
     */
    public static void main(String[] args) 
        Configuration conf = new Configuration();
        // paths to configuration files
        String coreConfPath = null;
        String hdfsConfPath = null;
        coreConfPath = args[0];
        hdfsConfPath = args[1];
        // you can use absolute paths, like below on windows:
//        coreConfPath = "E:\\\\git\\\\test\\\\src\\\\main\\\\resources\\\\core-site-test.xml";
//        hdfsConfPath = "E:\\\\git\\\\test\\\\src\\\\main\\\\resources\\\\hdfs-site-test.xml";
        // If you use relative paths, the files must be in the cwd, which can be get by System.getProperty("user.dir");
//        coreConfPath = "core-site-test.xml";
//        hdfsConfPath = "hdfs-site-test.xml";
//        conf.addResource(new Path(coreConfPath));
//        conf.addResource(new Path(hdfsConfPath));

        // if the configuraton files are already in the classpath, you can also use below codes to load them:
        conf.addResource(Thread.currentThread().getContextClassLoader().getResourceAsStream(coreConfPath));
        conf.addResource(Thread.currentThread().getContextClassLoader().getResourceAsStream(hdfsConfPath));
//        System.getenv().forEach((key,value) -> System.out.println(key.toString() + value.toString()));
//        System.getProperties().forEach((key,value) -> System.out.println(key.toString() + value.toString()));
//        conf.iterator().forEachRemaining((confItem)-> System.out.println(confItem.toString()));

        System.out.println("user dir is: " + System.getProperty("user.dir"));
        try  FileSystem fileSystem = FileSystem.get(conf);
        for (FileStatus status: fileSystem.listStatus(new Path("/")))
            System.out.println(status.getPath());
        
        catch (IOException e) 
            e.printStackTrace();
        
    

  1. 方式二:代码使用 spring 框架,目标HDFS 集群相关配置信息,配置在 properties 配置文件中:
package com.mingge.hdfs.demo;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;

/**
 * Created by xxx on xxx.
 */
@Configuration
public class HdfsConfig 

    private final Logger log = Logger.getLogger(this.getClass());

    @Value("$fs.default.name")
    String fs_default_name;

    @Value("$fs.namenode.isha:false")
    boolean fs_namenode_isha;

    @Value("$fs.namenode.address:")
    private String fs_namenode_address;

    @Value("$hadoop.security.authentication:")
    String hadoop_auth;

    @Value("$key.user:")
    String key_user;

    @Value("$key.path:")
    String key_path;

    @Value("$java.security.krb5.conf:")
    String kbr5_conf;

    @Value("$dfs.namenode.kerberos.principal:")
    String dfs_namenode_kerberos_principal;

    @Bean(name = "configuration1")
    public org.apache.hadoop.hdfs.HdfsConfiguration configuration()
        org.apache.hadoop.hdfs.HdfsConfiguration conf = new HdfsConfiguration();
        if(fs_namenode_isha)
            String clusterName = "clusterName";
            conf.set("fs.defaultFS", fs_default_name);
            conf.set("dfs.nameservices", clusterName);
            if(StringUtils.isBlank(fs_namenode_address))
                throw new RuntimeException("fs.namenode.address 不能为空");
            
            int i = 0;
            StringBuilder nodes = new StringBuilder();
            for(String address : fs_namenode_address.split(","))
                i++;
                nodes.append(",nn").append(i);
                conf.set("dfs.namenode.rpc-address."+clusterName+".nn" + i, address);
            
            conf.set("dfs.ha.namenodes."+clusterName, nodes.substring(1));
            //conf.setBoolean(name, value);
            conf.set("dfs.client.failover.proxy.provider."+clusterName,
                    "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
        else
            conf.set("fs.default.name",fs_default_name);
        
        conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
        if (StringUtils.isNotBlank(kbr5_conf)) 
//            System.setProperty("HADOOP_USER_NAME", user); //设置当前window/linux下用户为HBase可访问用户
            System.setProperty("java.security.krb5.conf", kbr5_conf );
            /** 使用Hadoop安全登录 **/
            conf.set("hadoop.security.authentication", hadoop_auth);
            conf.set("dfs.namenode.kerberos.principal", dfs_namenode_kerberos_principal);
            try 
                UserGroupInformation.setConfiguration(conf);
                UserGroupInformation.loginUserFromKeytab(key_user, key_path);
                log.info("=========================kerberos登录成功==============================");

             catch (IOException e1) 
                log.error("=====================登录错误==================:",e1);
                e1.printStackTrace();
            
        
        return conf;
    


HDFS 源码中是如何根据用户的配置文件创建对应的 FileSystem 对象实例的?

通过以上方法一的代码,我们不难发现,只要在类的加载路径上有配置文件core-site.xml和hdfs-site.xml,两行简单的如下语句就可以创建好指向目标 hdfs 集群的 FileSystem对象实例:

Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.get(conf)

这背后的原理,其实涉及到源码中类 org.apache.hadoop.conf.Configuration 和 org.apache.hadoop.hdfs.HdfsConfiguration,尤其是其如下静态代码块,截图如下:

相关知识点,总结如下:

  • If there are configuration files in the classpath with default names like core-site.xml, hdfs-site.xml, the Configuration class will automatically load them;
  • If your configuration files are not following the default names like core-site.xml, hdfs-site.xml, you must load them explicitly;
  • If the configuration files are already in the classpath, you can load them this way: conf.addResource(Thread.currentThread().getContextClassLoader().getResourceAsStream(coreConfPath));
  • If the configuration files are not in the classpath, you can load them this way: conf.addResource(new Path(coreConfPath));

大家可以在 IDE 工具中导入以上方法一的代码,DEBUG 调试下以了解其中的细节。以下是笔者排查上述问题时,debug过程中的相关截图:

!关注不迷路~ 各种福利、资源定期分享!欢迎小伙伴们扫码添加明哥微信,后台加群交流学习。

大数据问题排查系列-hive踩坑记

前言大家好,我是明哥!本片博文是“大数据线上问题排查系列”大类别之一,讲述前段时间我司某产品在某券商遇到的一个问题及解决方案,其背后涉及到hive的一个BUG,在hive3.0才修复。以下是正文。问题现象cdh6... 查看详情

大数据线上问题排查系列-hive踩坑记(代码片段)

大数据线上问题排查系列-HIVE踩坑记前言大家好,我是明哥!本片博文是“大数据线上问题排查系列”大类别之一,讲述前段时间我司某产品在某券商遇到的一个问题及解决方案,其背后涉及到hive的一个BUG,在hive3.... 查看详情

大数据问题排查系列-因hive中元数据与hdfs中实际的数据不一致引起的问题的修复(代码片段)

大数据问题排查系列-因HIVE中元数据与HDFS中实际的数据不一致引起的问题的修复前言大家好,我是明哥!本片博文是“大数据问题排查系列”之一,讲述某HIVESQL作业因为HIVE中的元数据与HDFS中实际的数据不一致引起的... 查看详情

大数据问题排查系列-tdh大数据平台中hive作业长时间无法执行结束

前言大家好,我是明哥!本片博文是“大数据问题排查系列”之一,讲述某星环TDH大数据平台中,研发同学提交的Hive作业在成功提交后,客户端长时间收不到任何结果信息也收不到任何报错信息问题的排查。... 查看详情

大数据问题排查系列-hdfsfilesystemapi的正确打开方式,你get了吗?(代码片段)

大数据问题排查系列-HDFSFileSystemAPI的正确打开方式,你GET了吗?前言大家好,我是明哥!本片博文是“大数据问题排查系列”之一,我们首先会聊聊一个问题的现象原因和解决方法,然后给出HDFSFileSystemAPI... 查看详情

大数据问题排查系列-开启kerberos后无法访问hiveserver2等服务的webui

大数据问题排查系列-开启kerberos后无法访问HIVESERVER2等服务的WEBUI1前言大家好,我是明哥!在博文“从技术视角看大数据行业的发展趋势”中,我们提到大数据的一个发展趋势是日益重视数据安全。在数据安全上,... 查看详情

大数据问题排查系列-sparkstandaloneha模式的一个缺陷点与应对方案(代码片段)

大数据问题排查系列-SPARKSTANDALONEHA模式的一个缺陷点与应对方案前言大家好,我是明哥!作为当今离线批处理模式的扛把子,SPARK在绝大多数公司的数据处理平台中都是不可或缺的。而在底层使用的具体资源管理器上&... 查看详情

大数据问题排查系列-同样的hivesql,在cdh与tdh平台执行效率差异的根本原因

前言大家好,我是明哥!公众号已经运维有一段时间了,也写了不少博文,其中很多是从自己解决真实线上问题的实战经历出发,写的经验总结和IT感悟。但由于前期摸索过程中,文风不统一且排版不太好&... 查看详情

大数据情况下如何排查代码

】大数据情况下如何排查代码【英文标题】:Howtotroubleshootcodeinthecaseofbigdata【发布时间】:2014-07-0607:36:15【问题描述】:我正在尝试实现一个表的thispythonsolutiontocountthenumberoflineswithidenticalcontentinthefirstfewcolumns。这是我的代码:#co... 查看详情

kubernetes应用问题的通用排查思路-大数据从业者之kubernetes必知必会

...,大家共勉!1技术趋势大背景我们知道,大数据进一步发展的一个趋势,就是大数据和云计算进一步融合(包括在底层更加青睐存储计 查看详情

直播疑难杂症排查(10)—直播功耗高

...我们首先要分析下,哪些因素会导致CPU/GPU占用率高。2.1数据量太大直播主要由:视频采集->视频处理(剪裁、美颜、滤镜)->编码->推流这些环节组成。在这 查看详情

mysqlmediumtext大字段存储错误问题排查(代码片段)

...1a;由于日志查询问题,没看到日志之前怀疑:MYSQL数据库字段长度是否真的足够,排查问题未果。2:步骤一未果,看日志了解错误信息如下Name":"com.javartisan.audience_management.jsf_service.service.AudienceServ 查看详情

第25天sql进阶-查询优化-performance_schema系列实战二:锁问题排查(全局读锁)(sql小虚竹)

...什么时候适合加全局锁​​​​三、实战演练​​​​3.1数据准备(如果已有数据可跳过此操作)​​​​3.2开启第一个会话,执行全局读锁​​​​3.3开启第二个会话,修改表数据​​​​3.4开启第三个会话,进行排查​​​... 查看详情

实操|hive数据倾斜问题定位排查及解决(代码片段)

Hive数据倾斜怎么发现,怎么定位,怎么解决多数介绍数据倾斜的文章都是以大篇幅的理论为主,并没有给出具体的数据倾斜案例。当工作中遇到了倾斜问题,这些理论很难直接应用,导致我们面对倾斜时还是... 查看详情

《直播疑难杂症排查系列》之一:播放失败

...花屏、绿屏播放杂音、噪音、回声点播拖动不准直播发热问题其他问题(待续)第一篇文章我们从播放开始,因为观看直播最重要的一个环节就是打开播放器,很多问题的直接反馈也是来自观众端。导致播放失败的原因有很多种... 查看详情

问题解决系列:遇到tomcat的假死问题,如何排查问题(代码片段)

(文章目录)问题场景线上,有时候会遇到一种这样的情况:tomcat没有奔溃退出,输出日志也没有异常,但是界面访问就一直卡着。假如遇到这种情况,没错,你遇到了tomcat假死问题了。那么,该怎么排查这个问题呢?这个就是本... 查看详情

系列序—直播疑难杂症排查

...七牛做直播SDK一年多了,帮助客户解决过各种形形色色的问题,如直播卡顿、马赛克、花屏、黑屏、杂音、音画不同步等等等等,这其中,有一些是网络原因,有一些是客户的使用姿势问题,有一些是参数配置错误,当然,也有... 查看详情

第25天sql进阶-查询优化-performance_schema系列实战二:锁问题排查(全局读锁)(sql小虚竹)(代码片段)

...什么是全局锁二、什么时候适合加全局锁三、实战演练3.1数据准备(如果已有数据可跳过此操作)3.2开启第一个会话,执行全局读锁3.3开启第二个会话,修改表数据3.4开启第三个会话,进行排查3.5分析3.6释放全局读... 查看详情