0x0 背景
最近为了将hadoop&hive的五大配置文件,即:

core-site.xml
hdfs-site.xml
yarn-site.xml
mapred-site.xml
hive-site.xml

从项目中(classpath)移到项目外(任意位置),研究了spark启动过程的源码,在此记录一下。

0x1 Hadoop及Hive获取默认配置过程
Hadoop有一个类 
Configuration implementsIterable<Map.Entry<String,String>>,Writable 
这个类就是用于处理hadoop的配置,其内部有静态代码块:

static{
    //print deprecation warning if hadoop-site.xml is found in classpath
    ClassLoader cL = Thread.currentThread().getContextClassLoader();
    if (cL == null) {
      cL = Configuration.class.getClassLoader();
    }
    if(cL.getResource("hadoop-site.xml")!=null) {
      LOG.warn("DEPRECATED: hadoop-site.xml found in the classpath. " +
          "Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, "
          + "mapred-site.xml and hdfs-site.xml to override properties of " +
          "core-default.xml, mapred-default.xml and hdfs-default.xml " +
          "respectively");
    }
    addDefaultResource("core-default.xml");
    addDefaultResource("core-site.xml");
  }

可见,当Configuration加载后,就会从classpath读取

hadoop-site.xml
core-default.xml
core-site.xml

这三个配置文件。 
同时,Configuration类有四个子类: 
 
分别是:

HdfsConfiguration
HiveConf
JobConf
YarnConfiguration

进入这四个类内部同样可以见到类似的静态代码, 
HdfsConfiguration中:

static {
    addDeprecatedKeys();
    // adds the default resources
    Configuration.addDefaultResource("hdfs-default.xml");
    Configuration.addDefaultResource("hdfs-site.xml");
}

YarnConfiguration中:

static {
        addDeprecatedKeys();
        Configuration.addDefaultResource("yarn-default.xml");
        Configuration.addDefaultResource("yarn-site.xml");
        ...
}

JobConf中:

public static void loadResources() {
        addDeprecatedKeys();
        Configuration.addDefaultResource("mapred-default.xml");
        Configuration.addDefaultResource("mapred-site.xml");
        Configuration.addDefaultResource("yarn-default.xml");
        Configuration.addDefaultResource("yarn-site.xml");
}

但是HiveConf并未在静态代码块中读取配置文件,然而在CarbonData的启动过程中,会读取hive-site.xml:

val hadoopConf = new Configuration()
val configFile = Utils.getContextOrSparkClassLoader.getResource("hive-site.xml")
if (configFile != null) {
    hadoopConf.addResource(configFile)
}

可见,Hadoop在启动过程中,各组件会首先在classpath下读取相应的配置文件。 
我们也可以通过Configuration的set(String name, String value)或者addResource(Path file)方法来添加配置,addResource内部执行流程如下:

//将资源添加到resources列表(存储配置文件资源的列表)
    resources.add(resource);   // add to resources
    //将已有的属性清空
    properties = null;         // trigger reload
    finalParameters.clear();   // clear site-limits
    //重新加载所有配置
    loadResources(Properties properties,
                  ArrayList<Resource> resources,
                  boolean quiet)

0x2 Spark启动过程中设置Hadoop配置
Spark Application启动过程中首先要实启动一个SparkContext,其实SparkContext本质上可以理解为Spark运行的配置集合。

val sc = SparkContext.getOrCreate(sparkConf)

而在SparkContext创建过程中会启动一个调度任务,用于连接远程集群:

val backend = cm.createSchedulerBackend(sc, masterUrl, scheduler)

如果是Spark on Yarn,会调用YarnClusterManager的createSchedulerBackend方法:

override def createSchedulerBackend(sc: SparkContext,
      masterURL: String,
      scheduler: TaskScheduler): SchedulerBackend = {
    sc.deployMode match {
      case "cluster" =>
        new YarnClusterSchedulerBackend(scheduler.asInstanceOf[TaskSchedulerImpl], sc)
      case "client" =>
        new YarnClientSchedulerBackend(scheduler.asInstanceOf[TaskSchedulerImpl], sc)
      case  _ =>
        throw new SparkException(s"Unknown deploy mode '${sc.deployMode}' for Yarn")
    }
  }

然后在YarnClientSchedulerBackend中创建了YarnClient,可见看Client中的构造函数:

