大数据中的各类框架优化

一、Hive

一)计算资源调优

基于Hive on MR

1.1 Yarn资源配置

yarn-site.xml

一个NodeManager节点分配给Container使用的内存,取决于NodeManager所在节点的总内存容量和该节点运行的其他服务的数量(默认8G,3台服务器总内存Memory Total24G),一般设置为总内存的1/2~2/3

<property>

    <name>yarn.nodemanager.resource.memory-mb</name>

    <value>65536</value>

</property>

一个NodeManager节点分配给Container使用的CPU核数VCores Total,取决于NM所在节点的总CPU核数和该节点运行的其他服务

<property>

    <name>yarn.nodemanager.resource.cpu-vcores</name>

    <value>16</value>

</property>

单个Container能够使用的最大内存

<property>

    <name>yarn.scheduler.maximum-allocation-mb</name>

    <value>16384</value>

</property>

单个Container能够使用的最小内存

<property>

    <name>yarn.scheduler.minimum-allocation-mb</name>

    <value>512</value>

</property>

1.2 MapReduce资源配置

主要包括Map Task的内存和CPU核数,以及Reduce Task的内存和CPU核数

单个Map Task申请的container容器内存大小,默认值1024,该值不能超出yarn.scheduler.maximum-allocation-mb和yarn.scheduler.minimum-allocation-mb规定的范围

set  mapreduce.map.memory.mb=2048;

单个Map Task申请的container容器cpu核数,默认值为1,一般无需调整

单个Reduce Task申请的container容器内存大小,默认值为1024,不能超出yarn.scheduler.maximum-allocation-mb和yarn.scheduler.minimum-allocation-mb规定的范围

set  mapreduce.reduce.memory.mb=2048;

单个Reduce Task申请的container容器cpu核数,默认值为1,一般无需调整

二)SQL执行计划调优

Explain执行计划

  • TableScan:表扫描操作,通常map端第一个操作肯定是表扫描操作
  • Select Operator:选取操作
  • Group By Operator:分组聚合操作
  • Reduce Output Operator:输出到 reduce 操作
  • Filter Operator:过滤操作
  • Join Operator:join 操作
  • File Output Operator:文件输出操作
  • Fetch Operator:客户端获取数据操作

2.1 HQL语法优化之分组聚合优化
2.2 HQL语法优化之Join优化
2.3 HQL语法优化之数据倾斜
2.4 HQL语法优化之任务并行度
2.5 HQL语法优化之小文件合并
2.6 其他优化

1)CBO优化

2)谓词下推

3)矢量化查询

4)Fetch抓取

5)本地模式

6)并行执行

7)严格模式

二、Kafka

待补充……

三、Spark

待补充……

一)资源配置调优

为任务分配合适的资源,在一定范围内,增加资源的分配与性能的提升是成正比的

  • 标准的Flink任务提交脚本(Generic CLI 模式)
bin/flink run \
-t yarn-per-job \
-d \
-p 3 \ 指定并行度
-Dyarn.application.queue=default \ 指定yarn队列
-Djobmanager.memory.process.size=1024mb \ 指定JM的总进程大小 2~4G足够
-Dtaskmanager.memory.process.size=1024mb \ 指定每个TM的总进程大小  2~8G足够
-Dtaskmanager.numberOfTaskSlots=2 \ 指定每个TM的slot数  core:slot=1:1 或 1:2
-c com.atguigu.flink.tuning.UvDemo \
/opt/module/flink-1.17.0/flink-tuning-1.0-SNAPSHOT.jar

参数列表://nightlies.apache.org/flink/flink-docs-release-1.13/docs/deployment/config/

1.1 内存设置

1)TaskManager内存模型

  • JVM特定内存

taskmanager.memory.jvm-metaspace.size,默认256mb

taskmanager.memory.jvm-overhead.fraction,默认0.1

taskmanager.memory.jvm-overhead.min,默认192mb

taskmanager.memory.jvm-overhead.max,默认1gb

  • 框架内存

