Flink是什么?Flink使用体验和坑

1. 前言

  • 本文仅代表个人浅薄观点,不喜勿踩

  • 最近一年的工作有很长一段时间在和Flink打交道,Flink作为Apache软件基金会开发的新一代流批一体内存计算框架,既有令人惊艳之处,又有一些一言难尽之点,我将就这两点做一些个人的分享

  • 首先对Flink没有任何了解的人先科普下Flink(有了解的直接跳过),相较与官网,以下的解释可能都不够准确,但是通俗易懂

    • Flink是一个框架,主要用在数据流处理中,github超过21.7k的Star(不愧是Apache顶级项目)

    • 程序员只需要根据框架提供的各个层级的API(既可以使用熟悉的SQL、又可以精细的控制每条数据)进行简单的编程,并提交给框架,就可以完成一个数据处理程序

2. Flink的优点

2.1 官方描述的优点

  • 根据官方描述Flink强大的地方有很多,我也就这些强大之处写一些自己的看法,如

    • 流、批一体(既可以处理流、又可以处理批,ps:我想Flink这里想体现的是相对于Spark的微批,Flink做到了真正的流处理,不过流和批的矛盾由来已久,也就是时延和吞吐是一对矛盾)

    • 高吞吐、低延迟(这里Flink当然也是针对其他数据处理引擎进行对比,ps:无论使用什么语言,哪怕是令人诟病执行速度慢的python,我们原生的写一个计算任务当然会有更高的吞吐和更低的延迟,但我们知道Flink功能强大,而我们自己的demo当然也不具备这些功能,类比于ORM框架再快再先进,也比不过JDBC手写SQL的执行速度)

    • 状态计算的各种一致性语义(这个听起来比较复杂,实际上就是通过某种算法保证在异常状态可以实现数据在我们写的这个软件中只精确处理一次、至少处理一次等语义,ps:算法非常精妙,有兴趣可以了解Checkpoint,被称为Flink四大基石之一,另外三个分别为State、Time、Window,结合State,就可以实现这些一致性语义)

    • 分布式(分布式往往意味着高可用、弹性伸缩,ps:是的,但Flink的强大不止于此,这里提一点使用感受,下面会着重讲下辛酸经历,如果不使用分布式这个特性,没什么必要花费高昂成本学习Flink)

    • 运行任意规模应用(按照官方的说法,有了分布式保证,Flink可以部署到任意地方运行任意规模的应用,ps:这里任意地方主要指的是k8s、YARN等平台上,k8s、YARN是什么?没关系,只要理解他们有一种能力:资源管理,也就是说Flink高度兼容这些知名的资源管理程序,规模可以达到上至万亿事件、TB规模、数千个处理器)

    • 充分利用内存性能(这点我要着重说下,因为很多人对Flink的内存有误解)

      • Flink本质也是运行在JVM上的应用,注意很多文章具有误导性,我们一定要明确Flink并没有跳出JVM对内存的管理,这点在写Flink程序时需要格外注意,ps:在Flink的算子中我们编的程序new的对象,仍然在JVM堆区,受JVM管控

      • Flink针对大数据在内存中计算的痛点,我们这里简单介绍下做了很多优化

        • 回忆JVM规范的内容,我们知道Java对象在堆中存储,包含了对象头、对齐填充等和数据本身无关的内容,就连最基本数据类型boolean,在32位操作系统中,也占4byte,也就是说JVM的对象在内存中是松散堆积,存储密度低(指存了许多和数据本身无关的内容),这在内存计算框架中其实是很难接受的,我们希望充分的利用内存,同时计算大量的数据

        • 对象多了带了的问题就是频繁GC,CPU飙升

        • 对象再多点,OOM,严重的JVM崩溃

      • 针对此Flink做了哪些优化呢?代价是什么?

        • 既然松散,那就让他变密,方案一个词形容:序列化,二进制存储密度是最高的,这是最直接的解决方式

        • 代价:序列化需要耗时,你可以理解JVM中的对象虽重,但功能不仅强大、速度还快,空间换时间?嗯确信,所以对Flink来说序列化器很重要,非常重要,Flink官网有一章都是再讲序列化、和如何优化序列化器,假设你有计划使用Flink编写一个生产级代码,一定要着非常非常重看这章……,嗯!

        • 细化内存管理,方法并不是很难更多实现参考各式各样的参数配置,和接口MemorySegment实现,不着重介绍

        • 使用堆外内存,知名框架好像都有这个习惯,嗯确信这是有原因的——零拷贝

    • 轻量错误处理(部分异常可以重新自动拉起,并结合出错时的状态达到各种语义,前面有讲)

    • 支持乱序数据处理、迟到数据容忍(如果对每条数据的处理都是无状态的,就是说每条数据处理方式都相同,这条直接忽略,ps:这里说的是处理动作是有状态的,本条数据影响下一条处理方式,要求数据需要有时间语义,通俗说根据数据上的某个字段或进入程序的时间或处理数据时的时间Flink帮你排好序处理,嗯那怎么处理的?不妨看看另一个基石Time)

    • 高度灵活的窗口(简单的比如计数、计吞吐、计时延,复杂的计算一段时间平均值等等……,基石Window?嗯没错)

    • 自动优化(某些计算需要打乱、分区并行,甚至非常复杂,Flink会做一些优化合并)

    • 优秀的监控(嗯不光能通过Web监控JVM,还能有时时反压、火焰图等非常好用的特性,ps:还支持业内知名的prometheus,好吧我尝试过,还是有些学习成本的,最后因为时间原因没有调通,但确信是可以的)

    • ……

