数据倾斜(Data Skew)
1. 在哪些场景会遇到数据倾斜
- Elasticsearch 聚合查询:某些字段的值高度集中,导致部分分片数据量过大,查询时间变长。
- Kafka 消费端:某些 key 过于集中,导致个别 partition 的消费压力远大于其他 partition。
- 分布式计算(如 Spark/Flink/Hive) :某个 key 频繁出现,导致某个计算节点的数据远多于其他节点,引发计算瓶颈。
2. 数据倾斜的成因
数据倾斜通常是由数据分布不均衡造成的,具体原因包括:
-
Key 值分布不均:
- 例如,在 Spark/Flink 进行
groupBy或join时,如果某些 Key 出现频率远高于其他 Key,就会导致数据集中到某些节点上。 - Elasticsearch 中,基于
term的聚合查询可能会导致某个分片查询压力过大。
- 例如,在 Spark/Flink 进行
-
默认分区策略不合理:
- 例如,Kafka 生产数据时默认使用 Key 进行分区,如果部分 Key 过热,数据会集中到某些分区,导致消费端处理不均衡。
-
数据倾斜导致的计算瓶颈:
- 在 Spark Shuffle 过程中,某个 Task 处理的数据远超其他 Task,导致计算延迟,甚至导致 OOM(内存溢出)。
- 在 Elasticsearch 查询时,部分分片的查询压力远大于其他分片,导致整体查询变慢。
3. 解决方案
不同场景下,数据倾斜的解决方案也不同:
(1)减少 Key 的热点
-
随机前缀/哈希散列:
- 在
groupBy或join之前,给 Key 添加一个随机前缀,增加数据分布的随机性,比如key + random(0, N)。 - 在 Elasticsearch 查询时,可以使用
composite aggregation来避免单个分片负载过高。
- 在
-
热点 Key 拆分:
- 对于极少数高频 Key,可以手动拆分成多个 Key 处理,后续再合并结果。
(2)优化分区策略
-
Kafka 分区优化:
- 采用自定义分区策略,让高频 Key 分散到多个 Partition。
- 增加 Partition 数量,提高并发消费能力。
-
Spark/Flink 数据重分区:
repartition(n):强制数据均匀分布,增加计算节点负载均衡。salting:在 key 上加随机数后groupBy,减少数据热点。
(3)调整计算逻辑
-
本地聚合后再全局聚合:
- 例如在 Spark 计算中,可以先对数据进行 map-side 预聚合,减少数据传输量,然后再进行全局聚合。
- 在 Elasticsearch 里,可以使用
pre-filter方式减少查询范围,降低查询压力。
-
调整 SQL 执行策略:
- 在 Hive 或 SparkSQL 中,可以使用
skew join hint,让 Spark 采用 广播 join(broadcast join)而不是shuffle join,减少数据倾斜的影响。
- 在 Hive 或 SparkSQL 中,可以使用