堆内:taskmanager.memory.framework.heap.size,默认128MB

堆外:taskmanager.memory.framework.off-heap.size,默认128MB

  • Task内存

堆内:taskmanager.memory.task.heap.size,默认none,由Flink内存扣除掉其他部分的内存得到

堆外:taskmanager.memory.task.off-heap.size,默认0,表示不使用堆外内存

  • 网络内存(堆外)

taskmanager.memory.network.fraction,默认0.1

taskmanager.memory.network.min,默认64mb

taskmanager.memory.network.max,默认1gb

  • 托管内存/管理内存(堆外)

taskmanager.memory.managed.fraction,默认0.4,非RocksDB时可以调小

taskmanager.memory.managed.size,默认none

1.2 CPU资源

Yarn的容量调度器默认情况下是使用“DefaultResourceCalculator”分配策略,只根据内存调度资源

可以在capacity-scheduler.xml 中修改属性

<property>
 <name>yarn.scheduler.capacity.resource-calculator</name>
 <!-- <value>org.apache.hadoop.yarn.util.resource.DefaultResourceCalculator</value> -->
 <value>org.apache.hadoop.yarn.util.resource.DominantResourceCalculator</value>
</property>
  • 默认策略:DefaultResourceCalculator
  • 动态策略:DominantResourceCalculator
    •         默认一个slot对应一个CPU vcore,可以手动指定为一个slot对应任意个CPU vcore
      •         用户设置的参数不会影响JobManager-->仍然对应1 vcore(ApplicationMaster)
      • Running Containers = 1 JobManager +  numberOfTaskSlots
      • Allocated CPU VCores = 1 JobManager + numberOfTaskSlots * vcores

不同共享组的最大并行度之和 = slot个数
1 CPU => 4G内存
        资源充足 => CPU:slot = 1:1
        资源不足 => CPU:slot = 1:2 1:3

1.3 并行度设置

先压测,测试单个并行度的处理上限,再计算并行度 = 总QPS/单并行度的处理能力

一般,整个任务的并行度 = Kafka的分区数

举例:
Kafka主题  4个分区 
4个分区 ==> 并行度为4 ==> 4个slot ==> CPU:slot=1:2 ==> 2个CPU ==> 8G内存(1个CPU 4G)

二)大状态及CheckPoint调优

2.1 RocksDB大状态调优

1)开启State访问性能监控(不常用)

state.backend.latency-track.keyed-state-enabled:true #启用访问状态的性能监控

-Dstate.backend.latency-track.keyed-state-enabled=true \

2)开启增量检查点和本地恢复(不开启则默认全量)

state.backend.incremental: true   #默认false,改为true,开启增量检查点

state.backend.local-recovery: true #开启本地恢复,目前仅涵盖键控类型的状态后端(RocksDB)

3)调整预定义选项(常用)

当前支持的预定义选项有DEFAULT、SPINNING_DISK_OPTIMIZED、SPINNING_DISK_OPTIMIZED_HIGH_MEM或FLASH_SSD_OPTIMIZED

state.backend.rocksdb.predefined-options: SPINNING_DISK_OPTIMIZED_HIGH_MEM #设置为机械硬盘+内存模式

4)增大block缓存

state.backend.rocksdb.block.cache-size: 64m   #默认8m,建议64~256mb

5)增大write buffer和level阈值大小

state.backend.rocksdb.writebuffer.size: 128m  #默认64mb,建议调大

state.backend.rocksdb.compaction.level.max-size-level-base: 320m  #默认64mb

6)增大write buffer数量

state.backend.rocksdb.writebuffer.count: 5  #默认2

7)增大后台线程数和write buffer合并数

state.backend.rocksdb.thread.num: 4  #默认为1

state.backend.rocksdb.writebuffer.number-to-merge: 3  #默认为1

2.2 CheckPoint设置

一般为min分钟级别,时效性要求高时可以设置为s秒或ms毫秒级

三)反压处理(重点)

Flink网络流控及反压的介绍:

https://flink-learning.org.cn/article/detail/138316d1556f8f9d34e517d04d670626

