Spark集群启动过程分析
来源:互联网 发布:淘宝发布的宝贝不见了 编辑:程序博客网 时间:2024/05/21 20:21
- 环境变量配置
- 通过命令行参数配置
- 通过spark-envsh配置
- 集群的启动过程
- Master的启动
- 脚本的执行流程
- Master的初始化
- Worker的启动
- 脚本的执行流程
- Worker的初始化
- Master的启动
环境变量配置
通过命令行参数配置
-h HOST
, --host HOST
Master或Workers的主机地址。 -p PORT
, --port PORT
Master或Worerks的端口号(默认是:7077,而Worker的端口号随机)。 --webui-port PORT
WebUI界面的端口号(默认情况下,Master是8080,Worker是8081)。 -c CORES
, --cores CORES
允许Spark Applications在机器上使用的总CPU内核数(默认是使用所有的内核),该配置仅限于Worker。 -m MEM
, --memory MEM
允许Spark Applications在机器上使用的内存总量(默认是:1g),该配置仅限于Worker。每个Application使用的内存都使用其spark.executor.memory
属性进行配置。 -d DIR
, --work-dir DIR
用于临时空间和作业输出日志的目录(默认是:${SPARK_HOME}/work),该配置仅限于Worker。 --properties-file FILE
要加载的自定义Spark属性文件的路径(默认是:${SPARK_HOME}/conf/spark-defaults.conf)。通过spark-env.sh配置
也可以通过在conf / spark-env.sh
中设置环境变量来进一步配置集群,不过在该文件中配置的属性优先级没有命令行参数高。
- master环境变量
- SPARK_MASTER_HOST:将Master绑定到特定的主机名或IP地址;
- SPARK_MASTER_PORT:在指定的端口启动Master(默认:7077);
- SPARK_MASTER_WEBUI_PORT:Master Web UI的端口(默认:8080);
- SPARK_MASTER_OPTS:以“-Dx = y”(默认值:无)格式应用于Master的配置属性,具体支持的属性如下configuration.html#SPARK_MASTER_OPTS
- worker环境变量
- SPARK_WORKER_CORES:允许Spark Applications在机器上使用的内核总数(默认:所有可用内核);
- SPARK_WORKER_MEMORY:允许Spark Applications在机器上使用的内存总数(默认:所有1G)。请注意,每个Application使用的内存都使用其
spark.executor.memory
属性进行配置。 - SPARK_WORKER_PORT:Worker的启用特定端口(默认值:随机分配);
- SPARK_WORKER_WEBUI_PORT:Worker的WebUI端口号(默认值是8081);
- SPARK_WORKER_DIR:在Worker中运行Application的目录,其中将包括日志和暂存空间(默认值:SPARK_HOME / work)。
- SPARK_WORKER_OPTS:以“-Dx = y”(默认值:无)格式应用于Worker的配置属性,具体支持的属性如下configuration.html#SPARK_WORKER_OPTS
- 通用的环境变量
- SPARK_LOCAL_DIRS:用于存储map输出文件和存储在磁盘上的RDD缓存。这应该在系统中的快速本地磁盘上,它也可以是不同磁盘上多个目录的逗号分隔列表。
- SPARK_DAEMON_MEMORY:分配给Master和Workers守护进程的内存(默认是1G);
- SPARK_DAEMON_JAVA_OPTS:Spark master和worker守护进程的JVM选项,格式为“-Dx = y”(默认值:无)。
- SPARK_PUBLIC_DNS:Spark Worker和Master的公共DNS名称。
集群的启动过程
Master和Workers需要通过脚本来启动,可以使用start-all.sh
一键启动Master和Workers,也可以使用start-master.sh
和start-slaves.sh
分别启动Master和Workers。总之,不管用什么脚本启动,它们之间的调用链如下图所示:
Master的启动
脚本的执行流程
start-master.sh
使用
start-master.sh
,在脚本执行的机器上启动Master实例,start-master.sh
脚本的主要逻辑包括:- 确定了master的启动类
org.apache.spark.master.Master
; - 通过执行
spark-env.sh
,获取到了master的运行环境变量,包括用户配置的主机地址、端口号和WebUI的端口号。如果没有配置,则使用默认配置。 - 最后,将以上参数提交给
spark-daemon.sh
,启动一个Master守护进程,具体的运行命令如下:
"${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS 1 \ --host $SPARK_MASTER_HOST --port $SPARK_MASTER_PORT --webui-port $SPARK_MASTER_WEBUI_PORT \ $ORIGINAL_ARGS
- 确定了master的启动类
start-daemon.sh
spark-daemon.sh
为守护进程提供了一些管理操作,包括启动、停止、查看运行状态等,具体用法如下:# start|stop|submit|status : 表示option# spark-command : 表示启动命令,如org.apache.spark.master.Master# spark-instance-number:启动的实例数,一般为1,对于Slave可以在一个节点上启动多个Worker;# args...:表示提供给spark-command 的运行参数。$ spark-daemon.sh [--config <conf-dir>] (start|stop|submit|status) <spark-command> <spark-instance-number> <args...>
spark-daemon.sh
脚本执行的流程主要包括以下几个步骤:解析命令行参数,得到option、command和instance;
初始化一些环境变量,包括日志目录、pid文件存储目录、调度的优先级、是否为daemon启动一个单独的进程,还是依附于执行脚本的bash所在的进程等;
根据不同的option执行对应的操作,如果是stop或status,则根据pid文件执行对应的操作。如果是submit和start,接着会调用
run_command
方法:case $option in(submit) run_command submit "$@" ;;(start) run_command class "$@" ;;
run_command() {mode="$1"shiftmkdir -p "$SPARK_PID_DIR"# 根据pid文件检查是否已经正在运行if [ -f "$pid" ]; then TARGET_ID="$(cat "$pid")" if [[ $(ps -p "$TARGET_ID" -o comm=) =~ "java" ]]; then echo "$command running as process $TARGET_ID. Stop it first." exit 1 fifiif [ "$SPARK_MASTER" != "" ]; then echo rsync from "$SPARK_MASTER" rsync -a -e ssh --delete --exclude=.svn --exclude='logs/*' --exclude='contrib/hod/logs/*' "$SPARK_MASTER/" "${SPARK_HOME}"fi# 日志迁移,将旧的日志编号递增,保证每次启动后日志名称都为 **.Master-1-master0.out,而旧的日志名称则为 .Master-1-master0.out.1 .Master-1-master0.out.2spark_rotate_log "$log"echo "starting $command, logging to $log"# 根据不同的模式,确定执行命令所使用的脚本case "$mode" in (class) execute_command nice -n "$SPARK_NICENESS" "${SPARK_HOME}"/bin/spark-class "$command" "$@" ;; (submit) execute_command nice -n "$SPARK_NICENESS" bash "${SPARK_HOME}"/bin/spark-submit --class "$command" "$@" ;; (*) echo "unknown mode: $mode" exit 1 ;;esac}
由于本次的执行模式mode是class,最终将执行命令交给了
spark-class
,来启动的可执行类。
spark-class
spark-class
脚本会加载spark配置的环境变量信息spark-env.sh
、获取类路径LAUNCH_CLASSPATH(默认是${SPARK_HOME}/jars
)、选择执行此命令的执行器(这里是java),并调用build_command
构建主类的启动命令。build_command() { "$RUNNER" -Xmx128m -cp "$LAUNCH_CLASSPATH" org.apache.spark.launcher.Main "$@" printf "%d\0" $? # 代表上一个命令执行是否成功的标志,如果执行成功则为0,否则不为0}
可以看出,构建主类启动命令是通过
org.apache.spark.launcher.Main
类进行的,Main类作用是接收[class] [class args]
格式的参数,并且提供了一下两种工作模式:如果使用的是
spark-submit
脚本提交,那么class一定为org.apache.spark.deploy.SparkSubmit
,生成的启动命令是:/opt/jdk/1.8.0_151/bin/java -cp /opt/spark/2.2.0/conf/:/opt/spark/2.2.0/jars/* -Xmx 1g org.apache.spark.deploy.SparkSubmit --master spark://master0:7077 --deploy-mode cluster --class cn.vibrancy.spark.ComplexJob --name complexjob /home/deploy/complex-job.jar
如果执行的是
spark-class
脚本,那么运行参数提供的class,生成的启动命令是:/opt/jdk/1.8.0_151/bin/java -cp /opt/spark/2.2.0/conf/:/opt/spark/2.2.0/jars/* -Xmx 1g org.apache.spark.master.Master -host master -p 7077 --webui-port 8080
接着,将构建出的主class启动命令打印,bash可以使用read来获取打印的结果,并放到CMD中。
// Main.java// 将生成的命令打印出,bash可以获取并收集到打印的结果List<String> bashCmd = prepareBashCommand(cmd, env);for (String c : bashCmd) { System.out.print(c); System.out.print('\0');}
# spark-classset +o posixCMD=()while IFS= read -d '' -r ARG; do CMD+=("$ARG")done < <(build_command "$@")
最后,执行CMD命令,这样就可以执行Master的
main
方法了。# spark-classCMD=("${CMD[@]:0:$LAST}")exec "${CMD[@]}"
Master的初始化
- 创建RpcEnv,并向RpcEnv实例中注册当前MasterEndpoint;
- 初始化Worker、Application和Driver相关的数据结构;
- 根据RECOVERY_MODE创建对应的Master元数据持久化引擎和领导选举机制,包括ZOOKEEPER、FILESYSTEM、CUSTOMER和NONE;
- 等待Worker的注册;
Worker的启动
脚本的执行流程
可以在执行start-slave.sh
脚本所在机器上启动一个Worker,也可以在任意一个节点上执行start-slaves.sh
脚本,则会启动slaves
中记录的所有从节点上的Worker。
start-slaves.sh
在任意节点上启动集群上所有的Worker原理很简单,在
start-slaves.sh
中:# Launch the slaves"${SPARK_HOME}/sbin/slaves.sh" cd "${SPARK_HOME}" \; "${SPARK_HOME}/sbin/start-slave.sh" "spark://$SPARK_MASTER_HOST:$SPARK_MASTER_PORT"
会调用
slaves.sh
脚本来启动集群中的Worker,其中cd后面的所有字符串都是传递给slaves.sh
的参数。slaves.sh
# slaves.shfor slave in `echo "$HOSTLIST"|sed "s/#.*$//;/^$/d"`; do if [ -n "${SPARK_SSH_FOREGROUND}" ]; then ssh $SPARK_SSH_OPTS "$slave" $"${@// /\\ }" \ 2>&1 | sed "s/^/$slave: /" else ssh $SPARK_SSH_OPTS "$slave" $"${@// /\\ }" \ 2>&1 | sed "s/^/$slave: /" & fi if [ "$SPARK_SLAVE_SLEEP" != "" ]; then sleep $SPARK_SLAVE_SLEEP fidone
在
slaves.sh
中,会解析slaves
文件,获得当前集群中的所有从节点host,最后会执行上面的代码段,意思是使用ssh连接到某个slave中,然后执行cd "${SPARK_HOME}" \; "${SPARK_HOME}/sbin/start-slave.sh" "spark://$SPARK_MASTER_HOST:$SPARK_MASTER_PORT"
,这样就成功的在远程slave上启动了一个Worker实例。start-slave.sh
该脚本中又会通过
spark-daemon.sh
脚本,来启动org.apache.spark.worker.Worker
类,spark-daemon.sh
上面已经详细介绍过了,只是启动类不同,这里不再复述了。"${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS $WORKER_NUM \ --webui-port "$WEBUI_PORT" $PORT_FLAG $PORT_NUM $MASTER "$@"
Worker的初始化
Worker的初始化比较简单,就是向masterRpcAddresses
列表中的Master注册,如果Master是Active并且Worker没有注册过,那么Master会回复Worker消息RegisteredWorker,表示Worker注册成功;如果注册失败,那么回复RegisterWorkerFailed,Worker会退出。
Worker向Master注册的时候有重试机制,即在指定时间如果收不到Master的响应,那么Worker将会重新发送注册请求。目前重新次数至多为16次。为了避免所有的Worker同时刻向Master发送注册请求,每次重试的时间间隔是随机的,前6次的重试间隔在5~15s,而后10次的重试间隔在30~90秒。
- Spark集群启动过程分析
- 用Scala模拟Spark集群启动过程
- spark core源码分析1 集群启动及任务提交过程
- spark core源码分析1 集群启动及任务提交过程
- spark 1.6.0 core源码分析1 集群启动及任务提交过程
- Spark分析之SparkContext启动过程分析
- Spark源码分析-spark集群启动及任务执行
- Spark集群启动之Master、Worker启动流程源码分析
- Spark Streaming应用启动过程分析
- spark 源代码分析 (二)spark启动过程
- 启动spark集群
- Spark的Master和Worker集群启动的源码分析
- spark集群搭建过程
- Spark独立集群下Application提交过程分析
- Spark Rpc的启动过程(其实也就是集群的启动过程)
- solrcloud集群启动管理过程基于源码的分析
- Spark集群启动命令汇总
- 配置Spark standalone集群启动
- HBase之重试机制
- HTTP协议
- python核心编程第二版 读到483页小节
- Java开发必会的Linux命令
- 轻松理解:硬盘的读写原理
- Spark集群启动过程分析
- Android 非常简单的实现 Fragment状态栏一体化布局,状态栏字体的颜色改变,
- 编写延时循环
- HDU2001 计算两点间的距离【入门】
- java-将xlsx(excel)文件转换成json
- 从零开始前端学习[51]:js中去操作css样式以及css属性的替代方法
- 输出
- org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
- C语言实验——最值