private[spark] class Client(
    val args: ClientArguments,
    val hadoopConf: Configuration,
    val sparkConf: SparkConf)
  extends Logging {

import Client._
  import YarnSparkHadoopUtil._

def this(clientArgs: ClientArguments, spConf: SparkConf) =
    this(clientArgs, SparkHadoopUtil.get.newConfiguration(spConf), spConf)

private val yarnClient = YarnClient.createYarnClient
  private val yarnConf = new YarnConfiguration(hadoopConf)

可见,Spark将利用SparkConf中的配置,调用SparkHadoopUtil.get.newConfiguration(spConf)方法生成相应的Hadoop配置。 
其实,在SparkContext中,有2个成员变量(本质上是一个):

private var _hadoopConfiguration: Configuration = _
def hadoopConfiguration: Configuration = _hadoopConfiguration
....
_hadoopConfiguration = SparkHadoopUtil.get.newConfiguration(_conf)

这个_hadoopConfiguration 也是通过SparkHadoopUtil.get.newConfiguration(_conf)方法获取到hadoop的配置。 
进入SparkHadoopUtil.get.newConfiguration(_conf)方法,可见到:

conf.getAll.foreach { case (key, value) =>
        if (key.startsWith("spark.hadoop.")) {
          hadoopConf.set(key.substring("spark.hadoop.".length), value)
        }
      }
1
2
3
4
5
也就是说,在SparkConf中所有以spark.hadoop.开头的属性,都会被转换为hadoop的配置。

那么我们通过解析hadoop的xml配置文件,转换为相应的键值对,传给spark就可以了。代码如下:

/**
     * 读取hadoopConfPath下所有hadoop相关配置文件,并转换为SparkConf
     *
     * @param hadoopConfPath hadoop配置文件所在的文件夹
     * @return 
     */
    public SparkConf getHadoopConf(String hadoopConfPath) {
        SparkConf hadoopConf = new SparkConf();

try {
            Map<String, String> hiveConfMap = parseXMLToMap(hadoopConfPath + "/hive-site.xml");
            Map<String, String> hadoopConfMap = parseXMLToMap(hadoopConfPath + "/core-site.xml");
            hadoopConfMap.putAll(parseXMLToMap(hadoopConfPath + "/hdfs-site.xml"));
            hadoopConfMap.putAll(parseXMLToMap(hadoopConfPath + "/yarn-site.xml"));
            hadoopConfMap.putAll(parseXMLToMap(hadoopConfPath + "/mapred-site.xml"));

for (Map.Entry<String, String> entry : hiveConfMap.entrySet()) {
                hadoopConf.set(entry.getKey(), entry.getValue());
            }
            for (Map.Entry<String, String> entry : hadoopConfMap.entrySet()) {
                hadoopConf.set("spark.hadoop." + entry.getKey(), entry.getValue());
            }
            return hadoopConf;
        } catch (DocumentException e) {
            logger.error("读取xml文件失败!");
            throw new RuntimeException(e);
        }

}

//将xml解析为HashMap
    private Map<String, String> parseXMLToMap(String xmlFilePath) throws DocumentException {
        Map<String, String> confMap = new HashMap<>();
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(xmlFilePath));
        Element configuration = document.getRootElement();
        Iterator iterator = configuration.elementIterator();
        while (iterator.hasNext()) {
            Element property = (Element) iterator.next();
            String name = property.element("name").getText();
            String value = property.element("value").getText();
            confMap.put(name, value);
        }
        return confMap;
    }

注意: 
经测试,如果集群有kerberos加密,该方法无效! 
原因可能是:

class SparkHadoopUtil extends Logging {
      private val sparkConf = new SparkConf(false).loadFromSystemProperties(true)
      val conf: Configuration = newConfiguration(sparkConf)
      UserGroupInformation.setConfiguration(conf)

在该类中设置了一个new的SparkConf,这个SparkConf只从System.getProperty读取spark开头的属性,因此不是正确的属性,导致kerberos登录异常。

Spark加载hadoop配置原理相关推荐

  1. Springboot默认加载application.yml原理

    Springboot默认加载application.yml原理以及扩展 SpringApplication.run(-)默认会加载classpath下的application.yml或applicat ...

  2. atitit.动态加载数据库配置in orm hibernate mybatis

    atitit.动态加载数据库配置in orm 1. 动态加载数据库配置的优点::: 1 1.1. 组合多个配置文件... 1 1.2. 连接多个数据库 1 2. 基本的流程:::getCfg内存对象, ...

  3. 模块化加载_webpack模块化原理-异步加载模块

