声明: 1. 本文为我的个人复习总结, 并那种从零基础开始普及知识 内容详细全面, 言辞官方的文章
              2. 由于是个人总结, 所以用最精简的话语来写文章
              3. 若有错误不当之处, 请指出

一、背压机制:

下游处理数据 处理不过来时, 会使上游降低发送数据的速度

产生的原因:

  1. 系统资源不足
  2. 频繁发生GC, 导致经常暂停应用程序
  3. 数据倾斜
    这个发生数据倾斜的分区处理数据 处理不过来
  4. 外部依赖
    Source端 和 Sink端 读写性能太差

二、数据倾斜:

流式数据 不开窗的话是没法预聚合的

keyBy之前:

问题: Kafka有的分区数据量多, 有的分区数据量低

解决: Flink消费数据时使用rebalance算子将数据均匀分配

keyBy之后:

使用两阶段聚合:

非窗口聚合:

第一阶段进行拼接 随机数 进行部分聚合, 第二阶段去掉 拼接的随机数 进行最终聚合

窗口聚合:

第一阶段进行拼接 随机数 & WindowEndTime 进行部分聚合, 第二阶段去掉拼接的随机数, 然后groupBy WindowEndTime进行最终聚合

keyBy之后非窗口聚合操作:

问题:

需求: 计算hello的个数

现有4个hello, 拼接随机数后发往两个分区:

第一阶段: 1号分区为(hello_1,1),(hello_1,2), 2号分区为(hello_2,1),(hello_2,2)

第二阶段: 去掉拼接的随机数后, 得到数据(hello,1),(hello,2), (hello,1),(hello,2)

可见输入的数据并没有减少 & 数据被重复计算了

解决:

使用LocalKeyBy的思想, 自己维护一个状态, 使聚合后只返回一条数据;

那样第二阶段去掉拼接的随机数后 得到的数据就是 (hello,2),(hello,2)

keyBy之后窗口聚合操作:

第一阶段: 1号分区为(hello_1_WindowEndTime,1),(hello_1_WindowEndTime,2),

2号分区为(hello_2_WindowEndTime,1),(hello_2_WindowEndTime,2)

第二阶段: 得到数据(hello_1_WindowEndTime,2),(hello_1_WindowEndTime,2),

去掉拼接的随机数, 然后groupBy WindowEndTime即可得到每个窗口的hello个数聚合值

三、FlinkSQL调优:

分组聚合优化:

  1. 开启MiniBatch微批处理, 提升吞吐量
  2. 开启LocalGlobal(需要先开启MiniBatch), 处理热点数据问题(LocalKeyBy的思想)
  3. 开启Split Distinct
    count(distinct 热点数据) 的效果并不好, 而split distinct底层做了优化
    split distinct的原理(手动实现):
-- 两阶段聚合
select day, sum(cnt)
from (
    select day, count(distinct user_id) as cnt
    from t
    group by day, mod(hash_code(user_id), 1024)
)
group by day
  1. 使用filter 代替 case when, filter底层做了优化

TopN优化:

  1. 使用最优算法
    两个条件:
  1. 有主键
  2. 排序字段的更新是单调的, 且排序方向与单调方向相反
    例如count是递增的, 同时使用递减排序 order by count desc
  1. 增大Cache内存大小, 提高缓存命中率, 减少访问磁盘的次数

高效去重方案:

保留首行

  • 如果要是取第一, 就使用rank后取第一行数据
  • 如果要是取倒数第一, 就使用rank desc后取第一行数据

这样只保留一条数据即可, 不用保留n条数据