
前阵子我换了 Flink 2.2.x 跑本地实验解压完安装包之后习惯性去 bin 目录下找 start-cluster.bat结果把整个目录翻了个底朝天只剩下 start-cluster.sh、sql-client.sh、sql-gateway.sh 这些 Linux 脚本一个 .bat 都没有。Windows 下玩 Flink 的朋友应该都有同感以前照着教程双击 start-cluster.bat 就能把集群拉起来到了新版直接失效网上还有很多资料停在旧路径跟着敲只会得到“系统找不到指定的文件”。这个事其实不算 bug而是官方在新版本里把 Windows 启动脚本整个拿掉了。但它对 Windows 用户的冲击是实打实的本地开发、写 Flink SQL 实验、用 CDC 同步数据第一步就卡住后面全没法玩。这篇博文我会把现象、原因、三种可行解法和后续高频报错一次性讲清楚覆盖从纯小白到有点基础想搞清楚原理的同学让你拿到新版 Flink 之后不用再为启动文件发愁。1. 为什么新版 Flink 不再提供 bat 启动文件1.1 从旧版到新版启动脚本到底经历了什么在 Flink 1.x 比较流行的阶段发行包的 bin 目录里通常有 start-cluster.bat、stop-cluster.bat、sql-client.bat、flink.bat 这几个 Windows 批处理文件。当时很多教程在 Windows 上跑 Flink都是从“双击 start-cluster.bat”开始的本地起一个 JobManager 和 TaskManager然后访问 8081 端口看 Web UI整个链路很简单。但越往后官方对 Windows 批处理脚本的维护意愿越来越低。我观察过的发行包变化是早期 bat 文件还偶尔更新后来慢慢变成“只保证 Linux 脚本可用bat 能跑就行”再往后干脆就从新版本发行包里移除了。到了 Flink 2.x 这类新版本bin 目录里你已经找不到任何 .bat全是 .sh这是非常明显的变化。官方这么做的原因并不难理解。Flink 本质是跑在 JVM 上的分布式计算引擎跨平台能力来自 Java 本身但启动脚本是另一回事Windows 批处理要额外处理路径转换、命令兼容、环境变量差异维护成本高又缺乏自动化测试覆盖。加上主流部署场景从物理机转向容器、K8sLinux 才是绝对主战场Windows 在官方视角里更多是“开发者的笔记本环境”优先级自然被一砍再砍。1.2 没有 bat 文件Windows 用户到底缺了什么很多人第一反应是“没有 bat 就不能跑 Flink 了”其实不对。Flink 的核心是基于 Java 的只要 JVM 环境正确Windows 完全可以运行。真正缺的是一个“一键双击就能启动”的入口。没有了 start-cluster.bat意味着你要自己处理 classpath、配置目录、日志路径、进程管理这些事。对刚接触 Flink 的新手来说这个门槛立刻就被抬高了。对下面的几类人影响尤其明显想用 Flink SQL 做本地数据分析、练习窗口和 watermark 语法的同学在 Windows 台式机上做 Flink CDC 同步实验的开发者公司规定开发环境必须是 Windows但又想快速验证 Flink 任务的工程师看旧教程学习结果被“找不到批处理文件”卡住的学生。另外还有一个连带问题旧版里 flink.bat 承担了提交作业、查看任务列表等功能现在这个入口也没了。所以严格来说缺的不是一个文件而是一整套面向 Windows 用户的操作入口。1.3 整体解法思路让官方 shell 脚本在 Windows 上“复活”面对没有 bat 的状况解决办法其实可以分成三条路线给 Windows 装一个 bash 环境直接运行官方 .sh 脚本。最典型的是 Git Bash或者完整的 WSL。不装任何模拟环境用 CMD 或 PowerShell 手工调用 java 命令把 JobManager 和 TaskManager 拉起来。完全抛弃本地脚本用 Docker 容器跑 Flink让镜像里的 Linux 环境来接管启动动作。这三条路线各有适用场景本地做实验、只想尽快把 Flink SQL 跑起来我用得最多的是 Git Bash如果追求“和服务器一致”的体验WSL 或者 Docker 更合适纯手工 CMD 其实最不推荐但它能帮你理解 Flink 启动的底层逻辑。后面几章我会按优先级逐个展开。2. 首选方案用 Git Bash 把官方 .sh 脚本重新“捡起来”2.1 为什么我推荐 Git Bash 而不是直接上 WSLGit Bash 是随 Git for Windows 一起安装的轻量模拟环境启动快、占用小自带 bash、sed、awk、cygpath 等工具Flink 官方 .sh 脚本里依赖的 dirname、readlink、变量处理这些能力它基本都能满足。相比之下WSL 是一个完整的 Linux 子系统功能更强大但也更重。如果你只是为了启动 Flink 集群装一个 WSL 再配发行版有点杀鸡用牛刀。而且 WSL 访问 Windows 盘符下的文件时路径挂载、文件权限、换行符都可能踩坑对新手不友好。Git Bash 还有一个隐藏优势它和 Git 绑定很多开发者电脑上本来就装着。就算没装安装过程也就是一路 Next不需要额外配虚拟化不需要重启系统学习成本非常低。所以我个人给 Windows 本地开发场景的默认建议就是用 Git Bash 跑 .sh。2.2 启动 standalone 集群的完整流程我用 Git Bash 跑 Flink 新版本的流程基本是固定的按下面几步操作就能把集群拉起来安装 Git for Windows安装选项保持默认即可右键菜单会出现“Git Bash Here”。下载新版 Flink 二进制包解压到一个没有中文、没有空格的路径比如 D:\env\flink-2.2.1。这一步很重要路径里有空格或中文后面启动脚本很可能报奇怪错误。确认 JDK 环境。新版 Flink 对 JDK 版本有要求一般 JDK 8 或 11 都算稳妥具体以官方文档为准。配置好 JAVA_HOME并在 CMD 里确认 java -version 能正常输出。进入 Flink 根目录在空白处右键选择“Git Bash Here”然后执行./bin/start-cluster.sh看到 “Starting cluster.” 输出后打开浏览器访问 http://localhost:8081 能看到 Flink Web UI 就说明 JobManager 起来了。用完以后在同一个 Git Bash 窗口执行./bin/stop-cluster.sh如果你执行 start-cluster.sh 后没有任何反应或者访问不到 8081第一步不是怀疑脚本坏了而是去看 log 目录下的日志文件。Flink 会把 JobManager、TaskManager 的启动日志都写到 log 目录真正的报错信息都在里面。2.3 用同样方式启动 SQL Client 和 SQL Gateway很多人在 Windows 上玩 Flink 不只是为了看 Web UI更关心 Flink SQL 能不能跑。新版发行包里的 SQL Client 入口同样只剩 .sh启动方式./bin/sql-client.sh embedded这样会进入一个交互式 SQL 环境可以直接执行 CREATE TABLE、SELECT 等语句。如果你想跑一个写好的 SQL 文件可以用./bin/sql-client.sh -f /path/to/query.sql如果想把 SQL 能力暴露成 REST API方便其他程序调用需要启动 SQL Gateway。新版 Flink 有独立的 sql-gateway.sh./bin/sql-gateway.sh start -Dsql-gateway.endpoint.rest.hostlocalhost启动后用 curl 或者浏览器访问对应的 HTTP 端口可以看到 SQL Gateway 的 REST 接口。不同小版本可能默认端口不同启动日志里会打印实际监听地址以日志为准。这里要注意一个常见误区SQL Client 本身只是一个命令行客户端真正执行 SQL 还是要靠 Flink 集群。所以你必须先把 start-cluster.sh 启动起来再开第二个 Git Bash 窗口去跑 sql-client.sh否则连接不到集群。2.4 做一个一键启动辅助“bat”文件虽然 Flink 官方不给 bat 了但我们可以自己写一个简单的批处理间接调用 Git Bash 里的 bash.exe实现“双击就启动集群”的效果。下面这个脚本的思路是先在 CMD 里把工作目录切到 Flink 根目录然后用 Git Bash 执行官方脚本。这么做可以避开 Windows 路径传给 bash 时常见的盘符转换问题。echo off chcp 65001 nul set FLINK_HOMED:\env\flink-2.2.1 cd /d %FLINK_HOME% echo Starting Flink cluster... start Flink JobManager %ProgramFiles%\Git\bin\bash.exe -lc ./bin/start-cluster.sh timeout /t 3 nul start http://localhost:8081 echo Flink cluster has been started. Press any key to stop. pause nul echo Stopping Flink cluster... %ProgramFiles%\Git\bin\bash.exe -lc ./bin/stop-cluster.sh pause脚本里的 chcp 65001 是为了让 CMD 窗口显示 UTF-8 输出不乱码。start 命令会让 Git Bash 在新窗口运行所以原来的 CMD 窗口还能继续等用户按任意键停止集群算是一个很简单的 start/stop 一体工具。如果你把 Flink 装到了其他路径记得同步修改 FLINK_HOME。这个脚本和官方 bat 的核心差异只是多了一层对 Git Bash 的调用但已经足够解决“没有启动文件”的问题了。3. 不想装 Git Bash用 CMD/PowerShell 手工拉起来3.1 手工启动的底层逻辑如果你因为某些原因不想装 Git Bash或者你只是想知道 Flink 的启动脚本到底做了什么那这一章能帮上忙。start-cluster.sh 表面上一行命令搞定集群实际操作可以拆成两部分启动一个 JobManager 进程再启动一个或多个 TaskManager 进程。JobManager 在 standalone 模式下的入口类是 org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypointTaskManager 的入口类是 org.apache.flink.runtime.taskexecutor.TaskManagerRunner。知道了这两个类名理论上你就可以用 java -cp 手动拉起整个集群。难点在于 classpath 要包含 lib 目录下的所有依赖 jar还要设置日志、配置目录等系统参数命令会非常长。3.2 手工启动 JobManager 与 TaskManager 的命令骨架如果你想体验一把手工启动可以用 PowerShell 写一个简单版本。下面是一个示意性的骨架帮助你理解过程实际使用时要根据你的目录和版本调整$env:FLINK_HOME D:\env\flink-2.2.1 $env:FLINK_CONF_DIR $env:FLINK_HOME\conf $env:FLINK_LIB_DIR $env:FLINK_HOME\lib $env:FLINK_PLUGINS_DIR $env:FLINK_HOME\plugins $jobManagerClass org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypoint $taskManagerClass org.apache.flink.runtime.taskexecutor.TaskManagerRunner Start-Process java -ArgumentList ( -cp, $env:FLINK_HOME\lib\*, $jobManagerClass, -Dlog.file$env:FLINK_HOME\log\jobmanager.log ) Start-Process java -ArgumentList ( -cp, $env:FLINK_HOME\lib\*, $taskManagerClass, -Dlog.file$env:FLINK_HOME\log\taskmanager.log )说实话这个方案在日常使用中并不舒服。日志路径、配置项、内存参数稍微写错一点进程起不来或起了一半失败排查起来比用官方脚本麻烦很多。所以我更建议把这一章当成“理解原理”的辅助材料而不是长期使用的启动方式。3.3 批处理和 PowerShell 里最容易踩的坑如果你就是要走手工启动这条路下面几个坑提前帮你排掉JDK 版本问题。Flink 2.x 对 JDK 版本有最低要求如果本机装的是过老的 JDK会直接报 UnsupportedClassVersionError。先确认 java -version 输出。路径里有空格。手工写 classpath 时路径必须加引号否则 JVM 会认为空格后面是新增参数直接启动失败。CMD 通配符和 bash 不同。CMD 里 -cp D:\lib* 的引号位置很敏感建议直接用 PowerShell 的数组参数方式避免被 CMD 解析器拆坏。环境变量不生效。新装的 JAVA_HOME 或 FLINK_HOME 不会立刻在当前窗口生效要重新打开一个 CMD 或 PowerShell 窗口。日志参数缺失。手工启动时如果不指定 -Dlog.file日志可能打到控制台或者根本找不到出了问题没法定位。3.4 内存参数为什么不能随便乱调手工启动时很多人会顺手加 -Xmx/-Xms但这里有个隐藏问题Flink 从 1.11 开始引入了一套内存模型jobmanager.memory.process.size 和 taskmanager.memory.process.size 才是真正决定老年代、堆内存、堆外内存的参数而且会覆盖 JVM 层面的部分设置。如果你只是手工启动没改 flink-conf.yaml那么你就算在命令行里写了 -Xmx4g也可能发现实际堆内存不是 4g或者进程因为配置不一致直接失败。正确的做法是先修改 conf/flink-conf.yaml 里的内存配置再启动进程。这也是为什么我不太推荐纯手工启动的原因之一可配置项太多官方脚本已经把配置和命令组织好了省略这些细节埋下的坑反而更多。4. 想省事就上容器WSL 与 Docker4.1 WSL 下直接复用 Linux 脚本如果你用的 Windows 10/11 开了 WSL那情况会简单很多。在 WSL 里Flink 脚本和你在 Linux 服务器上完全一致没有任何“Windows 没有 bat”的概念。操作上最常见的坑有两个。第一是文件权限从 Windows 下载解压的文件可能在 WSL 里没有可执行权限需要先chmod x bin/*.sh第二是换行符。如果你用 Windows 自带的记事本或某些编辑器改过脚本文件可能是 CRLF 换行bash 执行时会报$\r: command not found这种错误。解决办法是把换行符转成 LFsed -i s/\r$// bin/*.sh处理完这两步按照正常 Linux 方式执行 ./bin/start-cluster.sh 即可。WSL 的好处是环境干净和服务器行为一致适合需要长期稳定跑 Flink 实验的同学。4.2 Docker Compose 部署 Flink 和 Flink CDC如果你连脚本都不想碰直接用 Docker 是最省事的方式。官方 Flink 镜像本身就内置了完整的 Linux 环境启动动作全部在容器里完成Windows 本地只需要一个 Docker Desktop。下面是一个最精简的 Docker Compose 示例拉起一个 JobManager 和一个 TaskManagerservices: jobmanager: image: flink:2.2.1 ports: - 8081:8081 command: jobmanager environment: - | FLINK_PROPERTIES jobmanager.rpc.address: jobmanager taskmanager: image: flink:2.2.1 depends_on: - jobmanager command: taskmanager environment: - | FLINK_PROPERTIES jobmanager.rpc.address: jobmanager taskmanager.numberOfTaskSlots: 2在项目目录下执行 docker compose up -d然后访问 http://localhost:8081 就能看到集群界面。对于 Flink CDC 3.x 这类新组件Docker 部署优势更明显。你可以把 CDC 需要的 connector jar 挂载进容器或者直接使用 flink-cdc 相关的 compose 编排避免在 Windows 本地折腾 jar 依赖和启动文件匹配。版本匹配上要特别注意Flink 2.x 对应的 CDC 主版本和 Flink 1.x 不是一个系列用错版本会出现类找不到或者 Source 无法实例化的问题去看官方版本匹配表最稳妥。4.3 三种方式怎么选我把 Git Bash、纯手工命令、Docker/WSL 三种方式做了个对比方便你对号入座。方式核心原理优点缺点适用场景Git Bash 跑 .sh在 Windows 上模拟 bash 环境轻量、无需虚拟化、启动快可能出现少量路径和命令兼容问题本地快速实验、学习 Flink SQL纯 CMD/PowerShell 手工启动直接调用 java 入口类不依赖额外工具命令复杂、易出错、维护成本高理解启动原理、应急排障Docker / WSL在 Linux 环境运行官方脚本行为与服务器一致、干净可控占用资源多Docker 在 Windows 上依赖虚拟化长期开发、部署预演、CDC 全链路验证我个人的倾向是只想跑个 SQL 验证想法用 Git Bash想认真搞数据同步或者做项目直接上 Docker。5. 启动文件解决了后面这几个问题你大概率也会遇到5.1 SQL Client 报错找不到 jdbc factory当你终于把集群启动起来兴致勃勃在 SQL Client 里执行 CREATE TABLE 连接 MySQL结果弹出一句“Could not find any factory for identifier jdbc”大概率是因为 Flink 默认发行包并没有内置 JDBC connector。解决思路很简单把 flink-connector-jdbc 的 jar 包下载下来放到 Flink 根目录的 lib 文件夹中然后重启 SQL Client。注意版本要和 Flink 大版本匹配比如 Flink 2.x 对应连接器 3.x 系列具体版本号以 Maven Central 或官网连接器页为准。你也可以用 sql-client.sh 的 -C 参数临时指定 jar 路径但我实测下来直接把 jar 放进 lib 是最省心的方式省得每次启动都要带参数。5.2 连接 MySQL 时 Driver 冲突解决了 jdbc factory 问题你还可能遇到第二个报错ClassNotFoundException: com.mysql.cj.jdbc.Driver。这是因为 Flink 的 JDBC connector 只负责翻译 SQL 和建立连接框架真正和 MySQL 通信还需要 MySQL 驱动包。把 mysql-connector-j 8.x 的 jar 也放到 lib 目录问题一般就能解决。这里要注意不要同时放多个版本的 MySQL 驱动否则可能出现驱动加载错乱、连接行为诡异的故障。我在实际排障中见过一个例子lib 目录里既有 mysql-connector-java 5.x又有 8.x结果 Flink 随机使用错误的驱动报加密协议不支持的毛病折腾了整整一下午。5.3 8081 端口被占用新版 Flink 启动时如果发现 8081 被占用Web UI 会起不来但进程可能已经跑了看起来像“集群启动失败”。排查方法是在 CMD 里执行netstat -ano | findstr 8081看到 PID 之后打开任务管理器结束对应进程或者修改 conf/flink-conf.yaml 里的 rest.port 改成别的端口。这里还有一个隐藏坑如果你修改了 rest.port但没注意内部通信端口 jobmanager.rpc.port 和 taskmanager 的数据端口是否冲突TaskManager 可能注册不上。我遇到过只改了 HTTP 端口、忘了检查内部端口结果集群界面一直显示 0 个 TaskManager 的情况日志里全是连接超时。5.4 SQL 里 WATERMARK 和 CDC 版本不要踩雷很多人在新版 SQL Client 里用 WATERMARK 语法时会报错常见原因是把 WATERMARK 写在了 SELECT 外部或者使用了旧版的写法。新版 Flink 要求在 DDL 里直接定义 watermark 字段格式要严格符合语法多看官方文档的示例最靠谱。Flink CDC 那边也是类似情况。CDC 2.x 和 3.x 对应不同的 Flink 版本用错版本启动任务时会出现找不到 SourceFunction 或者 factory 的异常第一反应不要怀疑代码先去核对版本匹配表。我的习惯是用 Docker 部署 Flink CDC因为镜像内部把版本兼容问题处理得相对干净本地只要挂载好配置文件即可。5.5 新手启动排障自检清单下面这张表是我调试 Flink 启动问题时经常对照的速查表按症状查原因能省不少时间。症状可能原因快速定位执行 start-cluster.sh 无输出8081 无法访问Java 版本不对、JAVA_HOME 未配置java -version检查环境变量日志出现 ClassNotFoundException依赖 jar 缺失或版本不匹配查看具体是哪个类找对应 jar 放入 lib启动后 Web UI 有 JobManager但没有 TaskManager内部端口冲突、taskmanager 未注册看 TaskManager 日志、检查 conf/flink-conf.yamlSQL Client 找不到 jdbc factoryJDBC connector 未安装下载 flink-connector-jdbc 放入 lib中文目录或空格路径导致启动异常路径解析问题把 Flink 移到纯英文无空格路径WSL 下脚本报 $\r 相关错误换行符是 CRLFsed -i s/\r$// bin/*.sh最后再分享一个小技巧我每次在 Windows 上跑 Flink 实验都会先单独建一个干净的实验目录比如 D:\env\flink-2.2.1所有连接器 jar 都统一放到 lib 目录升级版本之前先看一眼官方兼容性说明再动手。这样即使新版没有 bat 启动文件我也能用 Git Bash 在几分钟内把集群和 SQL 环境全部拉起来。希望这套经验能让你少踩几次坑顺利把 Flink 在 Windows 上跑起来。