反压(BackPressure):生产速度 > 消费速度

危害:数据积压、延迟变高、资源耗尽、系统崩溃(影响checkpoint时长、影响state大小)

定位反压节点:禁用任务链,方便排查定位到具体算子


原因及处理:
        同一个Task中不同SubTask的BackPressure
        现象:有红有绿  ==> 原因:数据倾斜 ==> 解决:第四章
        现象:全红 ==> 看busy
                繁忙 ==> 原因:资源不足 ==> 解决:调整资源
                不繁忙 ==> 原因:与外部交互 ==> 解决:加缓存Cache、异步IO

四)数据倾斜(重点)

数据倾斜不一定产生反压
        keyBy前:
                原因:一个并行度消费一个分区的数据 上游source分区中本身就是数据倾斜
                解决:使用rebalance重分区(全局轮询)
        keyBy后的聚合/窗口操作:
                直接聚合:
                        加随机数实现双重聚合(× 来一条输出一条)
                        预聚合(√)==> 状态编程+定时器
                开窗聚合:
                        加随机数实现双重聚合(√ 一个窗口输出一次 第一次开窗聚合后要添加窗口信息作为第二次分组条件)
                        预聚合(× 丢失了时间,丢失了数据条数)

五)Job优化

5.1 算子指定UUID(重点)

严格地说,仅需要给有状态的算子设置就足够了

但因为Flink的某些内置算子(如window)是有状态的,而有些是无状态的,可能不清楚哪些有状态的哪些没有

所以从实践经验上来说,建议每个算子都指定上 UUID

.uid("").name("")
5.2 链路延迟测量(不常用)

flink本身监控:不与数据库交互或维表关联时,延迟100ms以下(开窗时间另算)

开启参数:

metrics.latency.interval: 30000    #默认0,表示禁用,单位毫秒

metrics.latency.granularity: operator  #默认operator

5.3 开启对象重用(存在风险)

给下游发送地址值

必须要确保下游Function只有一种,或者下游的Function均不会改变对象内部的值,否则可能会有线程安全的问题

env.getConfig().enableObjectReuse();

5.4 细粒度滑动窗口优化

细粒度滑动窗口:窗口大小远远大于步长

重叠的窗口过多,一个数据会属于多个窗口,性能会急剧下降

解决:滚动窗口+在线存储+读时聚合

六)FlinkSQL调优

FlinkSQL官网配置参数:

//nightlies.apache.org/flink/flink-docs-release-1.13/docs/dev/table/config/

6.1 设置空闲状态保留时间TTL(重点)

#API指定
tableEnv.getConfig().setIdleStateRetention(Duration.ofHours(1));

#参数指定

Configuration configuration = tableEnv.getConfig().getConfiguration();

configuration.setString("table.exec.state.ttl", "1 h");

// 指定时区

configuration.setString("table.local-time-zone", "Asia/Shanghai");

6.2 开启MiniBatch

MiniBatch:微批处理,缓存一定的数据后再触发处理,以减少对State的访问,从而提升吞吐并减少数据的输出量

// 开启miniBatch

configuration.setString("table.exec.mini-batch.enabled", "true");

// 批量输出的间隔时间

configuration.setString("table.exec.mini-batch.allow-latency", "5 s");

// 防止OOM设置每个批次最多缓存数据的条数,可以设为2万条

configuration.setString("table.exec.mini-batch.size", "20000");

适用场景:聚合,增加延迟换取高吞吐

6.3 开启LocalGlobal

前提是开启MiniBatch

// 开启LocalGlobal

configuration.setString("table.optimizer.agg-phase-strategy", "TWO_PHASE");

相当于预聚合

6.4 开启Split Distinct

去重,手动改写为两层聚合(增加按Distinct Key取模的打散层)

Split Distinct和LocalGlobal的原理对比

// 开启Split Distinct

configuration.setString("table.optimizer.distinct-agg.split.enabled", "true");

// 第一层打散的bucket数目

