flink 学习备忘录-flink程序常见问题分析和调优
flink程序常见问题分析和调优?
出现最多的问题就是反压,交通业务卡口数据,早晚高峰时产生,下游的处理速度跟不上上游消费kafka的速度
猜测的原因:
- 大量的计算指标 13个指标 算不过来 流控 窗口算子使用的timeWindowAll 非并行算子 只能一个slot
- 反压产生在source,数据最终都会被积压在发生反压上游的算子的本地缓冲区(localbuffer)中,每一个taskmanager都有一个本地缓冲池,每一个算子数据进来后都会把数据填充到本地缓冲池中,数据从这个算子出去后会回收这块内存,但是当被反压后,数据发不出去,本地缓冲池就无法释放,导致一直请求缓冲区(requestBuffer).
解决
- 调大等待时延120s-->180s 12个slot 60s算一次,窗口被触发的时间延迟了
- 任务拆分,将流量统计跟外地车拆分开 //TODO 专门写一个流量统计 最低资源跑一下 1slot + 30s+5s延迟
slot 内存隔离,CPU不隔离
- 实际原因:线上CPU负载高,CPU争夺导致
产生过两次,一次是集群中solr数据量超过规划导致,50亿数据查询导致GC频繁
一次是离线任务:伴随车计算 分时段并行跑导致
实时离线程序,以及跟solr 未隔离导致的 - 另一个数据质量问题:
卡口设备采集到的过车时间 会提前或者滞后
网络传输/设备故障问题 会导致今天过车数据明天才会到达
- 过车时间提前(脏数据) 会导致计算窗口被提前触发-结束,数据失真 逻辑上需要过滤掉这部分数据
- 还有CPU指定的太小,且CPU不隔离 导致CPU在高峰期计算紧张 造成滞后
数据倾斜问题
影响:单点问题 --> GC频繁 --> 吞吐下降,延迟增大 --> 系统崩溃
- 单点问题:数据集中到某些partition上
- GC频繁:过多的数据集中到某些JVM中导致其内存资源短缺,进而引起频繁GC
- 吞吐下降,延迟增大:频繁的GC和数据单点问题导致系统吞吐下降,数据延迟
- 系统崩溃:严重情况下过长的GC会导致TM和JM失联,系统崩溃
倾斜-源头分析
- 对于数据源消费不均匀(比如kafka数据源,通过调整数据源算子的并发度解决)
- 原则:通常情况下是source的并发度和kafka的分区数一致
- 或kafka分区数是source并发度的正整数倍
注:公司卡口数据源 kk_data_first 6分区 指定6个以上算子会出现数据倾斜的现象
调优
设置并行度
- 并行度控制任务的数量,影响操作后数据被切分成的块数
- 调整并行度让任务的数量和每个任务处理的数据与机器的处理能力达到最优
- 一般并行度设置为集群CPU核数总和的2-3倍
配置进程参数
Flink on YARN模式下,有JobManager和TaskManager两种进程,在任务调度和运行过程中,JobManager和TaskManager承担很大责任
JobManager内存配置:
- 负责任务的调度,以及TaskManager、 RM之间的消息通信
- 如果出现任务数变多,任务并行度增大时,JobManager内存都需要相应增大
TaskManager个数配置: - 每个TaskManager每个核同时能跑一个task,所以增加了TaskManager的个数相当于增大了任务的并发度
- 资源充足,可以相应增加TaskManager的个数,以提高运行效率
单个TaskManager Slot数配置: - TaskManager的内存主要用于任务执行、通信等
- 当一个任务很大的时候,可能需要较多资源,因而内存也可以做相应的增加
调优1:
--------------------------------------------------------------------------------------
yarn-session 示例:
nohup bin/yarn-session.sh \
--queue xxx \ 指定yarn队列
--container 12 \
--jobManagerMemory 10240 \ 指定 jobManagerMemory 内存
--taskManagerMemory 20480 \ 指定 taskManager 内存
--slots 10 \
--ship test/ \
>/opt/xxx/xxx/flink-cluster/log/yarn-session.log 2>&1 &
nohup bin/flink run \
--class com.xxx.xxx.xxx.xxx \ 主类
-yid application_1570900515161_13406 \ 已经发布yarn-session的AM
-p 12 \ 指定并行度,即使用12个slot(slot从总的taskmanager内存)
/opt/xxx/xxx//xxx-xxx-xxx-1.0.jar \ jar包路径
>/opt/xxx/xxx//xxx-xxx-xxx-1.0.log 2>&1 & 日志路径
--------------------------------------------------------
设置分区方法
合理的设计分区依据,可以优化task的切分
- 思路:在程序编写过程中要尽量分区均匀,这样可以实现每个task数据不倾斜,防止由于某个task的执行时间过长导致整个任务执行缓慢
- 查看是否倾斜: UI -->Subtasks 点开一个阶段 -->看数据分布是否均匀
分区方式
- 随机分区: 将元素随机地进行分区 dataStream.shuffle()
- Rebalancing分区: 基于round-robin对元素进行分区,使得每个分区负载均衡 对于存在数据倾斜的性能优化是很有用的 dataStream.rebalance()
- Rescaling:以round-robin的形式将元素分区到下游操作的子集中 将数据从一个源的每个并行实例中散发到一些mappers的子集中,用来分散负载(不需要完全rebalance) dataStream.rescale()
- 广播: 广播每个元素到所有分区 dataStream.broadcast()
- 自定义分区:自定义的Partitioner对每一个元素选择目标task,以按照某个特征进行分区
内存调优
- 非堆内存:network buffer && manager pool 要是调整两者比例
- head内存:flink系统内 flink是运行在JVM上的,flink的堆内存调优跟其他JVM调优一致 将默认的Parallel Scavenge的垃圾回收器改为 G1垃圾回收器
配置 netty 网络通信
经验总结
判断数据倾斜
当出现数据倾斜(某一部分数据量特别大),虽然没有GC,但是task时间严重不一致
判断缓冲区超时设置
由于task在执行过程中存在数据通过网络进行交换,数据在不同服务器之间传递的缓冲区超时时间可以通过setBufferTimeout进行设置
- setBufferTimeout(-1):会等待缓冲区满之后才会刷新,使其达到最大吞吐量
- setBufferTimeout(0):可以最小化延迟,数据一旦接收到就会刷新
- setBufferTimeout(n):n>0时,缓冲区会在该时间之后超时,然后进行缓冲区的刷新
代码中设置 env.setBufferTimeout(n)
缓存区:存在的原因是为了维持内存跟输入输出的设备速度不匹配, 程序执行时,可以先将数据拷贝至缓冲区,一定情形下将数据传给设备
缓冲区刷新:就是将当前缓冲区数据全部提交 忘记刷新可能会导致输出停留在缓冲区
引用 flink面试题整理

浙公网安备 33010602011771号