用分桶解决动态分区最后一轮reducer数量过少导致运行缓慢问题。

场景

动态分区时,最后一轮reduce会按照字段的值作为key去分发数据到不同的reducer,但是如果分区值的数量过少,就会导致严重的数据倾斜。运行时间过长。

任务growth.m_device_impression.sql中,由于p_app_name是分区字段,而目前只有三个可能的值,所以最后一轮按key分发任务时,只有三个reducer。其中某个值的那个reducer要跑一个小时。这是由于数据倾斜导致的任务满问题。

-- 简化版sql
USE growth;
CREATE TABLE IF NOT EXISTS m_device_impression
(
  platform_type STRING,
  device_id BIGINT
  impression BIGINT,
)
PARTITIONED BY (p_date STRING,  p_app_name STRING)
--CLUSTERED BY(device_id) INTO 30 BUCKETS
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS
  INPUTFORMAT "org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat"
  OUTPUTFORMAT "org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat"
;
SET hive.exec.dynamic.partition=true; 
SET hive.exec.dynamic.partition.mode=nonstrict;
  
--set hive.enforce.bucketing=true;
 
--行为数据;
INSERT OVERWRITE TABLE m_device_impression PARTITION(p_date = "DATA_DATE",  p_app_name)
SELECT
platform_type AS platform_type,
  CASE WHEN device_id=0 THEN app_device_id ELSE device_id END AS device_id,
SUM(impression) AS impression,
FROM
default.impression_stats_daily 
GROUP BY
  platform_type,
  CASE WHEN device_id=0 THEN app_device_id ELSE device_id END,
  p_app_name 

解决方案

    使用分桶,按照某个key(比如device_id)来做分桶,那么在每个动态分区(app_name)中内都会再次细分,于是reducer的数目就不会仅仅只有三个(app_name的枚举个数)。

    重新建表,添加

CLUSTERED BY(device_id) INTO 30 BUCKETS

    然后重新拉取数据,添加:

set hive.enforce.bucketing=true;
 tips:动态分区请参考链接: HIve动态分区实战



你可能感兴趣的:(Hive)