configuration.setString("table.optimizer.distinct-agg.split.bucket-num", "1024");

6.5 多维DISTINCT 使用Filter(特定语法优化)

CASE WHEN语法

SELECT
 a,
 COUNT(DISTINCT b) AS total_b,
 COUNT(DISTINCT CASE WHEN c IN ('A', 'B') THEN b ELSE NULL END) AS AB_b,
 COUNT(DISTINCT CASE WHEN c IN ('C', 'D') THEN b ELSE NULL END) AS CD_b
FROM T
GROUP BY a

在上面的示例中,三个COUNT DISTINCT都作用在b列上,此时,经过优化器识别后,Flink可以只使用一个共享状态实例,而不是三个状态实例,可减少状态的大小和对状态的访问

将上边的CASE WHEN替换成FILTER后

SELECT
 a,
 COUNT(DISTINCT b) AS total_b,
 COUNT(DISTINCT b) FILTER (WHERE c IN ('A', 'B')) AS AB_b,
 COUNT(DISTINCT b) FILTER (WHERE c IN ('C', 'D')) AS CD_b
FROM T
GROUP BY a

七)常见故障排除

7.1 非法配置异常

异常:从TaskExecutorProcessUtils 或 JobManagerProcessUtils抛出的IllegalConfigurationException

原因:通常表明存在无效的配置值(例如负内存大小、大于 1 的分数等)或配置冲突

解决:重新配置内存参数

7.2 内存
1)Java堆空间异常

异常:OutOfMemoryError:Java heap space

原因:通常表示JVM Heap太小

解决:可以尝试通过增加总内存来增加JVM堆大小,也可以直接为TaskManager增加任务堆内存,或为JobManager增加JVM堆内存,在确定Flink框架本身需要更多内存时还可以为TaskManagers增加框架堆内存

2)直接缓冲存储器异常

异常:OutOfMemoryError:Direct buffer memory

原因:通常表示JVM直接内存限制太小或存在直接内存泄漏

解决:检查用户代码或其他外部依赖项是否使用了JVM直接内存,以及它是否被正确考虑,可以尝试通过调整直接堆外内存来增加其限制

3)元空间异常

异常:OutOfMemoryError:Metaspace

原因:通常表示JVM元空间限制配置得太小

解决:加大JVM元空间TaskManagers或JobManagers选项

4) 网络缓冲区数量不足

异常:IOException: Insufficient number of network buffers

原因:通常表示配置的网络内存大小不够大

解决:增加网络内存

5)超出容器内存异常

异常:Flink 容器尝试分配超出其请求大小(Yarn或Kubernetes)的内存

原因:没有预留足够的本机内存

解决:调整JVM OverHead内存

7.3 Checkpoint
1)Checkpoint Decline

异常:当前task接收到上游发送过来的barrierCancel消息,从而取消了对应的Checkpoint

从 jobmanager.log 中看到类似下面的日志:

execution 被调度:

Decline checkpoint 10423 by task 0b60f08bf8984085b59f8d9bc74ce2e1 of job 85d268e6fbc19411185f7e4868a44178. 

Checkpoint Cancel:

当前 Flink 中如果较小的 Checkpoint 还没有对齐的情况下,收到了更大的 Checkpoint,则会把较小的 Checkpoint 给取消掉

$taskNameWithSubTaskAndID: Received checkpoint barrier for checkpoint 20 before completing current checkpoint 19. Skipping current checkpoint.

在下游 task 收到被 cancelBarrier 的时候:

DEBUG
$taskNameWithSubTaskAndID: Checkpoint 19 canceled, aborting alignment.

或者
DEBUG
$taskNameWithSubTaskAndID: Checkpoint 19 canceled, skipping alignment.

或者
WARN
$taskNameWithSubTaskAndID: Received cancellation barrier for checkpoint 20 before completing current checkpoint 19. Skipping current checkpoint.
2)Checkpoint Expire

异常:Checkpoint 由于超时而失败

Checkpoint 1 of job 85d268e6fbc19411185f7e4868a44178  expired before completing.

