Flink集群安装部署实战:Standalone模式与ZooKeeper高可用配置
这个系列写到第6篇终于要聊集群安装部署了。前几篇我们把Flink的架构、组件分工、状态与检查点机制、流处理API这些内容都过了一遍但说句实在话如果只是在单机上跑跑Demo很多概念是体会不到实际价值的。只有当你真正把多台机器组起来跑集群才会明白为什么Flink要有JobManager和TaskManager之分、为什么需要配置高可用、为什么一个看似合理的配置在真实负载下会突然崩掉。这篇文章的核心是一件事从零安装部署一套Flink集群。默认环境是Linux物理机或虚拟机部署模式选Standalone独立模式并在其基础上扩展ZooKeeper高可用。适合刚学完Flink基础、准备进入分布式环境练手的同学也适合团队内部需要快速搭建一套测试集群的工程师参考。整个过程按实际操作顺序写包括配置项的取舍、启动验证步骤以及我踩过的坑尽量做到每一步都有据可查、可以复现。1. 部署方案选型先想清楚再动手1.1 Flink的三种部署模式到底怎么选Flink的部署模式说白了就解决一个问题TaskManager这些计算进程由谁来启动、由谁来分配资源、由谁来回收。按这个维度主流方案就三种Standalone、YARN、Kubernetes。Standalone模式不依赖任何外部资源管理系统Flink自己启动并管理JobManager和TaskManager进程。它的优点是架构简单、部署路径最短任何一台装了JDK的Linux机器都能跑缺点是资源弹性差TaskManager的启停都要人工干预机器空闲时也不会自动缩容。YARN模式把Flink的资源管理交给Hadoop YARN提交任务时YARN动态分配一个容器给FlinkJobManager和TaskManager都跑在YARN容器里。这个模式的好处是复用已有大数据体系资源按需申请队列和配额都现成代价是的前提是你得先有一套Hadoop集群部署和排查链路变长。Kubernetes模式则是把Flink容器化用K8s来调度Pod适合云原生基础设施比较成熟的团队。它的优点是资源隔离好、弹性伸缩能力强、环境一致性高缺点是学习成本高Pod崩溃日志、网络模型、存储卷这些概念不熟悉容器的话会相当痛苦。三种模式的差异整理成表格更直观维度StandaloneYARNKubernetes资源管理Flink自管交给YARN交给K8s部署复杂度低中高资源弹性弱强强学习成本低中高适用场景测试、小规模作业已有Hadoop体系容器化成熟团队1.2 为什么学习阶段选Standalone如果说后面要去生产环境用YARN或K8s那学习阶段从Standalone切入是不是白费功夫我个人经验是不白费。因为Flink的核心配置项比如JobManager地址、内存参数、Slot数量、状态后端、检查点路径、高可用配置在不同模式下是同一套逻辑。你在一套Standalone集群上把这些参数琢磨透了到了YARN和K8s模式下大部分概念可以直接平移只是“谁来启动进程”这一步变了而已。而且Standalone能让你把注意力完全放在Flink本身。遇到问题就是一台机器、几个进程、几份日志排查链路非常短。直接上YARN的话任务起不来你先得判断是Flink的问题还是YARN的问题对新手很不友好。我当年搭建第一套集群就是从Standalone入手的到现在我都觉得这一步走得值。2. 集群资源规划与前置配置2.1 节点规划几台机器、什么角色、多大规格部署之前先规划节点这一步最容易被跳过也最容易后面返工。一个Flink集群至少在逻辑上要区分两类角色JobManager负责调度、协调、Checkpoint的全局控制TaskManager负责任务的实际执行。在Standalone模式下两者可以部署在同一台机器上但生产环境强烈建议分机部署。以一套四节点测试集群为例规划如下节点角色规格参考备注node-01JobManager主 TaskManager4核8G学习环境可混合部署node-02JobManager备 TaskManager4核8G高可用章节使用node-03TaskManager ZooKeeper4核8GZK为HA服务node-04TaskManager ZooKeeper4核8GZK为HA服务如果你只是想先跑通基础Standalone最低可以缩到两台机器甚至单机。但既然标题是集群安装部署我建议至少三台这样能体会到主备切换和跨节点传输的真实效果。生产环境的最低配置我后面在巡检章节再展开讲。2.2 主机环境准备JDK、SSH免密与文件句柄先把每台机器的系统环境抹平。Flink 1.17左右的主线版本JDK 8和JDK 11都支持建议统一用JDK 8或11别混用。安装完JDK后在每台机器的/etc/hosts里把节点IP和主机名对应关系写清楚否则Flink节点间用主机名通信时会解析失败任务跑着跑着就断连。SSH免密必须配好。Flink的start-cluster.sh脚本在启动集群时会通过SSH依次登录到masters和workers文件里列出的所有主机执行远程启动命令。如果不配免密脚本会一个节点一个节点地提示输入密码实际体验非常痛苦。配置方式很常规在node-01上生成密钥对把公钥分发到所有节点验证ssh node-03 hostname能直接返回而不询问密码就行。文件句柄限制也值得提前处理。流任务持续跑一天每张表、每份状态后端、每路网络连接都在消耗句柄一旦超过系统默认的1024任务会莫名其妙地报“Too many open files”。建议在/etc/security/limits.conf里将nofile调到65535以上同时把nproc限制也放开。2.3 网络端口规划哪些端口必须放通Flink集群跑起来之后涉及的端口不少而且不同角色之间的通信端口是分开的。部署前把端口规划好一方面是为了防火墙放行另一方面是避免和其他中间件冲突。以我常用的默认端口为例端口用途8081JobManager的Web UI与REST接口6123JobManager RPC端口6124TaskManager RPC端口6125Blob服务端口传输用户Jar包等文件2181ZooKeeper客户端端口高可用场景如果你用的是云主机或者跨机房部署安全组和防火墙一定要把这些端口放通。另外注意TaskManager在启动时会动态分配网络通信端口默认端口范围较宽如果想收紧到某个段可以通过taskmanager.bind.host和taskmanager.network.bind-port来控制比如固定为6124-6130这样防火墙规则就更好写。3. Flink集群安装部署实操全记录3.1 安装包下载与版本校验进入正题。先去Flink官网或者镜像站下载二进制发行包文件名类似flink-1.17.2-bin-scala_2.12.tgz。注意版本号后面的scala_2.12这个代表内置的Scala版本。如果你后续要跑Scala API作业建议与集群发行包的Scala版本保持一致否则可能出现兼容性告警。下载完先校验一下完整性。发行包提供的有SHA512校验和命令很简单sha512sum flink-1.17.2-bin-scala_2.12.tgz把输出的哈希值和官网对照一致再进行下一步。这一步看似多余但真实环境里因为下载源代理导致包损坏的情况我遇到过不止一次解压到一半报错才发现就晚了。解压并规划安装目录tar -zxvf flink-1.17.2-bin-scala_2.12.tgz mkdir -p /opt/flink mv flink-1.17.2 /opt/flink/flink建议每台机器都放在同一路径下后面脚本和配置会更省心。解压后目录里的关键子目录包括bin启动停止脚本、conf所有配置文件、lib默认依赖与用户扩展包、log运行日志、plugins可插拔模块。先对这几个目录混个脸熟排查问题时都是直接和它们打交道。3.2 flink-conf.yaml核心配置逐项解析所有核心配置都在conf/flink-conf.yaml文件里。这个文件是Flink集群的“总开关”改错了轻则任务跑得慢重则集群根本起不来。我以测试集群为例给出一个可以直接上手的配置# JobManager地址写每台机器都能解析到的主机名或IP jobmanager.rpc.address: node-01 # 各进程总内存包含堆内外、元空间、JVM开销等 jobmanager.memory.process.size: 2048m taskmanager.memory.process.size: 4096m # 每个TaskManager可以提供几个Slot一般取CPU核数 taskmanager.numberOfTaskSlots: 2 # 默认并行度提交任务时未指定则按此值执行 parallelism.default: 2 # 状态后端和检查点目录 state.backend: hashmap state.checkpoints.dir: file:///data/flink/checkpoints # WEB UI地址 rest.address: node-01 rest.port: 8081 # 重启策略快速恢复实验用 restart-strategy: fixed-delay restart-strategy.fixed-delay.attempts: 3 restart-strategy.fixed-delay.delay: 10 s这里有几个关键点需要理解。第一jobmanager.rpc.address不能乱填。在Standalone模式下所有TaskManager启动时都会读取这个地址去注册自己如果你的配置和实际JobManager所在机器不一致TaskManager永远注册不上集群里会看到一堆“TaskManager not reachable”的错误。第二内存参数别拍脑袋写。taskmanager.memory.process.size表示一个TaskManager进程的总内存预算Flink会在这个预算内自动划分堆内存、托管内存、网络缓冲和JVM开销。4G内存给到一个8G物理机上是合理的因为系统本身、ZooKeeper、日志等还要留余量。如果你在2G的小机器上强行分配4G给TaskManager进程会直接因为内存分配失败而退出。第三taskmanager.numberOfTaskSlots和并行度的关系要搞清楚。一个TaskManager能同时运行的任务线程数等于Slot数整个集群的总Slot数就是所有TaskManager的Slot之和。你的作业并行度如果超过总Slot数任务会一直处于Pending状态不会报错但永远不跑。并行度不是越大越好它受限于Slot总容量而Slot容量又受限于CPU和内存。3.3 masters与workers文件配置conf/masters和conf/workers决定集群启动时会在哪些机器上拉起什么进程。masters文件每行一个JobManager地址格式是“主机名:端口”workers文件每行一个TaskManager地址。基础部署时masters文件只写一个节点node-01:8081workers文件写所有充当TaskManager的节点node-01 node-02 node-03 node-04这里有个容易踩坑的细节masters文件里写的端口是Web UI的端口不是RPC端口。也就是说Flink脚本会根据你给定的端口启动对应的REST服务。而jobmanager.rpc.port是在flink-conf.yaml里单独配置的默认是6123二者不要混淆。当然后面做高可用时masters文件会改成两个节点这个我放到下一节专门讲。3.4 集群启动、验证与第一个测试任务配置完成开始启动。在node-01上执行bin/start-cluster.sh脚本会依次读取masters和workers文件通过SSH拉起JobManager和TaskManager进程。启动完成后第一件事是验证进程是否存在不要直接看“Connect to ... failed”这种输出就以为成功了。在所有节点上用jps查看Java进程正常情况下应该能看到StandaloneSessionClusterEntrypointJobManager进程名和TaskManagerExecutorTaskManager进程名。如果进程没起来去log目录看对应日志。JobManager的日志前缀类似flink-*-standalonesession-*-node-01.logTaskManager的日志前缀类似flink-*-taskexecutor-*-node-03.log。绝大多数启动失败问题日志里都有明确原因比对着屏幕猜要高效得多。进程都在了再验证Web UI。浏览器访问http://node-01:8081能看到集群总览页面左侧菜单能列出当前TaskManager列表和可用Slot数量基本就说明集群处于正常状态。接下来提交第一个测试任务。Flink发行包自带一些示例程序位于examples/batch和examples/streaming目录下我们用一个简单的流处理任务验证全链路bin/flink run -d examples/streaming/WindowJoin.jar \ --windowSize 200-d参数表示后台运行。提交成功后控制台会打印出Job ID类似a3b5c2f0...。再回到Web UI看Jobs页面能看到这个任务处于RUNNING状态并且每个并行子任务都分配到了对应的TaskManager和Slot上。到这里一套Standalone集群就算真正跑通了。提示如果运行的是无界流任务任务会一直处于RUNNING状态这是正常的停掉它用bin/flink cancel jobId即可。4. 高可用扩展引入ZooKeeper实现JobManager故障转移4.1 单JobManager是整个集群的单点风险前面部署的集群只有一个JobManager这在测试环境没问题但如果你要让Flink承认真实任务单点风险是绕不开的。JobManager挂了会发生什么集群的调度层面会瘫痪正在运行的任务虽然不会立刻丢数据但新的任务无法提交已有任务的重启恢复也无从谈起整个集群处于“只读”状态。Flink高可用的核心思路是引入ZooKeeper做分布式协调部署多个JobManager其中一个为Active主其余为Standby备。Active JobManager会把自己持有的作业元数据、状态位置信息写入ZooKeeper和共享存储一旦宕机ZooKeeper能感知到会话超时Standby节点随即抢占成为新的Active并从共享存储恢复元数据继续接管集群。4.2 HA模式配置步骤HA模式需要两样基础设施一套ZooKeeper集群和一个所有JobManager都能访问的共享文件系统。ZooKeeper最少三节点对着官方文档装即可标准模式就好不需要特殊配置。共享文件系统在测试环境可以用NFS挂载比如都挂载到/data/flink/ha生产环境一般直接使用HDFS或者S3。以三节点ZooKeeper为例在flink-conf.yaml里追加或修改以下配置# 启用ZooKeeper高可用模式 high-availability: zookeeper # ZooKeeper集群地址 high-availability.zookeeper.quorum: zk-01:2181,zk-02:2181,zk-03:2181 # 元数据存储目录必须所有JobManager共享可读写 high-availability.storageDir: file:///data/flink/ha # ZooKeeper根路径多套集群可隔离 high-availability.zookeeper.path.root: /flink-ha同时masters文件改为列出所有候选JobManager一个节点一行node-01:8081 node-02:8081每个候选节点上都要放相同配置。磁盘和文件夹权限务必确保两个JobManager都能写入同一个共享目录这是最容易被忽略的环节如果storageDir只能被node-01写node-02成为Active后是无法恢复状态的。启动顺序上也有讲究先启动ZooKeeper再启动Flink集群。bin/start-cluster.sh会在所有masters节点拉起JobManager进程此时它们都处于待命状态ZooKeeper会自动指定一个为Active。验证HA能否生效我的做法是提交一个开启检查点的流任务找到Active JobManager的进程PID直接kill -9模拟宕机。正常情况下10秒内另一个节点的JobManager会接管业务任务依靠检查点恢复Web UI上能看到重启次数变成1任务恢复RUNNING。这一步亲手操作一次你对高可用的理解会完全不一样。注意测试HA时任务必须开启Checkpoint并且配置了重启策略否则任务不会自动恢复只会失败结束。Checkpoint的存储位置也必须和HA配置一样选共享存储才能跨节点恢复。5. 常见故障与排查技巧实录5.1 JobManager因OOM反复重启症状是JobManager进程启动后不到几分钟就消失日志文件末尾出现的内存溢出报告或者干脆没有任何明显错误就退出。最常见原因是jobmanager.memory.process.size给得太小或者机器上其他进程挤占了物理内存导致JVM堆内存不够用。我的排查套路是先看free -g确认物理内存实际剩余量再看日志里JVM配置的堆大小和进程退出码。如果是典型的OutOfMemoryError: Java heap space先把jobmanager.memory.process.size调大比如从1024m调到2048m。如果频繁重启还伴随GC overhead limit exceeded说明堆过小之外还可能有频繁创建大量对象的作业在跑需要检查作业代码的内存消耗而不只是加内存。这里有个经验值JobManager进程总共至少预留1.5G到2G内存哪怕你的任务并行度很低。因为JobManager同时还有RPC服务、Web服务、Blob服务等需要承载这些不在堆内存里也会占去不少系统资源。5.2 Slot总容量与并行度不匹配症状很典型任务提交后一直Pending不报错不退出Web UI上Tasks一栏显示某个或某些子任务始终处于“PENDING”状态。这个时候第一反应不是检查代码而是去TaskManagers页面看集群当前到底有多少个Slot可用。排查思路是这样总Slot数 TaskManager数量 ×taskmanager.numberOfTaskSlots。如果你的并行度是4但集群总Slot只有2那多出来的2个并行子任务永远等不到Slot。解决方案有三个增加TaskManager节点、提高单节点Slot数量、降低作业并行度。三者优先级取决于资源实际情况测试环境建议先调低并行度验证逻辑生产环境再考虑扩容。我见过不少新手在这里卡很久以为并行度是个软件参数调大就能提高性能结果把集群资源直接打满甚至打崩。并行度本质上是“占坑位”坑不够任务就只能排队。5.3 提交任务时连接超时或Connection refused执行bin/flink run时客户端要去连JobManager的REST端口默认是8081。多数情况下报Connection refused是因为jobmanager.rpc.address配置指向了错误的主机或者rest.address没配置导致客户端连到了错误的地址。还有一种情况是防火墙未放行端口在云主机上特别常见。定位时先确认集群进程本身是健康的然后从提交任务的机器上用telnet node-01 8081探测端口连通性。如果端口不通检查防火墙systemctl status firewalld firewall-cmd --zonepublic --list-ports如果网络没问题重点看flink-conf.yaml里的jobmanager.rpc.address和rest.address确保它们和masters文件里写的节点一致。在HA模式下这两个地址建议都写成当前Active节点对应的主机名或者使用负载均衡地址否则客户端会只连一个固定的节点主备切换后就会出现连不上。5.4 Checkpoint频繁失败的隐性原因Checkpoint失败在任务日志里通常表现为“Checkpoint expired before completing”或“Checkpoint ... has been discarded”。很多人第一反应是调大超时时间但根因往往是存储目录不可写、空间不足或者跨机房延迟过高。如果你在集群模式下把state.checkpoints.dir配成了本地路径比如file:///data/flink/checkpoints而TaskManager分布在不同机器上那么每台机器上的本地路径并不共享检查点元数据无法被JobManager完整读取失败是必然的。正确做法是使用HDFS、S3或NFS路径。测试环境临时用NFS最省事。另一个隐性原因是磁盘容量。RocksDB状态后端会把状态数据落盘本地磁盘写满后任务不会立刻报错而是Checkpoint伙同TM之间的通信开始超时看起来像是网络问题。遇到莫名奇妙的Checkpoint失败记得先查每台机器的df -h把磁盘水位列出来超八成就要考虑清理和扩容了。5.5 故障排查速查表症状优先检查项常用修复进程启动即退出日志、物理内存余量调大对应进程内存参数任务一直Pending集群总Slot数扩容节点或降低并行度提交任务Connection refusedport连通性、配置地址修正rpc/rest地址、放通防火墙Checkpoint过期存储目录、磁盘空间、网络延迟换共享存储、清理磁盘、调大超时TaskManager注册不上JobManager地址、hosts解析统一hosts、检查网络6. 部署后的日常巡检与基础调优经验6.1 集群健康度巡检清单集群部署完成只是开始真正能跑一个月不掉链子靠的是日常巡检。我的习惯是每天固定看三样东西。第一看进程和日志。在所有节点执行jps确认进程都在再在log目录下用grep -i error扫一遍最近日志重点看有没有周期性出现的Exception。很多问题在变成严重故障之前日志里已经警告过很多天了只是没人看。第二看Web UI上的TaskManagers页面。这里能看到每个TaskManager的堆内存使用量、堆外内存、网络缓冲、磁盘占用。如果某个节点内存曲线持续走高且不回落很可能是有状态任务在膨胀趁早定位比等到OOM再恢复从容得多。第三看Checkpoint完成情况。在任务详情页的“Checkpoints”标签里连续一段时间内如果“Failed”数量明显增多或者最近一次检查点距当前时间过长那基本可以判定存储或网络出了问题按上一章的排查思路处理。6.2 几个值得动手调的基础参数部署阶段除了前面那些必配项还有几个参数我建议你在跑真实作业前就想好。taskmanager.memory.managed.fraction默认是0.4代表总内存里划给状态后端托管内存的比例。对于有状态任务比如用RocksDB做状态后端这个比例要适当调高比如0.5到0.6对于无状态任务保留默认值即可调高了反而浪费。taskmanager.memory.network.min和taskmanager.memory.network.max控制网络缓冲内存。任务数据Shuffle较大时网络缓冲不够会表现为吞吐上不去、背压频发。我一般会先改成最小值64MB、最大值256MB再根据监控曲线微调。还有一个容易忽略的配置是jobmanager.execution.failover-strategy默认是region按区域失败恢复这个策略在生产环境表现不错别轻易改成全图重启否则一个子任务失败整张图全部重跑资源浪费很大。6.3 部署阶段不该做的几件事说是经验不如说是反面教训。第一不要在lib目录里随便丢依赖包。Flink的lib目录是所有作业进程共享的放一个版本不对的冲突包可能让所有作业一起遭殃。自定义依赖最好通过--classpath或打包到作业胖Jar里而不是直接丢到lib下。第二不要用latest这种滚动版本。Flink的主线版本升级节奏不慢社区的特性变更也频繁。给团队搭建集群用稳定的LTS版本至少在一个季度内不要动版本避免把时间花在无意义的兼容性排查上。第三不要在主备混合部署的机器上把所有组件一股脑塞进去。有的同学手里机器有限把JobManager、TaskManager、ZooKeeper、NFS全放一台机器跑Demo可能没问题但一发生资源争抢性能问题会掩盖真正需要定位的逻辑问题排查体验非常折磨。实在机器少至少保证JobManager和TaskManager分开部署。写到这里基本把Standalone集群从选型、规划、部署、验证、HA到排查的完整链路都过了一遍。这套流程我在测试环境重复了很多次每次踩的坑都不太一样但核心逻辑是稳定不变的先搞懂每个参数背后的资源模型再动配置先确认进程和网络基本健康再深入业务级别的问题。安装部署这件事真正花时间的不是敲那几行命令而是建立对集群运行机制的整体感知。你把这套配置在你自己的环境里完整跑通一遍后面再切YARN或者K8s心里就很有底了。