尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Spark完全分布式部署实战:从零搭建高可用集群与核心配置详解

Spark完全分布式部署实战:从零搭建高可用集群与核心配置详解 1. 从单机到集群为什么需要完全分布式部署如果你已经跟着教程在单台机器上跑通了Spark的Local模式恭喜你你已经迈出了第一步。但很快你就会发现当数据量稍微大一点或者任务稍微复杂一点单台机器的计算和内存资源就成了瓶颈。这时候你就需要把Spark从“单兵作战”升级为“集群作战”也就是所谓的完全分布式部署。简单来说完全分布式部署就是把Spark的各个核心组件Master和Worker分别安装在不同的物理或虚拟服务器上让它们通过网络协同工作。一个Master节点负责资源调度和任务协调多个Worker节点负责提供计算资源并执行具体的任务。这不仅仅是把软件装到多台机器上那么简单它涉及到网络规划、资源配置、服务发现等一系列问题。很多新手在第一次部署时往往会卡在环境变量、主机名解析、端口开放这些看似基础但至关重要的环节上。我见过不少团队在测试环境用单节点跑得好好的一上生产集群就各种报错排查半天发现是防火墙没开端口或者主机名没配好。所以这篇内容我会以一个“过来人”的身份带你走一遍Spark完全分布式部署的全流程重点不是告诉你“输入什么命令”而是解释清楚“为什么这么做”以及“如果出错了该怎么想”。我们会基于最经典的Standalone集群模式来展开这是Spark自带的集群资源管理器理解它对于后续学习YARN或Kubernetes模式也大有裨益。2. 部署前的核心规划与资源准备在动手敲下任何安装命令之前花半小时做好规划能为你节省后面数小时的排错时间。完全分布式部署不是儿戏它要求你对即将构建的这个小“生态系统”有清晰的蓝图。2.1 集群角色与节点规划一个最基本的Spark Standalone集群至少需要两台机器一台Master一台Worker。但为了具备高可用性避免Master单点故障和更好的资源利用率我建议至少规划三台节点。一个典型的规划如下主节点Master Node1台。运行Spark Master进程负责管理整个集群接收应用提交并将任务分发给Worker。在生产环境为了高可用通常会部署多个Master一个Active一个或多个Standby这需要借助ZooKeeper。本篇我们先搞定基础版。工作节点Worker Node至少2台。运行Spark Worker进程向Master注册自己提供CPU核心和内存资源并启动执行器Executor来运行任务。客户端/边缘节点可选1台。用于提交应用程序spark-submit。理论上可以在任何能访问到Master的机器上提交但单独规划一台可以避免在Master或Worker节点上安装客户端工具保持集群节点的纯净。主机名与IP地址这是最容易出问题的地方。集群内所有机器必须能通过主机名互相解析。很多教程让你直接配IP这在小型静态环境勉强可行但一旦IP变动就会导致集群瘫痪。正确的做法是配置每台机器的/etc/hosts文件或者更好的是搭建一个内网DNS。例如你的三台机器192.168.1.101 spark-master 192.168.1.102 spark-worker-01 192.168.1.103 spark-worker-02确保在spark-master上执行ping spark-worker-01能通反之亦然。用hostname命令查看并设置每台机器的永久主机名如通过hostnamectl set-hostname spark-master。2.2 系统环境与依赖检查Spark运行依赖于Java。目前Spark 3.x系列通常需要Java 8或Java 11。不建议使用最新版本的Java可能存在兼容性问题。Java安装与配置# 在所有节点上检查Java版本 java -version # 如果未安装使用包管理器安装例如在Ubuntu/Debian上 # sudo apt update sudo apt install openjdk-11-jdk-headless -y # 在CentOS/RHEL上 # sudo yum install java-11-openjdk-devel -y # 配置JAVA_HOME环境变量。关键点这个路径必须指向JDK的根目录而不是JRE。 # 查找Java安装路径 update-alternatives --config java # 输出类似 /usr/lib/jvm/java-11-openjdk-amd64/bin/java # 那么JAVA_HOME就是 /usr/lib/jvm/java-11-openjdk-amd64 # 编辑 /etc/profile 或用户目录下的 .bashrc echo export JAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64 ~/.bashrc echo export PATH$JAVA_HOME/bin:$PATH ~/.bashrc source ~/.bashrc务必在所有节点上执行相同的Java安装和配置并确保JAVA_HOME正确设置。这是Spark进程启动的基础。SSH免密登录配置 虽然Standalone集群启动时Master通过SSH到Worker启动进程不是强制要求可以通过手动在每个Worker启动服务但使用Spark自带的集群启动脚本sbin/start-all.sh时需要Master能免密登录到所有Worker节点。配置步骤# 1. 在Master节点生成密钥对如果已有可跳过 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa # 2. 将公钥分发到所有Worker节点也包括自己方便统一管理 ssh-copy-id spark-worker-01 ssh-copy-id spark-worker-02 # 也需要能登录自己 ssh-copy-id spark-master # 3. 测试免密登录 ssh spark-worker-01 hostname # 应直接返回worker的主机名无需密码防火墙与端口 Spark集群内部通信需要开放一系列端口。如果节点间有防火墙如firewalld, ufw必须放行。关键端口包括Master Web UI: 8080 (默认)Master RPC端口: 7077 (默认用于应用提交)Worker Web UI: 8081 (默认)随机端口范围: Spark内部通信如Executor、BlockManager会使用大量随机端口。最好开放一个范围例如1024-65535或者更精确地根据spark-defaults.conf中的spark.port.maxRetries等配置来设定。一个常见的坑所有节点都能互相访问对方的这些端口。有时候从Master能ping通Worker但telnet worker-hostname 8081不通问题就出在防火墙。3. Spark软件分发与基础配置规划好环境后我们开始部署Spark本身。3.1 软件包选择与下载访问 Apache Spark 官网下载页面 。选择预编译的版本通常选最新的稳定版如Spark 3.5.x。Package type选择“Pre-built for Apache Hadoop 3.3 and later”除非你的环境有特定Hadoop版本需求。这个预编译包包含了大部分常用的Hadoop依赖即使你不使用HDFS也推荐选择这个兼容性更好。下载完成后在主节点上进行解压# 假设下载的包为 spark-3.5.1-bin-hadoop3.tgz tar -xzf spark-3.5.1-bin-hadoop3.tgz -C /opt/ cd /opt ln -s spark-3.5.1-bin-hadoop3 spark # 创建一个软链接方便版本管理和路径引用现在Spark的主目录是/opt/spark。3.2 核心配置文件详解Spark的配置主要通过$SPARK_HOME/conf目录下的文件完成。我们需要配置两个关键文件spark-env.sh和workers(旧版本叫slaves)。配置spark-env.sh(环境变量)cd /opt/spark/conf cp spark-env.sh.template spark-env.sh # 复制模板 vim spark-env.sh在这个文件中我们需要设置一些影响集群行为的环境变量。以下是一个示例配置请根据你的实际环境修改# 设置Java安装路径必须与之前配置的JAVA_HOME一致 export JAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64 # 设置Spark主节点的主机名或IP。Master进程会绑定到这个地址。 # 重要这里建议使用主机名并确保所有Worker能解析这个主机名。 export SPARK_MASTER_HOSTspark-master # 设置Master的Web UI端口默认8080 export SPARK_MASTER_WEBUI_PORT8080 # 设置每个Worker节点上Spark可用的最大内存。 # 注意不要设置为机器全部内存要为操作系统和其他服务留出空间。 # 例如机器有16G内存可以分配12G给Spark。 export SPARK_WORKER_MEMORY12g # 设置每个Worker节点上Spark可用的CPU核心数。 # 通常设置为机器物理核心数或者留出1-2个给系统。 export SPARK_WORKER_CORES4 # (可选) 设置Spark日志目录默认为$SPARK_HOME/logs export SPARK_LOG_DIR/var/log/spark # (可选) 设置PID文件目录用于存储进程ID export SPARK_PID_DIR/var/run/spark注意SPARK_WORKER_MEMORY和SPARK_WORKER_CORES是在spark-env.sh中设置的Worker级别的全局默认值。当用户提交应用时还可以通过spark-submit参数如--executor-memory、--executor-cores为特定应用指定不同的值但最终不能超过Worker提供的上限。配置workers(节点列表)cp workers.template workers vim workers这个文件非常简单每一行写一个Worker节点的主机名必须能被Master解析。例如spark-worker-01 spark-worker-02 # 可以添加更多Worker重要这个文件仅在使用Master上的sbin/start-all.sh等脚本一键启动整个集群时才需要。如果你选择在每个Worker节点上手动启动start-worker.sh则不需要此文件。3.3 将配置分发到所有Worker节点为了保持集群配置一致我们需要将配置好的Spark目录整个分发到所有Worker节点。使用rsync或scp# 假设你在Master节点的 /opt 目录下 # 使用rsync更高效支持增量同步 rsync -avz /opt/spark-3.5.1-bin-hadoop3/ spark-worker-01:/opt/spark-3.5.1-bin-hadoop3/ rsync -avz /opt/spark-3.5.1-bin-hadoop3/ spark-worker-02:/opt/spark-3.5.1-bin-hadoop3/ # 或者在每个Worker节点上也创建同样的软链接 ssh spark-worker-01 cd /opt ln -sfn spark-3.5.1-bin-hadoop3 spark ssh spark-worker-02 cd /opt ln -sfn spark-3.5.1-bin-hadoop3 spark分发完成后务必检查每个Worker节点上的spark-env.sh文件特别是JAVA_HOME路径因为不同节点的Java安装路径可能略有不同。需要根据每个节点的实际情况进行调整。4. 集群启动、验证与第一个分布式任务配置全部就绪最激动人心的时刻到了——启动集群并运行任务。4.1 启动与停止集群在Master节点上进入Spark的sbin目录使用提供的脚本。方法一使用脚本一键启动推荐前提是配好了SSH免密和workers文件cd /opt/spark/sbin ./start-all.sh这个脚本会先读取conf/spark-env.sh设置环境变量然后读取conf/workers文件通过SSH登录到每个列出的Worker节点启动Worker进程。方法二手动在各节点启动更可控便于调试在Master节点启动Master进程cd /opt/spark/sbin ./start-master.sh # 或者指定配置文件路径 # ./start-master.sh -h spark-master -p 7077 --webui-port 8080启动后查看日志$SPARK_HOME/logs/spark-*-master-*.out或直接访问http://spark-master:8080确认Master已启动。在每个Worker节点启动Worker进程# 在 spark-worker-01 上执行 cd /opt/spark/sbin ./start-worker.sh spark://spark-master:7077 # 同样在 spark-worker-02 上执行相同的命令这里的spark://spark-master:7077是Master的RPC地址从Master的Web UI或日志中可以找到。启动后访问Master的Web UI (http://spark-master:8080)你应该能看到“Alive Workers”的数量与你启动的Worker数一致并且每个Worker都显示了其内存和核心资源。停止集群# 在Master节点执行 cd /opt/spark/sbin ./stop-all.sh4.2 常见启动故障排查第一次启动很少有一帆风顺的。下面是一些典型问题及排查思路Worker无法连接到Master现象Worker日志显示Failed to connect to master spark-master:7077。排查网络连通性在Worker节点执行telnet spark-master 7077或nc -zv spark-master 7077。如果不通检查Master节点的防火墙是否开放了7077端口以及SPARK_MASTER_HOST是否绑定到了正确的网络接口有时会绑定到127.0.0.1。主机名解析确认Worker节点上/etc/hosts文件或DNS能正确解析spark-master为主节点的IP地址。Master进程状态确认Master进程确实在运行 (ps aux | grep spark)并监听在7077端口 (netstat -tlnp | grep 7077)。Master的Web UI可以访问但Worker显示为“DEAD”或根本不出现现象Master UI的“Workers”列表为空或Worker状态异常。排查检查Worker日志这是最重要的信息源。日志通常在$SPARK_HOME/logs/下文件名类似spark-*-worker-*.out。查看里面是否有错误堆栈。资源冲突检查SPARK_WORKER_MEMORY设置是否超过了机器物理内存。检查端口冲突Worker会启动一个Web UI默认8081和随机端口确保这些端口没有被占用。环境变量确认Worker节点上的JAVA_HOME在spark-env.sh中配置正确且已生效。使用start-all.sh脚本时某些Worker启动失败现象脚本报错Permission denied (publickey,password).。排查SSH免密登录配置有问题。回到2.2节仔细检查。确保Master节点的公钥(~/.ssh/id_rsa.pub)内容已经追加到了目标Worker节点的~/.ssh/authorized_keys文件中并且该文件的权限是600 (chmod 600 ~/.ssh/authorized_keys)。4.3 提交第一个分布式应用集群运行正常后我们来提交一个简单的任务验证集群是否能协同工作。我们使用Spark自带的计算Pi的示例。在Master节点或任何能访问到spark://spark-master:7077的客户端机器上执行cd /opt/spark ./bin/spark-submit \ --master spark://spark-master:7077 \ --class org.apache.spark.examples.SparkPi \ --executor-memory 1G \ --total-executor-cores 2 \ ./examples/jars/spark-examples_2.12-3.5.1.jar \ 100参数拆解--master spark://spark-master:7077指定集群Master的地址。这是最关键参数告诉spark-submit把任务提交到哪里。--class指定包含main方法的完整类名。--executor-memory 1G为每个Executor进程分配1GB内存。这个值不能超过单个Worker的SPARK_WORKER_MEMORY。--total-executor-cores 2为这个应用申请总共2个CPU核心。Spark会在Worker间分配这些核心。./examples/jars/spark-examples_*.jar示例Jar包的路径。100传递给SparkPi示例的参数代表迭代次数越大计算越精确。提交后控制台会输出大量日志最后找到类似Pi is roughly 3.141592653589793的一行说明计算成功。同时你可以刷新Master的Web UI (http://spark-master:8080)在“Running Applications”或“Completed Applications”列表中看到你刚提交的应用点击进去可以查看详细的执行计划、任务阶段、Executor列表等信息。一个重要的观察点在应用详情页查看“Executors”标签页。你会看到这个应用申请到的Executor被分配在了哪些Worker节点上每个Executor使用了多少内存和核心。这是理解Spark资源调度最直观的方式。5. 生产环境考量与进阶配置基础集群跑起来只是第一步。要用于实际生产或更严肃的开发测试还需要考虑以下几点。5.1 日志管理与历史服务器默认情况下Spark应用的日志随着应用结束而消失Web UI也无法再访问。这对于调试已完成的任务非常不便。Spark提供了History Server来持久化查看已完成应用的信息。配置事件日志编辑conf/spark-defaults.conf(复制模板spark-defaults.conf.template)。# 启用事件日志记录 spark.eventLog.enabled true # 指定事件日志存储目录需要是所有节点都能访问的共享目录如HDFS或NFS spark.eventLog.dir hdfs://namenode:8020/spark-logs # 或者使用本地路径仅单节点History Server可读 # spark.eventLog.dir file:///var/log/spark-events # 指定History Server的地址用于在Web UI生成链接 spark.history.fs.logDirectory hdfs://namenode:8020/spark-logs如果使用HDFS需要确保Spark有相应权限。如果使用本地目录需要确保该目录存在且History Server进程有读写权限。启动History Servercd /opt/spark/sbin ./start-history-server.sh默认访问地址是http://history-server-host:18080。现在当你提交应用时应用信息会被记录到指定目录即使应用结束也可以在History Server的UI上查看其详情。5.2 资源调度与动态分配在spark-defaults.conf中可以配置更精细的资源调度策略。静态分配我们之前用的就是静态分配通过--executor-memory和--total-executor-cores为应用固定资源。适合对资源需求明确且稳定的应用。动态分配允许Spark根据当前任务负载动态地向集群申请或释放Executor。这对于多用户共享集群或批处理与流处理混合的场景非常有用。spark.dynamicAllocation.enabled true spark.dynamicAllocation.initialExecutors 1 spark.dynamicAllocation.minExecutors 1 spark.dynamicAllocation.maxExecutors 10 spark.shuffle.service.enabled true # 启用外部Shuffle服务对于动态分配至关重要启用动态分配后需要额外启动一个spark shuffle service。5.3 高可用性HA部署我们目前是单Master如果Master节点宕机整个集群将无法提交新应用运行中的应用也可能失败。实现HA需要部署多个Master节点并借助ZooKeeper来选举Active Master。部署ZooKeeper集群至少3个节点。修改所有节点的spark-env.shexport SPARK_DAEMON_JAVA_OPTS-Dspark.deploy.recoveryModeZOOKEEPER -Dspark.deploy.zookeeper.urlzk1:2181,zk2:2181,zk3:2181 -Dspark.deploy.zookeeper.dir/spark启动集群在所有备选Master节点上启动Master进程./start-master.sh在Worker节点上启动Worker时需要连接所有Master用逗号分隔./start-worker.sh spark://master1:7077,master2:7077当一个Active Master失败后ZooKeeper会从Standby Master中选举出新的Active Master。Worker和客户端配置了多个Master地址会自动重连到新的Active Master。5.4 监控与运维建议监控指标Spark通过Metrics系统暴露了大量指标可以集成到PrometheusGrafana等监控栈中。关注指标如JVM堆内存使用、GC时间、各Stage耗时、Shuffle读写量、Executor存活数等。日志聚合将各节点的Spark日志$SPARK_HOME/logs集中收集到ELKElasticsearch, Logstash, Kibana或类似系统中方便全局检索和问题定位。配置版本化将spark-env.sh、spark-defaults.conf等配置文件纳入版本控制如Git确保集群配置变更可追溯、可回滚。使用集群管理工具对于更复杂的生产环境可以考虑使用Ansible、SaltStack等工具来自动化Spark集群的部署、配置管理和服务启停确保环境的一致性。部署一个稳定可靠的Spark完全分布式集群是进行大规模数据处理的基础。这个过程就像搭积木每一步的稳固都决定了最终建筑的可靠性。从主机名解析、环境变量到端口开放每一个细节都值得仔细对待。希望这篇详细的指南能帮你避开我当年踩过的那些坑顺利搭建起属于自己的Spark计算集群。
返回列表