ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Azkaban solo-server 0.1.0-SNAPSHOT 部署与工作流调度实战

Azkaban solo-server 0.1.0-SNAPSHOT 部署与工作流调度实战 简介本资源为Azkaban单服务器版Solo Server0.1.0-SNAPSHOT的已编译tar.gz包面向需要快速搭建工作流调度环境的小型团队、个人开发者及大数据初学者。Azkaban由LinkedIn开源用于简化Hadoop作业调度提供Web界面创建、管理和监控工作流支持多项目、定时任务与依赖顺序执行。Solo Server将Web服务器、执行器和内嵌H2数据库集成于同一台机器解压后即可完成配置与启动省去编译环节适合本地测试与轻量级调度场景。压缩包约42.28MB上游未提供文件总数与类型明细但已包含运行所需的完整目录结构。目前已有256人学习下载。通过该资源读者可快速体验项目创建、作业定义、工作流依赖编排、定时调度及日志监控等核心功能并借助配置文件调整数据库连接、端口与日志路径为后续迁移至集群部署打下基础。需注意SNAPSHOT版本稳定性有限生产环境建议选用稳定版。1. azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz一个压缩包背后藏着什么如果你在搜索框里敲下azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz大概率不是想了解 Azkaban 的历史而是手里已经拿到了这个包或者正准备从源码构建它却不确定下一步该干什么。这个文件名拆开看azkaban是 LinkedIn 开源的批处理工作流调度器solo-server是它三种部署模式里最轻量的一种0.1.0-SNAPSHOT说明这是从源码主干构建出来的快照版本不是官方发布的稳定版。合在一起它就是一个单机可跑、自带 Web 界面和元数据库的 Azkaban 发行包。这篇文章要解决的问题很具体拿到这个 tar.gz 之后怎么在本地或测试环境把它跑起来怎么提交第一个工作流以及为什么很多人卡在启动脚本报错、数据库连接失败、Executor 起不来这几个地方。适合谁看适合需要快速验证 Azkaban 调度能力、不想一上来就折腾 distributed 模式多节点部署的开发和运维。单机模式虽然简单但它的坑并不比集群模式少只是坑的位置不一样。2. 解压之前先搞清楚 solo-server 的目录结构和依赖2.1 为什么 solo-server 是验证调度逻辑的最短路径Azkaban 有三种运行模式solo-server、two-server、distributed。solo-server 把 Web Server 和 Executor 塞进同一个 JVM 进程元数据默认写本地 H2 数据库不依赖 MySQL。这意味着你不需要先装数据库、不需要配多节点通信、不需要处理 Executor 和 Web Server 之间的认证。对于只想验证「我的工作流能不能按依赖跑起来」这个诉求solo-server 是最短路径。但短路径不等于零配置。solo-server 的 tar.gz 解压后目录结构大致是这样的bin/放启动和停止脚本conf/放azkaban.properties和日志配置lib/放所有依赖 jarplugins/放作业类型插件web/放 Web 资源。很多人解压完直接bin/start-solo.sh然后发现进程秒退原因通常出在conf/azkaban.properties里的路径没有改成绝对路径或者 Java 版本不匹配。我一般会先做三件事确认 JDK 版本、检查azkaban.properties里的web.resource.dir和user.manager.xml.file路径、看一眼bin/下脚本的JAVA_OPTS有没有硬编码的内存参数。这三步做完再启动成功率会高很多。2.2 解压与目录初始化的具体命令假设你已经把azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz放到了/opt/software/下下面是我常用的解压和初始化流程# 创建安装目录避免直接解压到当前目录造成文件散落 mkdir -p /opt/azkaban tar -zxvf /opt/software/azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz -C /opt/azkaban # 进入解压后的目录注意目录名可能带版本号 cd /opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT # 查看目录结构确认 conf 和 bin 存在 ls -lh解压完成后不要急着启动。先打开conf/azkaban.properties把里面所有相对路径改成绝对路径。比如web.resource.dirweb要改成web.resource.dir/opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT/webuser.manager.xml.fileconf/azkaban-users.xml要改成绝对路径。这个文件里还定义了database.typeh2和h2.path如果h2.path是相对路径启动时会在当前工作目录下创建h2数据库文件换一个目录启动就会找不到之前的元数据。提示如果你打算把这个 solo-server 当成长期测试环境用建议把h2.path指到一个固定目录比如/data/azkaban/h2避免每次重启都丢历史记录。2.3 Java 版本和内存参数怎么定Azkaban 0.1.0-SNAPSHOT 这个分支对 JDK 8 兼容最好JDK 11 及以上可能会遇到模块化相关的反射报错。如果你机器上有多个 JDK可以在bin/start-solo.sh里显式指定JAVA_HOME而不是依赖环境变量。内存方面solo-server 默认的JAVA_OPTS通常给得比较保守。如果你提交的工作流里有多个并行作业建议把-Xmx调到 1G 以上。修改位置在bin/start-solo.sh里找到JAVA_OPTS那一行追加-Xmx1024m -Xms512m。注意不要调得太大solo-server 是单进程Web 和 Executor 共享内存给太多反而容易触发 Full GC 导致界面卡顿。3. 启动 solo-server 并验证 Web 界面和 Executor 状态3.1 启动命令与日志观察点启动 solo-server 的命令很简单cd /opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT bin/start-solo.sh但这个脚本执行后不会把日志打到终端而是写到logs/目录下。你需要立刻查看logs/azkaban-solo-server.log观察几个关键点H2 数据库是否成功初始化、Jetty 是否在 8081 端口监听、Executor 是否注册成功。如果日志里出现java.lang.ClassNotFoundException或者Address already in use说明依赖缺失或端口冲突。我习惯用tail -f盯着日志同时用ss -lntp | grep 8081确认端口。如果 8081 没起来先检查azkaban.properties里的jetty.port是不是被改过再检查有没有其他进程占用了这个端口。3.2 用 curl 和浏览器双重确认服务可用日志显示启动成功后不要只依赖浏览器。先用 curl 打一下接口# 检查 Web 服务是否返回 200 curl -I http://localhost:8081 # 检查登录页面是否可访问 curl -s http://localhost:8081/index | head -20如果 curl 返回 200 但浏览器打不开通常是防火墙或者绑定地址的问题。azkaban.properties里有个jetty.host参数默认可能是0.0.0.0或者localhost。如果你在虚拟机里跑想从宿主机访问要确认绑定的是0.0.0.0而不是127.0.0.1。浏览器打开http://localhost:8081后默认账号密码通常是azkaban/azkaban这个在conf/azkaban-users.xml里定义。登录进去后重点看两个地方Projects 页面能不能创建项目Executor 页面能不能看到本机 Executor 处于 active 状态。如果 Executor 显示离线但日志里没有明显报错大概率是azkaban.properties里的executor.port和 Web Server 通信配置不一致。3.3 提交第一个工作流从 job 文件到 flow 执行Azkaban 的工作流定义用.job文件每个文件是一个作业多个作业通过dependencies字段串联。下面是一个最小可运行示例两个作业prepare.job和process.job后者依赖前者。先创建一个项目目录mkdir -p /tmp/azkaban-demo cd /tmp/azkaban-demo然后写两个 job 文件# prepare.job typecommand commandecho prepare data at $(date)# process.job typecommand commandecho process data at $(date) dependenciesprepare把这两个文件打成 zip 包zip -r demo.zip prepare.job process.job在 Azkaban Web 界面创建项目上传demo.zip然后点击执行。如果一切正常你会看到prepare先跑成功后process才开始。如果process一直处于preparing状态检查dependencies里写的名字是不是 job 文件名去掉.job后缀大小写是否一致。注意solo-server 的 Executor 是内嵌的作业执行日志会写到logs/目录下但 Web 界面也能看到。如果界面一直转圈去logs/azkaban-execserver.log里搜作业 ID通常能看到具体报错。4. 避坑solo-server 启动和运行中最容易翻车的五个地方4.1 启动脚本报 “Cannot find Java” 或版本不匹配现象执行bin/start-solo.sh后立刻退出终端输出Cannot find Java或者Unsupported major.minor version。原因脚本依赖JAVA_HOME环境变量或者系统默认 Java 版本不是 JDK 8。有些 Linux 发行版预装了 JRE 而不是 JDK编译和运行都会出问题。解决在bin/start-solo.sh开头显式设置JAVA_HOME比如export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64。然后用$JAVA_HOME/bin/java -version确认版本是 1.8。如果机器上只有 JDK 11要么装 JDK 8要么在启动参数里加--add-opens相关参数但后者不一定能完全解决所有反射问题。4.2 H2 数据库文件权限导致启动失败现象日志里出现Database may be already in use或者Permission denied指向h2.path下的.mv.db文件。原因solo-server 第一次启动时会在h2.path指定目录下创建数据库文件。如果这个目录不存在或者当前用户没有写权限H2 就起不来。另外如果之前启动过一次没有正常关闭H2 会留下锁文件再次启动会报 “already in use”。解决确保h2.path目录存在且当前用户可写比如mkdir -p /data/azkaban/h2 chmod 755 /data/azkaban/h2。如果报 already in use先确认没有残留的 Azkaban 进程然后删除h2.path下的.lock文件再启动。4.3 上传 zip 包后作业一直处于 preparing 状态现象工作流提交后第一个作业一直显示preparing不进入running也没有报错。原因Executor 没有正确加载作业类型插件或者plugins/目录下的 jobtype 插件缺少依赖。solo-server 默认只带command类型如果你用了hive、spark等类型需要额外放插件 jar 到plugins/下。解决先确认azkaban.properties里azkaban.jobtype.plugin.dir指向的目录存在且包含对应插件。如果只用command类型检查plugins/下有没有jobtype目录里面是否有common和command相关 jar。缺少的话从源码构建或者找对应版本的插件包补上。4.4 端口冲突导致 Web 界面打不开现象启动日志显示 Jetty 启动失败报BindException: Address already in use。原因8081 端口被其他进程占用比如之前启动的 Azkaban 没关干净或者其他 Web 服务用了这个端口。解决用ss -lntp | grep 8081找到占用进程如果是残留的 Azkaban用bin/shutdown-solo.sh关掉或者直接kill掉。如果确实需要换端口改azkaban.properties里的jetty.port同时确认 Executor 通信端口executor.port没有被占用。4.5 时区不一致导致调度时间错乱现象设置了定时调度的工作流实际执行时间和预期差了几个小时。原因solo-server 的 JVM 时区、H2 数据库时区、以及 Web 界面显示的时区可能不一致。默认情况下Azkaban 用 JVM 默认时区如果服务器是 UTC 而你在东八区调度时间就会差 8 小时。解决在bin/start-solo.sh的JAVA_OPTS里加-Duser.timezoneAsia/Shanghai确保 JVM 时区正确。同时检查azkaban.properties里有没有azkaban.server.timezone相关配置有的话一并改成Asia/Shanghai。改完重启再提交一个定时工作流验证。5. 进阶把 solo-server 塞进 Docker 并做持久化5.1 为什么 solo-server 也值得容器化虽然 solo-server 是单机模式但用 Docker 跑有两个实际好处一是环境隔离不会污染宿主机上的 Java 和数据库二是方便迁移把镜像和 H2 数据目录挂载出来换一台机器直接起。热搜词里出现docker安装azkaban说明很多人已经在往这个方向走。但要注意solo-server 的官方镜像不一定存在自己写 Dockerfile 更可控。5.2 一个可复现的 Dockerfile 和启动命令下面这个 Dockerfile 基于openjdk:8-jre-slim把 tar.gz 解压到镜像里并暴露 8081 端口FROM openjdk:8-jre-slim # 安装必要工具zip 用于打包工作流curl 用于健康检查 RUN apt-get update apt-get install -y zip curl rm -rf /var/lib/apt/lists/* # 把 tar.gz 复制进镜像并解压 COPY azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz /opt/ RUN mkdir -p /opt/azkaban \ tar -zxvf /opt/azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz -C /opt/azkaban \ rm -f /opt/azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz # 设置工作目录 WORKDIR /opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT # 把 H2 数据目录和日志目录挂载出来方便持久化 VOLUME [/opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT/h2, /opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT/logs] EXPOSE 8081 # 启动 solo-server CMD [bin/start-solo.sh]构建和运行命令# 构建镜像 docker build -t azkaban-solo:0.1.0 . # 运行容器把 H2 数据和日志挂到宿主机 docker run -d --name azkaban-solo \ -p 8081:8081 \ -v /data/azkaban/h2:/opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT/h2 \ -v /data/azkaban/logs:/opt/azkaban/azkaban-solo-server-0.1.0-SNAPSHOT/logs \ azkaban-solo:0.1.0这里的关键参数是-v挂载。H2 数据库文件如果留在容器里容器一删数据就没了。把h2目录挂出来重建容器后历史工作流和执行记录还在。日志目录挂出来方便在宿主机上直接tail -f不用每次都docker exec进去。5.3 容器化之后的验证清单容器起来后按这个顺序验证检查项命令预期结果容器状态docker ps状态为 Up端口映射 8081Web 服务curl -I http://localhost:8081返回 HTTP/1.1 200登录页面curl -s http://localhost:8081/index包含登录表单日志无异常tail -50 /data/azkaban/logs/azkaban-solo-server.log无 ClassNotFound 或 BindExceptionH2 文件生成ls -lh /data/azkaban/h2有.mv.db文件如果 Web 服务返回 200 但登录后创建项目报错去日志里搜h2关键字通常是挂载目录权限问题。容器内进程以 root 跑的话宿主机目录权限要放开或者用--user指定 UID。5.4 我踩过的一个容器时区坑有一次在 Docker 里跑 solo-server定时任务总是比预期晚 8 小时。查了半天发现基础镜像openjdk:8-jre-slim默认时区是 UTC而我在azkaban.properties里没配时区。后来在 Dockerfile 里加了一行ENV TZAsia/Shanghai同时在JAVA_OPTS里加-Duser.timezoneAsia/Shanghai问题才解决。这个坑在物理机上不一定遇到但容器里非常常见因为基础镜像为了通用性通常不设本地时区。提示如果你用 docker-compose 编排时区配置可以写在environment里但 JVM 参数还是要在启动脚本里改两者缺一不可。5.5 从 solo-server 迁移到 two-server 的时机判断solo-server 跑通之后什么时候该换我的判断标准是当你需要多个 Executor 并行跑作业或者 Web Server 重启时不想中断正在执行的作业就该考虑 two-server 或 distributed 了。solo-server 的 Web 和 Executor 在同一个进程里重启 Web 必然杀掉 Executor正在跑的作业会失败。如果你只是做功能验证和轻量调度solo-server 完全够用没必要为了「看起来更生产」而提前上集群。我自己在测试环境用 solo-server 跑了半年多每天几十个作业H2 数据库也没出过性能问题。真正让我迁移的是有一次需要同时跑 20 个并行作业单进程内存扛不住才拆成了 two-server。所以别被「单机」两个字吓到先跑起来遇到瓶颈再换这是最省时间的路径。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进