2.2 我用起来很爽的点

  • 快,不是处理速度快,是开发速度快,框架的优点就在于此,资源管理、资源监控、任务调度……应有尽有,Web界面用起来确实挺爽,写Flink程序这一年,几乎没有用过JVM的其他监控工具,这点上他真的很香

  • 生态还不错,FlinkCDC是我这一年接触最多的和Flink有关的开源项目,不过em

3. Flink的问题(这个标题其实是有问题的)

3.1 关于标题的解释

  • Flink严格意义上作为公认的新一代内存计算引擎,没有问题

  • 那问题在哪里?在使用的人

    • 选用Flink前,最重要的不是了解Flink,而是了解你的需求,你需要做什么

    • 写代码漂亮、算法精湛的人未必是一个好的程序员,软件工程师的进阶更重要在理解需求,理解你要做什么,往往我们会在技术中迷失自己,技术固然非常重要,但技术是服务需求的

    • 一家只有几台服务器的单位,应用可能都是单击部署,不需要使用Flink来解决问题,设计模式中有一句经典话术:如无必要,勿增实体

    • 已经使用其他计算引擎实现过的程序,如运行没有大的瓶颈和问题,不需要花时间、经历和宝贵的研发资源去更换到Flink(ps:他强任他强,我用Java8)

    • 只实现简单的数据传输,不打算做任何计算,不需要使用Flink来解决问题

    • 以上问题也是我在不断的工作中总结的经验,希望后来者不要踩坑

