Azkaban solo-server 单机任务调度实战:解包、配置、跑通与避坑
简介Azkaban 是一款由 LinkedIn 开源的工作流执行引擎常用于大数据处理任务的调度与管理。这份 azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz 是其单服务器部署版本已编译打包解压即可运行适合小型团队、个人开发者以及需要快速搭建作业调度环境的入门用户。包体约 42.28MB为 gz 压缩格式上游未提供具体文件清单但按单机版结构通常包含 Web 服务、执行器与内嵌 H2 数据库等核心组件无需额外编译。该版本将全部服务集中于同一台机器安装配置简单可通过 Web 界面创建项目、定义作业依赖、设计工作流并设置定时调度同时查看执行状态与日志便于调试排错。目前已有 256 人学习下载可作为理解 Azkaban 调度模型与工作流编排的轻量实践入口。需注意 SNAPSHOT 属开发中版本生产环境建议改用稳定版或集群部署。1. 从一份 azkaban-solo-server 包说起单机任务调度到底能扛多少活手里这份azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz是 Azkaban 的单机执行版打包产物。Azkaban 本身是 LinkedIn 开源的批量工作流任务调度器靠.job文件和flow依赖描述把一堆散脚本串成有向无环图按依赖顺序跑。solo-server 模式把 web 控制台、执行器、元数据库全塞进一个 JVM 进程用内置 H2 存状态开箱即跑不需要 MySQL、不需要 executor 集群。它适合谁适合手上有一批 shell、Python、SQL 脚本要按顺序和依赖跑、又不想一上来就搭分布式调度的人——本地开发验证、小团队日批、CI 里跑一次性流水线都是它的舒适区。但单机就是单机并发和持久化的边界得先摸清楚后面几章我会把解包、配置、跑通、踩坑一条条拆开。2. 解包与目录结构先看清 solo-server 里装了什么2.1 解包与目录布局拿到 tar.gz 第一步不是急着启动而是先看它把什么打进去了。solo-server 的包结构相对固定解压后大致是这么几层# 解压到指定目录避免污染当前工作区 mkdir -p /opt/azkaban tar -zxvf azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz -C /opt/azkaban # 进入解压后的根目录查看结构 cd /opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT ls -la典型目录长这样目录/文件作用是否要改bin/启停脚本start-solo.sh、shutdown-solo.sh一般不动conf/azkaban.properties、log4j.properties、global.properties必改lib/全部依赖 jar含 azkaban core、H2、jetty不动plugins/job 类型插件目录如 jobtype、common按需executions/运行时生成的执行日志与临时目录自动生成projects/上传的项目包解压落点自动生成logs/服务端日志自动生成conf/azkaban.properties是核心solo-server 默认用 H2 内嵌库配置项里database.typeh2、h2.path指向本地文件。这里有个容易忽略的点H2 文件路径如果是相对路径会相对于启动时的工作目录解析所以启动脚本里通常会cd到安装根目录再拉起 JVM。你要是手动java -jar启动工作目录不对数据库文件就落到别处重启后任务历史凭空消失这是新手最常见的翻车点之一。2.2 关键配置项逐个说清打开conf/azkaban.propertiessolo-server 模式下真正影响行为的配置没几个但每个都得知道改了会怎样# 时区影响调度时间和日志时间戳国内部署务必改 azkaban.default.timezoneAsia/Shanghai # web 服务端口默认 8081被占用就换 jetty.port8081 # 数据库类型solo 模式固定 h2 database.typeh2 # H2 数据文件路径建议写绝对路径避免工作目录漂移 h2.path/opt/azkaban/data/azkaban # 执行器线程数决定同时能跑多少个 flow executor.flow.threads30 # 单次执行保留的最大日志大小超了会截断 executor.max.log.size102400 # 是否允许用户上传自定义 job 类型生产建议 false azkaban.server.allow.user.jobtypefalseexecutor.flow.threads这个参数最容易被误解。它限制的是同时处于运行态的 flow 数量不是单个 flow 里的 job 并发数。单个 flow 内部的 job 并发由 flow 定义里的依赖关系决定Azkaban 会按 DAG 拓扑序推进能并行的 job 会并行提交。所以你把flow.threads调到 100不代表一个 flow 里 100 个 job 能一起跑只代表能同时接 100 个 flow。单机 CPU 和内存有限这个值调太大反而会让 JVM 频繁 GC我一般按CPU 核数 × 2起步压测后再定。executor.max.log.size单位是字节默认 100KB 左右跑长任务时日志很容易被截断排查问题时看不到关键报错。常见做法是调到 10MB 级别同时配合 log4j 的滚动策略别让单个日志文件无限涨。3. 跑通第一个 flow从 .job 文件到依赖编排3.1 写一个带依赖的三节点 flowAzkaban 的任务单元是.job文件本质是 keyvalue 的属性文件typecommand表示跑 shell 命令。依赖关系靠文件名前缀加数字来声明a.job里写dependenciesb就表示 a 依赖 b。下面写一个下载 → 处理 → 校验的三步 flow# 建一个项目目录 mkdir -p ~/azkaban-demo cd ~/azkaban-demo # 第一步准备数据 cat 01_prepare.job EOF typecommand commandecho prepare data at $(date) mkdir -p /tmp/azk-demo echo raw /tmp/azk-demo/raw.txt EOF # 第二步处理数据依赖第一步 cat 02_process.job EOF typecommand commandcat /tmp/azk-demo/raw.txt | tr a-z A-Z /tmp/azk-demo/out.txt echo processed dependencies01_prepare EOF # 第三步校验结果依赖第二步 cat 03_verify.job EOF typecommand commandgrep -q RAW /tmp/azk-demo/out.txt echo verify ok || (echo verify failed exit 1) dependencies02_process EOF # 打包成 zipAzkaban 只认 zip zip -r demo.zip *.job三个.job文件加一个 zip 包这就是 Azkaban 项目的最小交付形态。dependencies的值是不带.job后缀的文件名写错了 Azkaban 在解析阶段就会报找不到依赖flow 根本提交不上去。command里如果有多条命令用串联任何一条返回非零整个 job 就标记为 FAILED后续依赖它的 job 不会执行——这是 Azkaban 的失败传播机制也是它比裸 crontab 强的地方。3.2 启动服务并提交执行配置改完、zip 打好启动 solo-server# 用官方脚本启动它会处理好工作目录和 classpath cd /opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT bin/start-solo.sh # 确认进程和端口 ps -ef | grep AzkabanSingleServer | grep -v grep netstat -tlnp | grep 8081启动脚本内部会cd到安装根目录再用java -cp lib/*:conf azkaban.soloserver.AzkabanSingleServer拉起主类。看到AzkabanSingleServer started且 8081 端口监听就说明起来了。浏览器打开http://机器IP:8081默认账号密码都是azkaban登录后Create Project→ 上传demo.zip→ 进入 flow 页面点Execute。执行完在Executions页能看到三个 job 的拓扑图和各自日志。如果03_verify失败点进去看它的日志会看到verify failed同时02_process是 SUCCESS、01_prepare是 SUCCESS——失败定位到具体节点这是调度器相对脚本堆叠的核心价值。提示solo-server 默认没有开启多用户权限体系所有项目对登录用户可见。多人共用时要么自己加前置鉴权要么别把它暴露在公网。3.3 用 API 触发接进现有流水线手动点页面只能验证真正落地要能程序化触发。Azkaban 提供 REST APIsolo-server 同样可用。先拿 session id再触发执行# 1. 登录拿 session.id SESSION$(curl -s -k -X POST http://127.0.0.1:8081 -d actionloginusernameazkabanpasswordazkaban | python3 -c import sys,json;print(json.load(sys.stdin)[session.id])) echo session$SESSION # 2. 触发指定项目的 flow 执行 curl -s -k -X POST http://127.0.0.1:8081/executor -d actionexecutesession.id$SESSIONprojectdemoflowdemodisabled[] # 3. 查询最近一次执行状态 curl -s -k http://127.0.0.1:8081/executor?actionfetchExecFlowsession.id$SESSIONexecid1actionexecute里的project和flow参数project是你在页面上建的项目名flow默认等于项目名Azkaban 会把项目里所有 job 按依赖拼成一个同名 flow。disabled[]是禁用节点列表传空数组表示全跑。返回的 JSON 里带execid拿这个 id 去fetchExecFlow查状态status字段是SUCCEEDED、FAILED、RUNNING之一。把这段塞进 CI 的 post 阶段就能实现代码合并后自动跑批。4. 避坑与排查solo-server 上最容易翻车的五件事4.1 重启后任务历史全没了现象服务重启后之前跑过的执行记录、项目列表全部消失像新装的一样。原因h2.path配的是相对路径或者启动时工作目录不是安装根目录H2 数据文件落到了临时目录重启后 JVM 换了工作目录找不到旧库。解决把h2.path改成绝对路径例如/opt/azkaban/data/azkaban并确保该目录存在且启动用户有写权限。改完先停服务把旧数据文件迁过去再启。4.2 flow 一直卡在 PREPARING 不动现象点了执行状态停在 PREPARING 或 RUNNING 但日志不更新。原因executor.flow.threads被占满新 flow 排队或者某个 job 的命令在等标准输入、等锁、等网络把执行线程挂住了。解决先看executor.flow.threads当前值和正在跑的 flow 数适当调大再进具体 job 日志看最后一行停在哪。命令里凡是可能交互的加/dev/null或-y参数别让脚本等输入。4.3 中文日志乱码现象job 日志里中文显示成问号或方块。原因JVM 默认字符集不是 UTF-8或者azkaban.default.timezone没配导致时间戳格式异常连带影响编码。解决在start-solo.sh的 java 启动参数里加-Dfile.encodingUTF-8同时把azkaban.default.timezoneAsia/Shanghai配上。改完重启新执行的日志就正常了历史日志不会追溯修复。4.4 上传 zip 报 Job file not found现象上传项目包时提示找不到 job 文件或 flow 解析失败。原因zip 打包时把.job文件套了一层父目录Azkaban 要求.job文件在 zip 根目录下或者dependencies写成了带.job后缀的名字。解决进到.job所在目录再zip -r demo.zip *.job别在上级目录打包整个文件夹。dependencies只写文件名主体不带后缀。4.5 单机跑大批量任务时 OOM现象跑几十个 flow 后 JVM 抛 OutOfMemoryError服务假死。原因solo-server 把 web、executor、H2 放一个 JVM默认堆内存偏小flow 多了之后执行上下文和日志缓冲把堆吃满。解决在启动脚本里调大-Xmx比如-Xmx2g同时把executor.flow.threads控制在合理范围别让并发无上限。真要跑大批量solo-server 不是终点该上分布式 executor 就上。5. 进阶技巧把 solo-server 当本地调度沙箱用solo-server 最被低估的用法是当本地调度沙箱——在把 flow 推到生产集群之前先在单机上把依赖关系、失败传播、重试逻辑验证一遍。我一般会这么做本地起一个 solo-server把生产 flow 的.job文件原样拷过来只改command里的路径和连接串跑通再推。这样能提前暴露 90% 的依赖写错、命令拼错、环境变量缺失问题比在生产上试错成本低得多。再进一步可以配合azkaban.properties里的executor.max.log.size和 log4j 滚动策略把每次执行的日志按execid归档写个小脚本定期把executions/下的日志同步到对象存储做执行审计。solo-server 的executions/目录结构是project/flow/execid/按这个层级遍历就能批量捞日志# 归档最近 7 天的执行日志按项目名分目录 find /opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT/executions -type d -name [0-9]* -mtime -7 | while read d; do proj$(echo $d | awk -F/ {print $(NF-3)}) execid$(basename $d) mkdir -p /backup/azkaban-logs/$proj cp -r $d /backup/azkaban-logs/$proj/$execid done这段脚本按目录层级反推项目名和执行 id把日志复制到备份目录。-mtime -7控制只归档最近 7 天避免全量拷贝拖慢磁盘。生产上我会把它挂到 crontab 每天凌晨跑一次配合对象存储的生命周期策略做冷备。还有一个验证技巧改完azkaban.properties后别急着重启先用bin/shutdown-solo.sh优雅停确认进程退出再启。solo-server 的 H2 在异常退出时可能留下锁文件下次启动报 Database may be already in use这时候删掉h2.path同目录下的.lock.db文件再启就行。这个坑我踩过一次排查了半小时才反应过来是锁文件没释放。从那以后我每次动配置都强制走一遍停服务 → 改配置 → 确认无残留进程和锁文件 → 启动 → 跑一个最小 flow 验证的流程再也没出现过重启后数据对不上的情况。希望帮到你。本文还有配套的精品资源点击获取