一, Flink怎样实现并行计算
每个TaskManager是一个JVM进程(也就是一台机器), 然后配置文件flink-conf.yaml中可以设置每个机器的taskmanager.numberOfTaskSlots: 4, 推荐是配置为机器的CPU核心数, slot是静态设置的资源(内存, IO)分配为多少份, 实际并行运行的时候是一个task是一个jvm线程, 然后他们之间可能在相同的slot上运行, 也可能在不同的slot运行, 然后不同task之间还会跨taskmanager进行交互, 比如说keyby或者 合并流
二, 并行的任务, 需要占用多少个slot
1,如果没有设置slotSharingGroup, 则以整个数据流中设置的最大的并行度来占用slot, 因为Flink默认是slot可以共享的
2, 设置了slotSharingGroup则将每个group中最大并行度相加则是占用slot的个数, 因为不同的group默认要运行在不同的slot上
三, 一个流处理程序, 到底包含多少个任务?
并不是每一个操作就代表一个任务, 可能两个操作在DAG(有向无环图)中显示着合并为一个任务了.原因是如下:
所有的Flink程序都是由三部分组成的: Source、Transformation和Sink. 这些组成了数据流图,大部分情况下程序中的transformations和 dataflow中的operator是一一对应关系.
1,Flink中的执行图
可以分为四层: StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图
StreamGraph(client上生成): 用户通过Sream API编写的代码生成的最初的图
JobGraph(client上生成): 将 StreamGraph 中多个符合条件的节点chain在一起作为一个节点等优化后的图 (这个就是我们看到的图)
ExecutionGraph(jobmannager上生成): JobGraph 的并行化版本, 是调度层最核心的数据结构.
物理执行图(task上运行): JobManager 根据 ExecutionGraph 对Job进行调度后, 在各个TaskManager 上部署 Task 后形成的 “图”
2,数据传输形式
-
One-to-One(forwarding)模式, stream的分区不会发生改变
map、filter、flatMap、print、sum等算子都是one-to-one -
Redistributing: stream的分区会发生改变
keyBy基于 hashCode重分区、broadcast会随机重新分区, rebalance会轮询进行分区(前后两个并行度不同就会rebalance), 还有shuffle重分区 就是发牌这种操作
3,任务链(Operator Chains)
相同并行度且是one-to-one操作, Flink会将这样相连的算子链接在一起形成一个task, 原来的算子成为里面的subtask,任务链里面的算子, 是通过本地转发(local forward)方式进行连接, 其实还得是同一个slot共享组
如果不希望自动链接成一个Task可以有
resultStream.print().setParallelism(1).disableChaining();
或者
env.disableOperatorChaining();
前面断开后面不断
DataStream<Tuple2<String, Integer>> resultStream = inputDataStream.flatMap(new MyFlatMapper())
.keyBy(0)
.sum(1).setParallelism(2).startNewChain();