3.2 Flink真的没有槽点吗?

  • 当然也不是,以下部分内容新上手的同学可能未必理解,当然如果说错大家轻喷,毕竟我也是个新上手的同学

  • Flink支持的语言很多,但实际上建议大家还是不要使用python、甚至被称为大数据专属的Scala语言开发Flink程序

    • Flink被阿里收购后一直使用Java作为主要编程语言

  • Flink很长一段时间的版本是不支持并行算子间进行通信的,嗯确实如此查了官网文档(分布式系统中这并非易事,好在他后来支持了),Flink的每个算子工作只能由事件驱动

    • 有时候有些奇怪的东西确实需要这样通信,甚至还需要反数据流方向通信,em

    • 当然了在open()中嵌一个服务器他也不是不行,那我还要Flink做什么,我都这么能耐了,为什么还要用Flink……哈哈哈

  • Flink各并行算子间存在典型的木桶效应,即一个算子卡住,其他算子干瞪眼,结合并行算子无法通信,非常难受

    • 倒也不是不能解决,可以配置Checkpoint超时时间来解决

    • 那么问题又来了,万一我真的要算这么久呢,算了框架吗总是不能十全十美,这种任务可能真的不适合使用Flink

  • Flink的序列化往往可能会成为吞吐的瓶颈,有得就有失,嗯前面也详细讲过Flink内存管理策略

  • 出现奇怪的错误的时候别急,可能不是你的问题,【Flink | JIRA】,去找找说不定有惊喜……再次确信

  • Flink的一些社区衍生产品可能言过其实,嗯 细品,不能明说

  • Flink内部都不怎么维护Standalone部署模式(同事在Flink交流群里,有人提到这点,其他人纷纷投来惊艳的目光“嗯,你们Standalone上生产?”,吓的我着实不敢说话,因为我也这么干过……哈哈,一个分布式系统部署在单击,HA不光没用上,还带了一堆解决HA的组件,甚至是不如单击稳定的,所以使用Flink单击部署的同志慎重)

  • Flink的最小资源分配单位是Slot并且Flink认为每个并行度只能享有一个Solt

    • 嗯有分配单位,但是好像又不那么细,有时候我就是希望更细点怎么办…………要求真多

    • 额外注意,Slot,他是一个逻辑概念,他不会和具体的CPU绑定,也就是说本质上是做不到物理CPU隔离,原理参看SlotManager源码,是每个Slot实现了一个单线程线程池,并没有多高大上

    • 一句话,内存隔离平均分配,CPU逻辑隔离,物理不隔离(其实认真学习过操作系统的人仔细思考下,应该知道CPU调度是操作系统完成的,对操作系统来说JVM只是一个用户应用,何况跑在JVM上的Flink)

  • 由于独特的内存管理方式,和声明式的函数式编程,你发现你很多东西都要实现序列化接口否则会报错,好吧这也不是什么坏事

  • 对于复杂算子,如果不知道Flink运行机制,我们写着写着,甚至会有坑爹的同事(指我自己)在构造方法中加逻辑,出现各种资源未关闭、甚至会莫名出现空指针……这当然不是Flink的问题,但确实和传统的面向对象编程有那么点不同

    • Flink会先在JobManager中生成执行图,也就是先执行一遍所有算子的构造方法

    • 然后把生成的类都序列化后通过网络发送给TaskManager执行,所以逻辑要放在open()方法中哦

  • 反压真的要着重提一下,Flink1.5之前,任务间想做到隔离,就不能把网络I/O缓冲区吃满,否则就会出现一个TaskManager下,一个任务反压,打满底层TCP协议中分配的Socket Buffer,触发反压,影响其他任务,可能是当时的工程师们想着直接使用TCP协议的流量控制机制来做反压?或者即使是像Flink这样的开源项目代码也会存在想当然……嗯,咱也不知道

    • 好在Flink1.5之后解决了这个问题,解决思路其实也很简单啦,算子间传递数据告诉一下对方当前承载能力,学术名称叫credit机制

  • 如果想额外自定义做一个界面来控制、管理任务状态,我劝各位慎重,分布式状态一致性很难保证,坑很多

    • 毕竟通常Flink很多部分你不能自己修改、加分布式锁、编译(ps:有这个能力用不着Flink),你能做的就是提交一个任务

    • 有时候确实有这样的需求,我们的Flink Web可能确实不能满足用户的需求,毕竟在国内,一个全英文的界面,里面很多专业术语,没学过Flink真头疼

  • 哦,我竟然忘了这一点,Flink学习路线较为陡峭,官方文档写的着实也一般般,中文资料讲原理的并不是非常多,多数也讲不明白,有时候只能自己看源码

  • ……

4. 写在最后

  • 我在初学计算机的时候,有人教我,框架是一个半成品软件,Flink也不例外,对于选型一个半成品的软件来说,最重要的是关注他合不合适

  • Flink本身没有好坏,还是在于使用Flink的人

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值