一、先说人话
这一关的东西,平台上的名字叫 DolphinScheduler,日常都喊"海豚"。它不搬数据、不写 SQL、不算指标。它只干一件事:照时刻表把该干的活按顺序叫起来。
为什么非得有这么一间值班室?一个项目里就有 756 个任务摊在 10 台机器上;SUPP 那个场景 44 条工作流,42 条每天 08:00 一起开跑。谁等谁、几点开、失败重试几次、昨天漏了怎么补——这四件事人脑记不住,一张总表能记住。
而且这张表分三套厂区:生产(真正对外供数)、UAT(先试)、开发(本地验证)。三套厂区不是三个标签,是三套彼此不通的水电——资源、SQL 权限、发布权限全不一样。所以"开发厂区跑通了"这句话什么都不能证明:那儿连调度都是关着的。
先把这一关的词对一遍号,后面就不来回翻译了。
- 值班室
DolphinScheduler(海豚)——到点叫人、按顺序放行、失败重试、漏了补数- 时刻表
- 调度周期(cron)+ 上线 / 下线——几点开跑、今天跑不跑
- 格子与箭头
- 工作流定义:节点 + 依赖(DAG)——谁先谁后
- 工位
- Worker 分组
datax/seatunnel——这活排在哪台机器上干 - 工牌
t_ds_user/t_ds_session——你以谁的身份动手- 总钥匙
- 临时管理员(
apply-admin,1 小时)——能不能改真东西
下面这张图把这一关的四件东西摆在一起:左边一张时刻表,右边一条依赖链,底下那把钥匙。
左边那三格是"什么时候",右边那条链是"先干什么后干什么",中间用箭头咬死;底下那颗钥匙管的是"你凭什么能动手"。四件东西缺一件,值班室就成了墙上的一张废纸:只有时刻表没有依赖,下游会在上游还没出数的时候照样开跑;只有依赖没有钥匙,谁都能上去改两笔。
二、拆开看:每个零件是什么
2.1 三套厂区:同一套代码,三种待遇
像什么:同一个班组的活,在自家车间怎么试都行,进了客户现场连插头都不许自己换。厂区之间不是靠自觉,是靠制度把权限焊死。
其实是什么:海豚的环境分生产、UAT、开发三类,环境设置由系统管理员完成,要改就得联系平台组管理员——不是自己在页面上点一下能改的。三套厂区的差别不只是"数据不一样":用途、调度、能连哪些资源、能存什么 SQL 和同步作业,每一处都不一样。
| 差在哪 | 生产环境 | UAT 环境 | 开发环境 |
|---|---|---|---|
| 用途 | 正式上线、长期周期运行 | 集成验证测试、短期内周期运行 | 本地开发验证 |
| 调度开关 | 开启 | 开启 | 不开启 |
| 资源 LINK | 所有 LINK | ETL 全部 LINK;同步只授 UAT 写权限的 LINK | 只授开发环境 LINK(无生产写权限);不授权同步 LINK |
| 发布限制 | 管理员 / 临时管理员 | 同左 | 无限制 |
- 生产 · SQL 保存
- 禁
CREATE/DROP;禁读写_sit、_uat、temp_db、default这些测试环境表;import_db只读 - UAT · SQL 保存
- 禁
CREATE/DROP;只能写测试环境 Schema:_sit、_uat、temp_db、import_db、default - 开发 · SQL 保存
- 无限制
- 生产 · 同步保存
- 禁读后缀为
_sit、_uat、temp_db、import_db、default的库内表;写入不限制 - UAT · 同步保存
- 读取不限制;只能往后缀
_sit、_uat的 schema 同步数据 - 开发 · 同步保存
- —(原文未列限制,只说了不授权同步 LINK)
- 真名
生产环境/UAT 环境/开发环境(《项目多环境介绍》)- 谁改
- 环境设置由系统管理员完成
看完这张表,"开发环境里先跑一遍"这句话的分量就清楚了:那儿调度是关的,只能手动点。手点能过,只说明脚本没错;明天早上七点会不会自己起来、起来之后连的是哪个库,开发厂区一个字都答不了。
_sit、_uat 里写。所以一个同步任务在 UAT 里配得再顺,搬到生产也得把那两个后缀改回正式库——不改,保存这一关就过不去;真过去了,那是把测试数据往生产灌。2.2 五个厂区编号:认数字,不认名字
像什么:厂门口的门牌,写得再漂亮也没用,真正认的是那串编号。走进隔壁厂区,你干的活全算别人的。
其实是什么:海豚里每个项目都是一个编码,一串纯数字。下面这五个是这套体系里真在用的,抄错一位,改的就是别人的厂区。
- 生产 BI_PRD
148405435832576- 测试 BI_SIT
149223761565792- ETL 生产
136016656440288(ETL_日常离线计算)- ETL SIT
12302943659968- SUPP
12923899913280
这五个里,前两个是主厂区,中间两个是专门跑 ETL 的车间,最后一个是某个业务场景自己的院子(SUPP 那 44 条工作流就住在这儿)。
BI_SIT,表名里也带 _sit 后缀。别拿"UAT"三个字母去猜项目,认编码。对不上的时候,以项目的数字编码和表名后缀为准。2.3 五种工位:干不同的活,站不同的台
像什么:厂区里就五个工种。有的工位什么也不生产,只站在门口当个路标;有的工位必须接特定的机床;有的工位是把别人的活整段搬过来复用。
其实是什么:《数据实施规范》把节点类型定死了,一个工作流就是这五种工位拼起来的。
| 工位 | 干什么 | 为什么是它 / 怎么配 |
|---|---|---|
SHELL |
开始节点、结束节点、纯中转 | 它不干活,只要有个节点把箭头连起来;配置全默认,脚本 echo 1 |
SQL |
业务 SQL 本体 | 湖里所有 Spark SQL 只有一个入口,别的类型连不进去;数据源类型选 KYUUBI |
SUB_PROCESS |
子流程、模板 | 一段活被好几个工作流复用,改一处全体生效;参数必须评审,不塞私人参数或项目参数 |
DATAX |
入湖:源库 → 数据湖 Hudi | 入湖是"从别人的库里抽",源端压力小;Worker 分组 datax、环境名称 datax |
SEATUNNEL |
出湖入仓:Hudi → Doris(也支持别的源和目的) | 出湖要分布式算,吃的是集群算力;Worker 分组 seatunnel、环境名称 seatunnel |
- 真名
SHELL/SQL/SUB_PROCESS/DATAX/SEATUNNEL- 出处
- 《数据实施规范》3.3 任务定义规范
这张表里藏着两个低级但很贵的错。第一个是把中转节点配成 SQL 节点:它什么也不查,却要占一个 Kyuubi 会话,白排队。第二个是 SUB_PROCESS 里写死参数:模板是给全厂复用的,你在模板里塞一个只对自己有意义的参数,下一个用模板的人就被你的参数带跑。
DATAX 配 datax,SEATUNNEL 配 seatunnel。分组挑错不会报错,只会一直排队——活没丢,就是不上工。2.4 参数放哪:全厂通用的挂墙上,只给子流程的才写在工作流上
像什么:厂区大门口挂一块牌子,写着今天几号、走哪条线——所有人抬头都看得见。没人会把"今天几号"抄在自己工位的抽屉里。
其实是什么:参数分两层。跑哪一天(biz_date)、连哪个库这类全厂都要用的,放项目级参数;只有要往子流程里传值的时候,才在工作流上定义参数。
- 真名
- 项目级参数 / 工作流参数
- 规矩一
- 原则上所有 SQL 运行依赖的参数,都得在项目级参数里定义
- 规矩二
- 相同含义的参数不允许重复定义
- 规矩三
- 工作流参数原则上只在向
SUB_PROCESS传数据时才定义
搞错了会怎样:同一个东西起两个名字,改的时候改了一个、漏了另一个。生产跑起来连的还是旧库,SQL 一句没报错,数全落在错的表里——这种错最难查,因为两处都"看起来对"。
2.5 发布一次,到底动了什么
这一段是这一关最硬的地方。下面不是笼统的流程,是本机脚本 add_seatunnel.py 真跑过的顺序:给一个工作流加两个 SeaTunnel 节点,从验身份一直到最后回读核对。
- 先验工牌。第一步
ds_identity.resolve_ds_session(项目编码),去t_ds_user、t_ds_session两张表里查这个人现在有没有有效会话,默认账号liuliyin,拿到之后先断言用户名就是它。查不到不会回落成项目 owner——值班室不能因为刷不出你的卡,就自动借你项目经理的卡。 - 整份拆下来。
GET /projects/{项目编码}/process-definition/{工作流},一次取回三样:processDefinition(工作流本体:名字、版本、超时、执行方式)、taskDefinitionList(所有节点)、processTaskRelationList(所有连线)。这个接口不接"只补一个节点",它要的是整份。 - 领新号。
gen-task-codes申请新节点的编号(genNum填这次要几个);脚本还回头查一遍:数量对得上、号码没有重复。 - 整份交上去。
PUT同一个地址,body 里带taskDefinitionJson(节点)、taskRelationJson(DAG 连线)、locations(每个节点的 x/y 坐标)、globalParams、timeout、executionType(SERIAL_WAIT)、tenantCode。少连线,节点全成孤岛;少坐标,所有节点叠成一坨。返回体里code必须等于 0——HTTP 200 不算过。 - 当场念回执。再
GET一次,对版本号、节点数、依赖数,逐个节点打taskType和源表 / 目标表核对。不 GET 回读,就等于没验过——PUT 返回成功只说明服务器收下了,不说明它收的是你写的那一份。 - 发布,再启动。
release上线、start起跑。动这一步之前要先apply-admin申请 1 小时临时管理员,事后用cur-perm读回:确认权限拿到了,也确认它会自己过期。
code=0,直接去点发布和启动。结果节点数少一个(新加的节点压根没进定义)、或者连线上少一条(新节点挂在那儿没人叫它),工作流照样天天"跑成功",只是有一段活从来没干过。最阴的一种:定义里还留着 _sit 的表名——正式定义引用了 SIT 运行对象,跑出来的是测试数据。2.6 状态怎么看:五个词,一句人话
像什么:值班室墙上的灯。绿灯只说明"这个工位没出事",不说明"这个工位今天做的活是对的"。
其实是什么:海豚给每个任务实例一个状态。翻来覆去就五个词,认全了,一半的误会就没了。
| 状态 | 一句人话 |
|---|---|
RUNNING_EXECUTION | 正在转,还没出结果——先看它跑了多久,别催 |
SUCCESS | 跑完了、脚本没报错——只代表"没出错",不代表"数对" |
FAILED | 报错停了——资源不够、上游失败、脚本本身报错 |
KILLED | 被人或被平台掐断——超时、手动停、资源被回收 |
WAITING | 在等上游,自己不动——上游还没成功,它就在门口排队 |
近 8 天的实测:45,571 个成功、296 个失败、529 个被杀,失败率 0.65%。失败根因集中在 SeaTunnel 心跳超时(OperationTimeoutException / operation-heartbeat-timeout),靠下游 retry_to_doris 补跑之后全部成功。所以值班看板上"红了一下又绿了",多半是这条链自己在补。
SUCCESS 是"这段脚本正常退出了",不是"这段脚本算对了"。上游少给一天数据、增量时间字段没更新、口径改过但没重跑——这三种情况下任务全是绿的,数全是错的。所以验数是另一道工序,不能拿状态灯代替。三、串起来:一次完整的流程
把零件按一天的顺序排一遍,就是值班室真实的一天。前面三步是"上工之前",后面五步是"上工之后"。
- 先在开发厂区试。那儿调度是关的,只能手点。手点跑通只说明代码没错,不说明它会自己起来。
- 进 SIT 冒烟。交付测试的依据写得很死:SIT 环境的增量任务冒烟测试通过,才算可交付测试。
- 进 UAT 联调。UAT 只能写测试 schema、只能同步进
_sit/_uat;相关增量任务测试通过,才谈得上生产发布。 - 07:00 开泵。
DATAX节点(Worker 分组和环境名都是datax)把源库当天的新数据搬进 Hudi 湖。 - 08:00 上工。
SQL节点(数据源类型KYUUBI)沿依赖链一条条跑;SUPP 那 42 条工作流也在 08:00 集中开跑,所以这个点最容易看到WAITING。 - 09:00 出数。
SEATUNNEL节点(Worker 分组和环境名都是seatunnel)把湖里的结果同步进 Doris,页面和报表读的是 Doris,不读湖。 - 白天出岔子。先看状态:
WAITING是在等上游,RUNNING_EXECUTION是在转,FAILED是报错,KILLED是被掐。SUCCESS只说明脚本没报错,别再往下替它保证。 - 隔天补漏。昨天哪一格没跑成,补哪一格。别把整条链从头重跑一遍:结果表是整表覆盖写的,重跑会把下游已经算好的那份再盖一次。
这八步里,真正需要人盯的只有第 7 步和第 8 步。前面六步是制度在跑:厂区隔开、工位定死、参数收口、发布回读。制度跑得顺,值班室就安静;值班室天天响,八成是前面某一步被人抄了近路。
四、搞错了会怎样
值班室出的事,几乎都不是"任务挂了",而是"任务没挂,数不对"。挂了你至少知道要修;不挂,你要等业务方打电话来问"这个月怎么和上个月一模一样"。
像什么:值班表上写"等老王交班再开泵"。老王十月三号就调走了,可本子上他最后一次签字还是"正常"——于是没人再问一句"老王今天来了吗",泵每天照开。
10.160.10.26 一台接了 218 个、排队 3.8 分钟,另外 9 台基本空闲。这不是报错,是慢慢来:任务到点没动,看着像挂了,其实在等窗口。所以"卡住"的第一反应不该是改 SQL。先看状态是 WAITING 还是 RUNNING_EXECUTION,再看是不是排在这台忙机器上,最后才轮到怀疑脚本。顺序反了,SQL 改十遍也没用——活根本没开始跑。
五、一句话记住
值班室能担保的是四件事:到点叫人、按顺序放行、挂了重试、漏了补上。它担保不了的是第五件:被叫起来的那个人,今天搬的是不是今天的数据。那件事归验数——入湖对账、湖仓一致性检查、表级监控,一条一条对出来的。
所以看这一关的正确姿势是:状态灯管"有没有跑",验数管"对不对"。两本账分开记,值班室才不会变成一间只会报"一切正常"的屋子。