3)Checkpoint 慢

异常:Checkpoint interval 1分钟,超时10分钟,Checkpoint经常需要做 9 分钟(我们希望1分钟左右就能够做完)

原因及解决:

  1. ① Source Trigger Checkpoint 慢

  2. 原因:source 做snapshot并往下游发送barrier的时候,需要抢锁,一直抢不到锁的话,可能导致Checkpoint一直得不到机会进行

  3. 解决:通过 jstack 进行进一步确认锁的持有情况

② 使用增量checkpoint

原因:仅在 RocksDBStateBackend 中支持增量 Checkpoint

解决:如果使用 RocksDBStateBackend,可以通过开启增量 Checkpoint 来加速

③ 作业存在反压或数据倾斜

原因:task 仅在接受到所有的barrier之后才会进行snapshot,如果作业存在反压,或者有数据倾斜,则会导致全部的channel或者某些channel的barrier发送慢,从而整体影响Checkpoint 的时间

解决:见反压、数据倾斜

④ barrier对齐慢

原因:taskmanager.log 中没有日志

DEBUG
Starting checkpoint (6751) CHECKPOINT on task taskNameWithSubtasks (4/4)

解决:检查日志,了解哪些上游的 barrier 没有发送下来

⑤ 主线程太忙导致没机会做snapshot

原因:在 task 端,所有的处理都是单线程的,数据处理和 barrier 处理都由主线程处理,如果主线程在处理太慢(比如使用 RocksDBBackend,state 操作慢导致整体处理慢),导致 barrier 处理的慢,也会影响整体 Checkpoint 的进度

解决:通过火焰图分析

⑥ 同步阶段做得慢

⑦ 异步阶段做得慢

7.4 Kafka动态发现分区

通过 Properties指定参数开启(单位是毫秒):

FlinkKafkaConsumerBase.KEY_PARTITION_DISCOVERY_INTERVAL_MILLIS 

7.5 WaterMark不更新

原因:由于下游算子 watermark 的计算方式是取所有不同的上游并行数据源 watermark 的最小值,则其 watermark 将不会发生变化,导致窗口、定时器等不会被触发

解决:使用 WatermarkStrategy 来检测空闲输入并将其标记为空闲状态

.withIdleness(Duration.ofMinutes(5))

7.6 依赖冲突

异常:ClassNotFoundException/NoSuchMethodError/IncompatibleClassChangeError/...

原因:用户依赖第三方包的版本与Flink框架依赖的版本有冲突

解决:根据报错信息中的类名,定位到冲突的jar包,idea可以借助maven helper插件查找冲突的有哪些,打包插件建议使用maven-shade-plugin

7.7 超出文件描述符限制

异常:java.io.IOException: Too many open files

原因:超出文件描述符限制

解决:检查Linux系统ulimit -n的文件描述符限制,再注意检查程序内是否有资源(如各种连接池的连接)未及时释放

低版本Flink使用RocksDB状态后端也有可能会抛出这个异常,此时需修改flink-conf.yaml中的state.backend.rocksdb.files.open参数,如果不限制,可以改为-1(1.13默认就是-1)

7.8 脏数据导致数据转发失败

异常:org.apache.flink.streaming.runtime.tasks.ExceptionInChainedOperatorException: Could not forward element to next operator

原因:程序业务逻辑有误,或数据流里存在未处理好的脏数据

解决:继续向下追溯异常栈一般就可以看到具体的出错原因,比较常见的如POJO内有空字段,或者抽取事件时间的时间戳为null

7.9 通讯超时

异常:akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://...]] after [10000 ms]

原因:集群负载较大、网络拥堵,或业务逻辑同步调用耗时的外部服务

解决:调大akka.ask.timeout参数的值(默认只有10秒),调用外部服务时尽量异步操作(Async I/O)

7.10 其他错误

Flink on YARN(下):常见问题与排查思路-阿里云开发者社区

发现问题:
prometheus:监控
grafana:可视化展示&告警
之后通过webUI定位问题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值