我是靠谱客的博主 重要钢铁侠,这篇文章主要介绍spark-submit 到底做了什么,现在分享给大家,希望可以做个参考。

文章目录

    • 本文的目的是提升linux shell脚本的功力,以及熟悉spark-submit提交的具体流程
      • spark-sumbit*
      • 第一段
        • 背景知识
        • 综合案例
        • 解读
      • 第二段
        • 背景知识
        • 解读
      • 第三段
        • 背景知识
        • 解读
      • 总结语

本文的目的是提升linux shell脚本的功力,以及熟悉spark-submit提交的具体流程

spark-sumbit*

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env bash if [ -z "${SPARK_HOME}" ]; then source "$(dirname "$0")"/find-spark-home fi # disable randomized hash for string in Python 3.3+ export PYTHONHASHSEED=0 exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"

第一段

复制代码
1
2
3
4
if [ -z "${SPARK_HOME}" ]; then source "$(dirname "$0")"/find-spark-home fi

背景知识

  1. 双引号

    "${SPARK_HOME}"${SPARK_HOME} 这样写是等效的,均代表获取环境变量中的SPARK_HOME所引用的值
    在shell中 “$USER” 与 $USER 其代表的值是一样的。 加不加并不会记录到变量中,也不会添加到字符串中,其代表的一个根本的含义就是 定义 变量的意思。

    默认情况下,在shell编程中,不带双引号的都会被当作字符串来处理。这个惯例比较特殊。反正与一般意义上的高级编程语言不太一致。(读者可以自己揣摩一下单引号会得出什么样的结论)

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    #!/bin/bash if [ $USER = "$USER" ];then echo "eq" # 执行eq else echo "neq" fi
  2. if(空格)[(空格)-[a-z](空格)(string)(空格)];then 语法

    这个是常见的shell 字符串条件判断的格式,-z代表不存在,请注意空格是必填的,这个是跟处理shell脚本的编译器设置的语法解析器有关,或者说内置的正则表达式就是这么获取条件匹配的
    在方括号内退出码为0(exit 0即正常退出)则执行then后面的语句,否则执行其他分支

    复制代码
    1
    2
    3
    4
    homewell:/home/hadoop/shareh$ cat /etc/passwd | grep abc homewell:/home/hadoop/shareh$ echo $? 1

    比较其原型 是test命令

  3. source命令(直接copy命令)

    有人说是点(.)命令,也就是执行目标文件中的命令,但是source 不会执行生成子shell(概念要理清,这个子shell代表这创建一个新的进程被父进程管理环境变量)

    如果读者学过C++或者C,都会接触宏(#define)关键字,代表者代码在编译的时候直接把代码copy到引用了宏定义的代码段中,或者类似于C++中的内联函数,都是代码的直接copy.可以看 综合案例

    因此可以使用另一个脚本中暴露(export)的变量,因为相当于把另一脚本中的代码,直接copy到当前脚本中

    参考1
    参考2

  4. dirname 命令

    获取指定虚拟目录的父目录

    复制代码
    1
    2
    3
    4
    5
    6
    7
    homewell:/home/hadoop/shareh$ dirname /home/hadoop/shareh/ /home/hadoop homewell:/home/hadoop/shareh$ dirname /home/hadoop/shareh/abc abc/ abcd/ abc.sh homewell:/home/hadoop/shareh$ dirname /home/hadoop/shareh/abc.sh /home/hadoop/shareh
  5. 位置参数

    $0是调用程序的时候第一个字符串,通常与程序名一致,往往有些博客简单地把它理解成程序名,这样理解是很受伤的,很容易误伤,针对这种情况。希望读者能区分不同场景来理解(查看本案例)

    $1是第一个参数,$2是第二个参数

    5.案例

    复制代码
    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash echo "$0:""$0" echo "$1:""$1" # 超过10个参数的用{}包裹起来,否则 $10 == "$1" + "0" echo "第十个参数""${10}"
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    # 第一 全路径方式 homewell:~$ /home/homewell/shell1/testdoller.sh 23 $0:/home/homewell/shell1/testdoller.sh $1:23 # 全局变量方式(同上是一致的) homewell:~/shell1$ export SHELLTEST_HOME="/home/homewell/shell1" homewell:~/shell1$ export PATH="$SHELLTEST_HOME:$PATH" homewell:~/shell1$ testdoller.sh 1235 $0:/home/homewell/shell1/testdoller.sh $1:1235 # 第二种 通过相对路径1 homewell:~$ shell1/testdoller.sh 124 $0:shell1/testdoller.sh $1:124 # 第二种 通过相对路径2 homewell:~$ ./shell1/testdoller.sh 124 $0:./shell1/testdoller.sh $1:124 # 第三种 直接以./方式执行 homewell:~$ cd shell1/ homewell:~/shell1$ ./testdoller.sh 125 $0:./testdoller.sh $1:125 # 第四种 通过sh 命令执行 homewell:~/shell1$ sh testdoller.sh 126 $0:testdoller.sh $1:126

扩展内容 其他内置的跟$有关的位置参数

综合案例

复制代码
1
2
3
-rwxr-xr-x 1 zhangll zhangll 184 10月 2 21:14 pid2.sh* -rwxrwxrwx 1 zhangll zhangll 1292 10月 2 21:40 pid.sh*

pid.sh

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/bin/bash 表示当前shell echo "pid.sh当前shell pid进程($$):$$" echo "pid.sh当前shell最近一个后台进程pid($!):" "$!" echo "pid.sh前面一个命令的退出码 ($?) : $?" # 执行当前的目录路径下的pid2.sh echo "-------------./pid2.sh--------------" ./pid2.sh echo "pid.sh当前进程打印 pid2中的pid2暴露的变量($PID2): $PID2" echo "-------------查看(子进程)的一些特性------------" # 向外暴露a变量,在父进程中无法查看,只有在子shell中能看 export a=1 echo "pid.sh当前shell显示a 变量($a):"$a (export b=2; echo "子进程查看父进程暴露的(a):""$a";echo "子进程暴露的变量($b):""$b";echo "子进程打印的进程($$):""$$";echo "子进程($BASHPID):$BASHPID") echo "pid.sh 在 (子进程之后)当前shell最近一个后台进程pid2($!):" "$!" echo "pid.sh当前shell显示子进程暴露的b变量($b) : $b" echo "------------(./pid2.sh &)------------" ./pid2.sh & echo "pid.sh 在 (./pid2.sh &)最近一个后台进程pid2($!):" "$!" echo "pid.sh当前进程打印 pid2中的pid2暴露的变量($PID2): $PID2" echo "-----------source pid2.sh -----------" source ./pid2.sh echo "pid.sh source pid2.sh 之后当前进程打印 pid2中的pid2暴露的变量($PID2): $PID2" exit 0

pid2.sh

复制代码
1
2
3
4
5
6
7
#!/bin/bash echo "######pid2.sh 打印的 ($$):$$" echo "######pid2.sh 打印的 ($BASHPID):$BASHPID" echo "######pid2.sh 打印的最近一个后台进程 ($!):$!" export PID2=30

执行结果

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
pid.sh当前shell pid进程($$):9553 pid.sh当前shell最近一个后台进程pid($!): pid.sh前面一个命令的退出码 ($?) : 0 -------------./pid2.sh-------------- ######pid2.sh 打印的 ($$):9554 ######pid2.sh 打印的 ($BASHPID):9554 ######pid2.sh 打印的最近一个后台进程 ($!): pid.sh当前进程打印 pid2中的pid2暴露的变量($PID2): -------------查看(子进程)的一些特性------------ pid.sh当前shell显示a 变量($a):1 子进程查看父进程暴露的(a):1 子进程暴露的变量($b):2 子进程打印的进程($$):9553 子进程($BASHPID):9555 pid.sh 在 (子进程之后)当前shell最近一个后台进程pid2($!): pid.sh当前shell显示子进程暴露的b变量($b) : ------------(./pid2.sh &)------------ ######pid2.sh 打印的 ($$):9556 ######pid2.sh 打印的 ($BASHPID):9556 ######pid2.sh 打印的最近一个后台进程 ($!): pid.sh 在 (./pid2.sh &)最近一个后台进程pid2($!): 9556 pid.sh当前进程打印 pid2中的pid2暴露的变量($PID2): -----------source pid2.sh ----------- ######pid2.sh 打印的 ($$):9553 ######pid2.sh 打印的 ($BASHPID):9553 ######pid2.sh 打印的最近一个后台进程 ($!):9556 pid.sh source pid2.sh 之后当前进程打印 pid2中的pid2暴露的变量($PID2): 30

可以发现

  1. $! 代表当前shell进程空间最近一个执行的后台进程的id,并不会获取父进程空间的最近一次后台进程pid
    后台进程与子进程的区别
  2. ()括号包裹的虽然是开启了一个新的空间,但是其进程id与父亲的一致,但是在其内暴露(export)的变量,父进程无法获取
  3. $$ 并非代表当前shell的pid,

解读

复制代码
1
2
3
不管以./spark-submit 还是 直接执行spark-submit,当不存在SPARK_HOME环境变量的时候,就执行当前目录(spark-submit所在目录)中的find-spark-home命令 很显然find-spark-home 要做的工作肯定是设置一个 SPARK_HOME 环境变量用来给后期使用

第二段

复制代码
1
2
3
# disable randomized hash for string in Python 3.3+ export PYTHONHASHSEED=0

背景知识

  1. export 暴露/导出

    该关键词在nodejs/js/c/c++中会经常出现,代表这给调用该脚本的环境(脚本/shell环境)暴露一个变量,这个变量将会在当前进程空间中使用,包括子进程空间,但是不会影响父进程空间的变量

解读

很显然暴露了一个PYTHONHASHSEED (python hash seed)
这个是设置一个python随机
中的seed值,当改值为0的时候,代表着关闭随机hash种子,意味着对相同字符串多次使用hash函数,得到的是相同的值,这里可能考虑到pyspark上会调用hash值产生不必要的麻烦,比如spark中的group by 算子,由于可能数据在不同节点上,因此不同节点上会启动不同的python环境(可以理解成python session),python3.2.3之后就默认开启python环境的hash值,这意味着不同环境下的相同字符串,会默认在字符串前面添加一个盐值,防止DOS拒绝服务攻击手段,防止链表太长,降低性能。然后在group by 的相同字符串可能会在不同机器上输出不同 内容,因此为了能够保证数据一致性,需要关闭这个值

地址

第三段

复制代码
1
2
exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"

背景知识

  1. exec 命令 参数

    代表当前命令与参数 直接覆盖当前shell内容,这个是最暴力宏替换,不过会暴露当前的用户变量(局部变量)与全局变量

    案例见 Linux shell 整理之 复合命令行篇(四)

  2. exec 永久重定向操作

    案例见 Linux shell 整理之 复合命令行篇(四)

  3. 双引号

    同第一段 1)

解读

因此第三段的意思就是使用spark_home/bin/spark-class 并且传递两个参数
第一个是 org.apache.spark.deploy.SparkSubmit
第二个是 " @ " 代 表 当 前 s h e l l 执 行 所 窜 入 的 参 数 个 体 集 合 的 列 表 , 根 据 实 际 情 况 当 然 可 以 用 " @" 代表当前shell 执行所窜入的参数个体集合的列表,根据实际情况当然可以用 " @"shell""来代替。$@ 代表着把输入参数作为多个个体存在,而 $ 可以作为一个单独的个体存在

总结语

纸上得来终觉浅,绝知此事要躬行。简简单单3句话,其涵盖的内容,不是一两句话能够得出来的。当你用心去体会的时候,你会发现,原来一切都这么简单明白

最后

以上就是重要钢铁侠最近收集整理的关于spark-submit 到底做了什么的全部内容,更多相关spark-submit内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部