关于Flink
Flink架构
Flink是一种流式计算框架,与Spark的“微批”设计理念不同,Flink则将数据看作无限的和有限的数据流,支持对数据流进行逐条或者窗口式处理,从而保证数据处理延迟可以达到毫秒级。同时基于有限流的设想,Flink还可以实现数据的批量处理,实现了流批一体。可以说完全基于数据流的设计理念,一举将Spark打的体无完肤,从而可以说目前Flink成为各大厂商的流式数据处理的标配。
Flink集群采用的是主从架构,JobManager作为集群的主节点,负责集群任务调度以及资源管理的任务。TaskManager作为集群的从节点,负责接受JobManager分派的执行任务,为集群提供计算资源。
Flink提供了多种部署模式,包括Standalone、YARN、Mesos、K8S、Docker等。针对不同的部署方式,Flink集群的运行时态架构不太一样,但是核心部署架构还是保持一致的,即JobManager+TaskManager的组合。
与YARN一致,为了解决主节点的单点问题,Flink也需要解决JobManager的单点问题。针对Standalone的部署模式,需要部署多个JobManager节点通过主备模式实现高可用;如果是将Flink集群托管给YARN进行管理,则可以借助YARN集群的AM恢复机制来实现JobManager的高可用。
Flink on YARN
Flink可以运行在YARN集群中,也是基于Job Manager+TaskManager来对外提供服务。在YARN中,JobManager将内嵌在Flink应用的AM中,负责处理client端提交的Flink JOB。而TaskManager将运行在Yarn Container中,提供计算能力。
Flink在YARN集群上支持三种部署模式:Session模式、Per-job模式以及Application模式。
Session模式
Session模式的原理与Standalone模式相似,只不过是将Flink集群运行在YARN集群提供的Container中。在这种模式下,Flink将基于client的请求动态进行TaskManager的申请和回收。
这种模式的优势在于与standalone模式保持了一致的体验,同时Yarn集群又提供了Container节点的自动恢复能力,即TaskManager进程挂掉之后,AM(JobManager)能够自动把它拉起来。劣势也是standalone的劣势,就是会产生资源竞争,所有任务也都在一个Flink集群实例当中,日志混淆在了一起,不太便于日志排查和分析。
启动yarn-session
yarn-session.sh -jm
提交Job
在yarn-session模式下,提交job的方式与standalone模式一致。只不过区别在于,遵循的是yarn-cluster模式的命令参数组合,即可以通过-yD进行参数传递。
flink run -yD
停止job
与standalone模式一致,可以通过以下命令:
flink cancel
停止yarn-session
两种方式:
- 命令退出:
echo "stop" | ./bin/yarn-session.sh -id
- Attach方式:
yarn-session.sh -id
然后通过ctrl+C来退出
高可用配置
high-availability: zookeeper
high-availability.zookeeper.quorum: localhost:2181
high-availability.storageDir: hdfs:///flink/recovery
high-availability.zookeeper.path.root: /flink
yarn.application-attempts: 10
探秘
经过研读源码,在启动yarn-session时,系统首先会检测是否在${yarn.properties-file.location}文件夹下存在yarn配置文件,在配置文件中存放的是flink应用的applicationId信息。
这样我们在执行 flink run命令后,就可以通过appId连接到Flink集群,从而将应用提交到yarn-session的flink 集群中。
Per-Job 模式
Per-Job 模式是指每个Flink Job都是一组独立集群,即有自己的JobManager和TaskManager。提交任务后,YARN首先会为该任务分派一个AM容器,该容器内会运行一个JobManager进程,之后JobManager会向Yarn申请运行TaskManager所需要的container,container的数量和container的配置(CPU、内存)会基于客户端的需求来确定,当JobManager和TaskManager进程都拉起来之后,则会执行相应的Flink Job。这样,与Standalone以及yarn-session不同的是,我们不需要准备一个常驻的Flink 集群进程,只需要保证本地有一个Flink环境即可,Flink集群是在我们提交Job时动态创建出来的。
这种方式的优势在于每个任务独立运行,相互不会收到干扰,这个不干扰还包括了运行日志也是隔离的。另外,借助YARN集群的能力,提供了对Flink Job的全方位保障,包括JobManager的高可用,TaskManager的恢复,然后再结合Flink自身提供的健壮性,包括检查点、保存点机制,从而能够很好的保障Flink Job的高可用和健壮性。劣势的话,就是保证了资源隔离的同时也占用了更多的资源,因为每个Job都需要一个JobManager,每个JobManager都会消耗一个AM进程资源。
提交Job
flink run -d -m yarn-cluster -ys
其中 -m yarn-cluster 为固定写法【针对1.11版本】,通过阅读源码,Flink内部时通过提取-m中是否存在yarn-cluster标识来确定是否时per-job模式的。
停止Job
flink list -yid
flink cancel
探秘
之前一直好奇都是执行flink run命令,flink是如何区分是standalone、yarn-session还是per-job的,研读源码之后发现,相关的判断逻辑主要是在flink-client的工程中做的,首先会筛选应用Client进行Flink Job的启动,包括 GenericCLI、FlinkYarnSessionCli、DefaultCLI。如果在启动命令中包含 -m yarn-cluster 参数的话,则FlinkYarnSessionCli将被启用,从而顺利的开始执行后续的Per-job模式的启动流程。
Application模式
application模式与per-job模式类似,也是每个Job一个独立的Flink集群。与per-job的区别在于Flink Job的main函数的执行位置。Per-job的执行位置实在提交任务的客户端所在机器,需要进行JobGragh的生成与提交;而Application模式是在JobManaer侧执行,也就是在Yarn的AM中执行的,这样就可以释放clien侧的资源占用。另外,application模式可以从HDFS加载flink job相关jar文件,这样可以避免相关Jar文件的重复加载。
这种模式的优势的话与per-job是一致的,而且相比per-job还提供了远端启动job、jar包共享等优势,是一种更先进的部署模式。劣势与perjob是一致的。
启动Job
flink run-application -t yarn-application -Dtaskmanager.numberOfTaskSlots=2 -Dyarn.application.name=
停止Job
flink list -yid=
flink cancel 00000000000000000000000000000000 -yid
探秘
application模式,flink client采用的是GenericCLI,也就是遵循的是flink run的Generic Mode的参数体系。相比与per-job的启动参数配置,这里多出了checkpoints和savepoints路径的配置,这是因为在application模式下,开启了HA之后,所有任务的jobid都会固定为 0,这样为了避免各个任务的checkpoints和savepoints存储路径发生冲突,所以需要针对每个Job进行定制。
另外,这种运行模式在运行时,如果依赖于系统变量,则需要在yarn-env中添加,并同时加入到yarn-site.xml的env-whitlist参数中。
HA场景验证
本次验证了各种场景下的Flink on YARN的高可用场景,包括kill TaskManager容器、kill JobManager容器、kill NodeManager进程、kill ResourceManager进程、停止NodeManager进程以及停止ResourceManager进程。针对这些场景,Flink Job都能够做到正常恢复。针对不同的场景,恢复的机制也不太相同。
kill TaskManager容器后,会导致Flink Job的中断;而kill JobManager容器则不会。同样kill NodeManager也会导致相应的job进行中断恢复,而kill ResourceManager则不会(因为我们开启了RM的recovery模式,并且开启了RM的状态存储)。
总结
借助Yarn提供的资源管理能力,能够很好的保护Flink Job的高可用,避免了对于Flink集群的维护。但是实际上针对我们这种全是long running的job,并且需要保证所有任务都得能够启动起来的场景看,YARN处理提供了可靠性保障外,并没有发挥出Yarn的调度策略优势。针对我们单个部门的单个项目而言,引入YARN的成本有些高。毕竟虽然不用维护Flink集群了,但是却引入了YARN集群,哈哈。
经过讨论,YARN集群还是适合在整个公司来应用,是公司的大数据基础设施的一部分,借助Yarn的灵活的调度策略,来对公司的整个大数据资源池进行管控和调度,这样我们在实行flink on yarn就更加轻松了。
当然,目前K8S发展势头很猛,未来Flink的最佳部署实践是不是还是以Yarn为主,还是直接基于K8S还有待进一步学习才行。