    在上篇文章中,我们介绍了 webpack 同步加载模块的原理.这篇文章,我们来介绍一下 webpack 异步加载模块. 异步加载模块 还是先做一些准备工作. 首先定义一个依赖模块:math.js,ma ...

  4. Selenium基础 — 拓展:使用浏览器加载项配置实现用户免登陆

    1.什么是加载项配置 在很多情况下,我们在登录网站的时候,浏览器都会弹出一个是否保存登录账号的信息.如果我们选择保存,那么我们在下次登录时就不用再次输入账号,直接免登录了. 在我们实际的测试过程中,测 ...

  5. 前端性能优化之资源传输优化、渲染优化、Web 加载和渲染原理

    一.资源传输优化 使用压缩 Gzip,如下所示: 对传输资源进行体积压缩,可高达 90% 配置 Nginx 启用 Gzip 启用 Keep Alive,如下所示: 一个持久的 TCP 连接,节省了连接 ...

  6. Apollo配置中心热加载mysql_Apollo配置中心介绍

    1.What is Apollo 1.1 背景 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关.参数的配置.服务器的地址-- 对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分 ...

  7. 海思涵科技WIFI认证服务器不在线,在海思平台外加一个usb wifi模块,mt7601 加载ok,配置网络ok,但不能ping通?...

    请教下:我用mt7601 usb wifi模块 加载驱动 配置网络后经常打印 PeerBeaconAtJoinAction(): Set CentralChannel=1 PeerBeaconAtJo ...

  8. Flutter 实现根据环境加载不同配置

    之前做后端开发的时候,不管是什么语言或者框架,都习惯根据不同环境加载不同的开发配置,比如本地开发的时候,加载local.env配置,部署开发环境的时候加载develop.env配置,通常通过一个环境变 ...

  9. springboot 启动分析【难点】——如何自动扫描 @SpringBootApplication||如何加载自动配置类 @EnableAutoConfiguration||如何加载前端控制器

    springboot 启动分析[难点] 自动扫描的特点 默认扫描与 启动类 同级的所有包及其子包都可以自动扫描 如果不可要使用@ComponentScan(basePackage={"&qu ...

最新文章

  1. Windows系统下制作一个记事本以语音方式读出你输入的文字 以及放到开机启动项,开机自启动读出语音!
  2. CI框架json无法Unicode转中文解决方案
  3. 解决方案 | python安装wordfreq库
  4. 需求调研报告模板_2020年工业软管行业深度市场调研及投资策略建议报告-液体化学品增加对其需求...
  5. Java二叉搜索树转循环链表,关于java:二叉搜索树转换为单向链表interview1712
  6. logstash filter 处理json数据按原始数据字段数据存储
  7. 剑指offer面试题[21]包含min函数的栈
  8. 【正点原子MP157连载】第四十四章Linux SPI总线框架-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7
  9. Altium Designer使用-----智能pdf输出装配图
  10. 尾矿库监测 GNSS北斗高精度定位终端机应用
  11. <论文阅读> M2BEV Multi-Camera Joint 3D Detection and Segmentation with Unified Bird’s-Eye View Represen
  12. 移动APP测试中的功能与非功能测试
  13. 显卡天梯图2020年10月完整版
  14. 分享篇:第十届“泰迪杯”数据挖掘挑战赛-农田害虫图像识别(特等奖)一
  15. tecplot选择变量
  16. SVN解决冲突的几种情况
  17. 电磁场与电磁波:法拉第电磁感应定律,高斯定律的高斯定律
  18. Arrays.copyOf方法
  19. FFN -> GLU -> GAU
  20. 信托资金将分辨用于向邢台依林山庄食物有限公司、唐山国泰纸业有限公司、唐山蓝猫饮品团体有限公司发放流动资金贷款1亿、1.5亿、1亿

热门文章

  1. c语言链表萌新,萌新一枚,关于链表问题求大佬解答
  2. 会不会导致内存泄漏_可能会导致.NET内存泄露的8种行为
  3. Win7 路由上网DNS服务器ping不通的解决方法
  4. 给Win7光盘添加PE3.0
  5. 2个红外传感器循迹原理_红外线光学气体浓度传感器作用原理
  6. 在php中页面布局 3列左右侧固定中间自适应居中,css三列布局--两边固定中间自适应和中间固定两边自适应...
  7. octave安装 缺java_Octave信号包安装
  8. html表单提交前验证,jquery表单提交前实现同步验证(附代码)
  9. linux 音频文件播放文件管理,linux dsp 播放音频文件
  10. python 画图设置横纵坐标_Python输出高质量论文图片