ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Azkaban启动实战指南:Hadoop工作流调度器的部署、配置与排错

Azkaban启动实战指南:Hadoop工作流调度器的部署、配置与排错 开头如果你正在学 Hadoop并且进度已经推到了“工作流调度”这一节那你大概率绕不开 Azkaban 这个名字。我之前在好几个数据平台项目里都用它来管理定时任务和 Hive/Spark 作业的编排这篇文章就专门聊聊一个非常实际的环节——Azkaban 的启动。不少同学跟着教程把安装包解压好了、数据库也建好了结果卡在启动这一步要么是 Web 界面死活打不开要么是 Executor 报错连不上 MySQL再要么就是启动成功了但一提交任务就失败。这些问题的根子往往不在启动那一刻而在启动前的一堆小细节里。这篇文章适合两种人一种是刚把 Hadoop 伪分布式或者集群搭好、正要装 Azkaban 入门的新手另一种是在真实环境里被启动问题折磨过、想系统理清 Azkaban 部署和启动逻辑的工程师。我会从 Azkaban 的架构开始讲把所有关键配置、启动顺序、日志排查技巧都过一遍最后还会附上我踩过的坑和排查经验。读完你就能明白为什么明明按教程做了还是起不来以及下次再遇到启动失败该怎么自己定位问题。1. 先把 Azkaban 是什么说清楚——为什么 Hadoop 集群需要它很多人第一次看到“Azkaban 的启动”这个标题心里想的是“不就是敲个启动命令嘛有什么好讲的”。这种想法我特别理解但只有真正在生产环境里维护过 Hadoop 平台的人才知道启动 Azkaban 之前你得先理解它在整个大数据体系里扮演什么角色。1.1 工作岗位里的“闹钟管理员”调度器的价值Hadoop 生态里光有 HDFS 存数据、Yarn 跑计算是不够的。一个真实的数据平台往往有成百上千个任务凌晨两点跑日志清洗、凌晨三点跑用户画像、早上八点跑报表汇总……这些任务有依赖关系有执行时间要求失败了还要重试和告警。如果靠人肉去敲命令迟早出事故。Azkaban 要解决的就是这件事。它是个工作流调度器你可以在上面定义“作业Job”和“依赖关系Flow”设定执行时间查看运行日志失败后自动重试或者报警。用一句话概括Azkaban 是数据平台的“闹钟管理员”和“流水线班长”负责按时把事情安排在对应的时间点并按顺序做完。所以当你说“启动 Azkaban”本质上是在启动整个数据任务的中枢控制系统。如果这一层没起来那些 MapReduce、Spark、Hive 任务就没人帮你去排队、去按顺序执行。这也解释了为什么 Azkaban 启动问题会影响面特别大——它不是单点工具而是整个平台运转的地基之一。1.2 Azkaban 的架构和选型两种部署模式怎么选知道了它多重要我们来看看它的肚子里面长什么样。Azkaban 从 3.x 开始拆分成了两个核心进程Azkaban Web Server负责用户登录、项目管理、调度配置、界面展示。你可以理解成“前台大厅”所有操作都走它。Azkaban Executor Server真正把 Job 提交到 Hadoop/Yarn 上运行的“执行工人”。可以多个 Executor 组成集群Web Server 负责负载均衡和分发。这两者的关系可以类比成餐厅里“前台点菜”和“后厨做菜”前台记录你要吃什么后厨按顺序做出来再把结果端回去。启动的时候如果你只启动了前台菜永远做不出来只启动后厨客人又没地方下单。Azkaban 有几种部署模式我实际用下来最常见的是两种模式特点适用场景solo-server 模式内置 H2 数据库一个进程搞定 Web Executor只适合本地演示学习测试快速体验two-server 模式Web Server 与 Executor Server 分离共用 MySQL支持多执行器生产环境正式项目很多人一上来就误以为 solo-server 就是 Azkaban 的全部结果学着学着发现生产环境根本不用这个。本文后面讲的是 two-server 模式的启动这个才是真正有实战价值的内容。把一个 Executor 的 two-server 模式部署好以后集群要扩展就只是加机器的事。2. 安装前的环境规划版本匹配是启动成功的前提前面说得再多落不了地都是白搭。下面进入正经实操。我先给出一套我在生产环境验证过的部署方案Hadoop 2.7.x 或 3.x伪分布式或集群均可JDK 1.8MySQL 5.7Azkaban 3.70.0源码编译产物或官方 release 包2.1 每个软件版本都要有姓名Hadoop/MySQL/JDK 的搭配版本问题是启动失败的“第一大元凶”比什么配置漏写都常见。先说 JDK。Azkaban 是用 Java 写的Web Server 和 Executor 都是 Java 进程所以 JDK 必须提前装好并且配好JAVA_HOME。我的建议是直接用 JDK 1.8不要图新鲜上 11 或者 17。老版本 Hadoop 生态对 JDK 版本极其敏感你为了省事换新版本后面会遇到一堆诡异的UnsupportedClassVersionError排查起来非常煎熬。再说 MySQL。Azkaban 从 3.x 开始把元数据存在 MySQL 里包括用户信息、项目信息、调度计划、执行记录等。数据库版本建议 5.7字符集用 utf8mb4 或者 utf8 都行但排序规则最好统一。其中一个特别容易被忽略的点是MySQL 的连接数。Azkaban 启动时会初始化一堆线程池如果你用的是默认配置连接数上限不够启动阶段就会在数据库连接池初始化那里卡住。最后是 Hadoop。Azkaban 本身是通过命令行提交 Job 的它跟 Hadoop 的耦合主要在 core-site.xml、hdfs-site.xml、yarn-site.xml 里。你不需要单独给 Azkaban 编译什么 Hadoop 插件但得保证 Job 执行节点的机器能连上 Hadoop 集群。换句话说你启动 Azkaban 的机器必须能正常执行hdfs dfs -ls /这种命令否则 Executor 即使起来了提交任务也会失败。2.2 工程结构提前规划下载编译还是直接次包Azkaban 官方 GitHub 仓库提供两种获取方式下载 release 包或者自己编译。release 包是最省事的选择但版本一定要挑对。这里有个坑Azkaban 3.70.0 之后主仓库基本不怎么发新 release 了很多资料还会让你去源码里翻build插件。新手最稳妥的做法是直接去 GitHub 的 release 页面找azkaban-web-server-*.tar.gz、azkaban-exec-server-*.tar.gz和azkaban-db-*.sql这三样就够了。我自己试过用源码编译确实也能出包但过程很折磨Maven 下载依赖慢某些测试用例还会因为网络问题失败。如果你不是要对 Azkaban 做二次开发别折腾编译直接拿 release 包。拿到压缩包之后建议目录结构这样设计/data/azkaban/azkaban-web-server-3.70.0 /data/azkaban/azkaban-exec-server-3.70.0 /data/azkaban/azkaban-db-3.70.0.sqlAzkaban 本身就是免安装的解压改配置就算“安装”完成真正决定成败的是配置文件和启动顺序。2.3 创建部署目录与系统用户生产环境里我强烈建议用单独的账号跑 Azkaban不要直接用 root。原因是 Azkaban 的 Executor 要提交任务到 Yarn而 Yarn 对执行用户身份有严格的校验逻辑。如果进程以 root 身份跑任务提交后你会看到User xxx not found或者权限相关的报错等到业务方催你的时候才知道什么叫崩溃。创建账号并调整目录所有者useradd azkaban passwd azkaban mkdir -p /data/azkaban chown -R azkaban:azkaban /data/azkaban然后解压两个 server 包并给启动脚本加好执行权限。启动脚本的位置分别在azkaban-web-server-*/bin/azkaban-web-start.shazkaban-exec-server-*/bin/azkaban-exec-start.sh到这里环境层面的准备就结束了。不要急着启动先把你手头的 MySQL、Hadoop 状态确认好MySQL 能连上吗Hadoop 的jps能看到 NameNode 和 DataNode 吗这些外部依赖没就绪之前启动 Azkaban 就是白费功夫。3. Azkaban 安装配置实操Web 与 Executor环境准备好以后就到了最容易出错的配置阶段。很多教程喜欢直接扔一个配置模板但完全不解释每个参数是干嘛的。我在这里会把重点参数拆开讲清楚目的是让你在启动失败的时候敢于看配置而不是只会复制粘贴。3.1 先跑 Nginx 没用的先初始化 MySQL 数据库Azkaban 的 Web Server 和 Executor Server 都要连 MySQL所以第一步是把数据库建好、表结构导进去。登录 MySQLmysql -uroot -p创建数据库和用户CREATE DATABASE azkaban DEFAULT CHARACTER SET utf8; CREATE USER azkaban% IDENTIFIED BY your_password; GRANT ALL PRIVILEGES ON azkaban.* TO azkaban%; FLUSH PRIVILEGES;然后导入官方提供的建表脚本mysql -uroot -p azkaban /data/azkaban/azkaban-db-3.70.0.sql导入完成后你可以确认一下表数量正常情况下会生成几十张表包括executors、projects、execution_jobs、schedules等。如果你发现表数量明显偏少说明 SQL 文件导入不完整后面启动大概率会报“找不到表”的错误。这里有一个非常容易被忽略的点executor 表里默认没有任何数据。Azkaban 的 Web Server 是通过查这张表才知道有哪些 Executor 可用的。如果表里没记录Web Server 就会提示“no active executors”任务根本没法执行。我们需要提前手动插入一条INSERT INTO executors (host, port, active) VALUES (你的主机名或IP, 12321, 1);这条记录要跟你后续在 Executor 配置文件里写的azkaban.executor.port保持一致。写错的话Web Server 会认为这台 Executor 不存在。3.2 配置 Executor Server别人忽视的端口参数Executor Server 的配置文件在解压目录下的conf/azkaban.properties。这个文件是 Azkaban 的核心配置所在地两个服务都有自己的版本一定不要搞混。Executor 侧的关键配置如下# 数据库连接 database.typemysql mysql.port3306 mysql.host你的MySQL地址 mysql.databaseazkaban mysql.userazkaban mysql.password你的密码 mysql.numConnections100 # Executor 服务端口 azkaban.executor.port12321 # 执行器名称 azkaban.nameexecutor-server # 时区 default.timezone.idAsia/Shanghai有两个配置我要专门提示一下。第一个是azkaban.executor.port默认值是 12321这是 Executor 服务对外暴露的 RPC 端口Web Server 通过它来和 Executor 通信。你启动之后可以用netstat -anp | grep 12321检查端口是否监听。第二个是mysql.numConnections。如果你部署的机器上跑的任务粒度很细并发量高线程池不够就会报Timeout when waiting for connection。我一般会调到 100 左右如果你的 MySQL 资源紧张50 也能跑但 100 是我试下来比较平衡的值。3.3 配置 Web Server最容易踩坑的三个参数Web Server 的配置同样是conf/azkaban.properties但内容比 Executor 多不少。我把最容易踩坑的三个参数列出来# Web 服务端口 jetty.port8081 # MySQL database.typemysql mysql.host你的MySQL地址 mysql.port3306 mysql.databaseazkaban mysql.userazkaban mysql.password你的密码 # Azkaban 自身管理 azkaban.executorselector.filtersStaticRemainingFlowSize,MinimumFreeMemory azkaban.executorselector.comparator.NumberOfAssignedFlowComparator1 # 项目存储目录 project.dir/data/azkaban/azkaban-web-server-3.70.0/projects # 用户管理配置 user.manager.xml.fileconf/azkaban-users.xml先说jetty.port。Azkaban 的 Web 界面默认是 8081而不是 8080。很多新手习惯性打开http://localhost:8080当然打不开。这一点如果你已经知道了可能不觉得是问题但确实有太多人卡在“启动成功却访问不了”的假象里。再说azkaban.executorselector.filters。这个参数的含义是当系统有多个 Executor 时Web Server 根据什么规则来挑选合适的执行器。StaticRemainingFlowSize表示按剩余任务量选择MinimumFreeMemory表示按最小空闲内存选择。如果你只有一台 Executor这个规则随便写写就行如果以后扩容了要再深入研究这些过滤器的权重。我第一次配置的时候图省事没写这一个参数结果 Web 界面里总显示“no active executors”折腾了半天才发现是 Executor 管理器没有正确注册。最后是project.dir。Azkaban 每次上传项目包后会把压缩包解压到本地目录。如果不配这个目录默认位置在$AZKABAN_HOME/projects下倒也不是不能用但我建议显式配置到你的数据盘避免系统盘空间被撑爆。Web Server 还有一个文件叫azkaban-users.xml用来配置登录用户。默认配置里有azkaban用户密码也是azkaban。你本地测试可以直接用正式环境一定要改掉默认密码否则你的调度界面就等于裸奔。3.4 配置文件里的“隐形杀手”时区和内存除了上面说的大项还有两个小点专门拿出来讲因为它们在启动时报错的表现极具迷惑性。一个是时区。Azkaban 的调度系统对时间非常敏感如果服务器默认时区是 UTC而你设置的是 Asia/Shanghai界面上的“下次运行时间”永远比你预期的时间差 8 小时。我在生产环境里用default.timezone.idAsia/Shanghai同时把操作系统本身的时区也改成 CST。两条线都对齐了调度时间才能不出岔子。另一个是 JVM 内存参数。Azkaban 的启动脚本里默认给了内存设置在bin/azkaban-web-start.sh里通常有类似JAVA_OPTS-Xmx4G -Xms4G -server如果你是拿 2G 内存的虚拟机调试默认 4G 可能会直接导致内存不足进程起不来。我一般会在实验环境把它调成JAVA_OPTS-Xmx1G -Xms512M -server生产环境再根据业务量适当加大。启动脚本里改这一行不会破坏任何功能但你节省的可能是整个下午的排错时间。4. 启动顺序与启动排错全流程配置写完终于到了正题启动。这一节我会按“实际踩坑顺序”来写而不是按文档顺序因为你真正动手的时候90% 的注意力都会花在“起没起来、为什么没起来、日志里写了什么”这三件事上。4.1 关键规则先 Executor 后 Web我见过最多的启动错误先启 Web后启 Executor然后 Web 界面能打开但一直找不到可用的执行器。原因前面也说了Web Server 启动时要读取 MySQL 中executors表的记录如果 Executor 进程还没起来它就认为集群里没有可用资源。所以标准顺序是启动 MySQL 并确认azkaban库可连接启动 Executor Server确认 12321 端口监听启动 Web Server确认 8081 端口监听Executor 启动命令cd /data/azkaban/azkaban-exec-server-3.70.0 bin/azkaban-exec-start.sh执行完以后不要急着干别的先看日志tail -100 logs/azkaban-exec-server.log正常情况下会出现类似关键信息Starting Executor Server ... ...... Added executor 1 with host xxx如果你看到Added executor字样说明 Executor 已经成功注册到数据库了。这一步非常重要因为它是 Web 端能找到执行器的前提。Web Server 启动命令cd /data/azkaban/azkaban-web-server-3.70.0 bin/azkaban-web-start.sh同样看日志tail -100 logs/azkaban-web-server.log看到Starting Jetty Server和Server started之类的日志基本就成功了。这时访问http://服务器IP:8081用配置好的账户登录即可。4.2 启动脚本实操与检查很多教程到上面那步就结束了但实战中你还需要掌握“检查进程”这项基本功。启动脚本本身是后台运行的它把日志写进文件不会像mapreduce任务一样时刻在前台刷屏。所以你会觉得“好像没反应”这是正常的。我用几个命令来确认它真的起来了。第一看进程是否存活jps | grep -E Azkaban(Web|Exec)Server正常会有两个AzkabanWebServer和AzkabanExecutorServer这样的 Java 进程。第二看端口是否监听netstat -lntp | grep -E 8081|12321第三确认数据库里的执行器状态SELECT id, host, port, active FROM executors;active字段为 1 才说明 Web Server 认为这台执行器可用。如果看到 0说明 Executor 虽然起了但没完成注册大概率是配置文件里的端口或者主机名对不上。这一套三连检查做完启动是否成功基本一目了然。4.3 结合日志判断启动状态日志是判断启动状态的最终依据。Azkaban 的日志文件通常在各自目录下的logs/文件夹启动失败时错误信息也会写在这里。我积累了一份快速判断表你可以对照着看日志关键字含义通常原因Added executor执行器注册成功正常Starting Jetty ServerWeb 容器启动正常ERROR ... Failed to obtain connection数据库连不上MySQL 地址、IP、密码不对ERROR ... No active executorsWeb 找不到执行器没启 Executor或 executors 表为空ERROR ... Address already in use端口被占用另一个实例没关干净ERROR ... java.net.UnknownHostException主机名解析失败/etc/hosts 没配好Exception during DB init数据库初始化失败SQL 文件没导入完整别小看这份表很多启动问题在日志里都有非常明显的线索。你与其去猜配置哪里写错了不如先打开日志按关键字搜一遍。4.4 启动失败的排查思路先剥洋葱别拆到底启动失败最容易让人急躁但排查思路其实是“从外到内、层层剥洋葱”的过程看端口通不通。外部访问 Web 界面失败先curl http://localhost:8081如果连接被拒说明 Web 进程本身就没起来或者监听地址不对。看日志报什么。日志文件是最真实的消息源比任何教程都准。看 MySQL 连接。Azkaban 的两个 Server 强依赖 MySQL数据库不通就是最典型的启动失败原因。看权限。日志目录、项目目录的所有者是不是当前启动用户。文件权限不对启动脚本写日志都会失败。看主机名解析。很多时候你花半天查配置文件最后发现是/etc/hosts里没有本机主机名的解析记录。Java 进程在启动时要InetAddress.getLocalHost()解析不了直接抛异常。这五步走完90% 的启动问题都能定位。5. 和 Hadoop 生态的整合任务真正跑起来Azkaban 起不来是问题但更常见的情况是“启动了却跑不了任务”。这一节讲启动之后跟 Hadoop 的联动。既然标题里有 hadoop这部分我多说几句。5.1 想让 Executor 提交任务先让机器“认识”HadoopExecutor Server 所在机器必须能正常执行 Hadoop 命令。验证方法hdfs dfs -ls /如果能正常列目录说明 Hadoop 客户端环境没问题。如果报找不到命令说明HADOOP_HOME没配或者没 source。需要在启动 Azkaban 的用户环境变量里加上export HADOOP_HOME/opt/hadoop export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin加到/etc/profile或者用户.bashrc里。这一步漏掉的话Azkaban 的 Job 执行时会在日志里直接报“command not found”但 Web Server 本身却能正常跑迷惑性极强。5.2 在 Azkaban 里创建一个最简单的 Hello 工作流配置和启动都搞定以后建议先创建一个最简单的测试项目验证整条链路是通的。第一步新建一个项目目录写一个.job文件# hello.job typecommand commandecho hello azkaban第二步把 job 文件打成压缩包zip -r hello.zip hello.job第三步在 Azkaban Web 界面创建项目并上传hello.zip然后执行。如果日志里能看到hello azkaban的输出说明整条链路已通Web 找到 ExecutorExecutor 找到 Hadoop任务正常执行。如果你想在实际业务里用得更深可以把command换成hive或spark-submit通过 Azkaban 把这些计算任务串起来。这也是 Azkaban 在生产里最常见的用法。5.3 集群模式下的额外注意事项如果你的 Hadoop 是集群Executor 机器的/etc/hosts上要让所有 DataNode 和 NodeManager 主机名都能解析。Hadoop 各节点之间的通信靠的是主机名如果你这台机器解析不了集群里的其他节点即使 HDFS 客户端能连上 NameNode执行 MapReduce 任务时也可能在获取数据副本阶段失败。另外Yarn 的yarn.resourcemanager.hostname在客户端机器上要能访问。很多伪分布式单机环境没问题但一旦你拓展到多台机器网络策略、防火墙默认禁止的端口如 8088、8042、50010都会成为故障点。Azkaban 的 Executor 只负责发起提交真正跑计算的是 Yarn 上的 Container所以你的 Executor 机器和 Hadoop 集群之间网络必须双向通。6. 常见问题与避坑实录这一节把我这些年遇到的启动相关典型问题整理成速查表再分享几个一般文档里不会写的排错技巧。6.1 问题速查表现象原因解决方案Web 界面无法访问端口错误、Web 没启动确认jetty.port8081检查进程和日志登录后提示 no active executorsExecutor 没启动或 executors 表记录不对先启 Executor并检查executors表active字段Executor 启动时报 SQL 连接失败MySQL 地址、账号、密码写错用命令行验证是否能连上对应的库提交任务后长时间排队Executor 注册异常重启 Executor检查日志注册信息任务日志显示 command not found环境变量缺失在启动用户的环境变量中配置 Hadoop 路径任务失败显示权限错误用 root 启动 Azkaban改用专用账号并把目录 owner 换掉调度时间不对时区配置不一致配置default.timezone.idAsia/ShanghaiWeb 启动后马上退出内存不足或者端口冲突调低启动脚本中的 JVM 参数查端口占用上传 zip 包后解析失败zip 包结构不对确保 job 文件在压缩包根目录不要嵌套目录6.2 独家排错技巧启动不求人第一个技巧把 executor 表的删除和重建写成一条命令。平时测试要反复重启经常遇到 Executor 没注册成功的情况。与其每次进入 MySQL 手动删数据不如在启动 Executor 前直接执行DELETE FROM executors;再重新启 Executor它会自己往表里插新的记录。这个方法在反复调试配置时能省掉很多无谓操作。第二个技巧启动脚本里加“日志前置打印”。有些问题在启动脚本读配置时就会崩溃但日志文件可能还没创建所以你怎么tail都是空。我习惯在azkaban-web-start.sh第一行加一句echo start at $(date)这样脚本是否开始执行一查便知。第三个技巧如果你改了配置之后执行启动脚本没反应先确认你确实在bin目录下执行的而不是在别的目录下调用脚本。Azkaban 的脚本会尝试用相对路径读conf/和lib/如果你在别的目录下执行会报找不到配置文件或者直接读取了默认路径。我踩过一次这种坑花了一个小时。第四个技巧生产环境别忘了配置重启策略。Azkaban 的进程挂了不会自动拉起建议用 supervisor 或者 systemd 做守护。守护脚本的核心命令很简单bin/azkaban-exec-start.sh但 ulimit、JAVA_HOME、HADOOP_HOME 这些环境变量都要在 systemd 的 Unit 文件里写全否则你手动启动没问题一交给 systemd 就报找不到 Java这类问题也相当常见。6.3 最后再分享一个我自己的经验单独把这条拎出来说是因为它救过我很多次。任何一次重启 Azkaban都先把旧进程彻底杀干净。Azkaban 启动脚本在 stop 的时间点上很“默契地”做得比较敷衍有时候进程还挂着端口还占着你以为停了结果再启动时直接Address already in use。我现在的标准操作是jps | grep Azkaban kill -9 pid确认输出为空之后再执行启动脚本。可能有人觉得 kill -9 太暴力但 Azkaban 本身不是一个需要优雅停机的系统它的执行状态都写着数据库里强杀不会导致脑裂。还有一个小点很多资料会推荐使用nohup方式手动启动我个人反而更推荐用自带的start脚本。因为自带脚本里包含了一些环境变量和 CLASSPATH 的初始化逻辑你自己nohup启动很容易漏掉某个环节然后出现“手工能启动、提交任务却失败”的诡异现象。老老实实用官方脚本才是效率最高的路径。Azkaban 的启动表面上看是“跑一个命令”的事实际上牵涉到数据库初始化、双服务注册、端口校验、Hadoop 客户端环境、系统时区、JVM 参数等一串连锁环节。把这套东西理清楚了你不仅能把 Azkaban 启动起来更能在以后遇到任何分布式组件启动问题时有一套自己的排查方法论。这也是我为什么愿意花这么大篇幅写启动这件事的原因——它是理解整个调度系统工作原理的最好入口。
返回列表