当前位置:   article > 正文

hive十亿级以上数据全局排序的一种实现方式_hvie处理十亿数据排序问题

hvie处理十亿数据排序问题

背景

大数据时代,日常工作中经常会处理数以亿计的数据。
笔者近期就遇到了一个十亿级以上的数据排序需求,并输出序号。
如果是小规模数据我们直接使用row_number全局排序就可以了,但是当数据规模达到十亿或者以上时,直接使用row_number肯定是不太现实。
因为全局排序的时候变成了单节点任务,要么超内存,要么就超时。

经过几轮调试,问题解决了,并且性能还不错,笔者把处理这个问题的思路与解决方案分享出来与网友交流学习。

解决过程

目标全局排序15亿条记录,排序字段是一个概率分(分值在0-1之间)。
由于直接使用row_number肯定不能解决。大数据处理还是需要分布式的思想,笔者首先想到的是根据数据大小对数据进行分段排序,然后在合并逐段的排序结果形成全局排序结果(归并排序的一种特殊形式)。
因为有15亿数据,分成1000段,平均每个reduce处理150W。
想好了,直接写代码开干。

with t1 as
(
    select id,p,ceil(p*1000) as sub_level, 
    row_number() over(partition by ceil(p*1000) order by p) as sub_order
    from table_source
),
t2 as (
    -- 获取每个分桶的起始排序(使用sum over累加计算得出的当前分桶与比他小的分桶累计了多少条记录)
    select sub_level,(sum(cnt) over(order by sub_level) - cnt) as base_order
    from  
    (
    	-- 获取每个分桶的数量
        select sub_level,count(1) as cnt
        from t1
        group by sub_level
    ) t
)
-- 起始排序 + 组内排序就是全局排序
select id,p,base_order + sub_order as global_order
from t1
left join t2 on t1.sub_level = t2.sub_level
;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

由于数据分布不均匀,上面的代码运行直接部分节点爆内存了。
那么就粗暴的加大分桶数量直接到5000(把上面代码中的1000修改成5000),再运行就成功了。
但是耗时4800s。相对较长,分析发现主要是分桶不均匀导致长尾效益。

这种粗暴的分桶方式对于数据分布比较均匀的场景比较适合,但是对于数据分布不均匀的场景可能就比较低效。
那么我们该怎么优化一下呢?

优化过程

由于问题是数据分桶不均匀导致的,那么我从分桶均的角度来解决。

  • 首先查看排序数据的分布
select ceil(p*1000) as sub_level, count(1)
from table_source
group by ceil(p*1000)
order by 2 desc;
  • 1
  • 2
  • 3
  • 4

根据结果发现数据在四个区间分布比较
(0,0.05] 分布占大部分
(0.05,0.056]分布比较密集
(0.057,0.061]分布高度密集
(0.061,0.15)分布较少
我们根据这个4个区间的数据量分布进行定值化分段,让分桶尽量均匀。

定制化分段后的sql如下,

with t0 as (
    select id, p,
    case 
        when p <= 0.05 then ceil(600 * (p-0.0) / (0.05-0.0))
        when p <= 0.056 then 600 + ceil(400 * (p-0.05) / (0.056-0.05))
        when p <= 0.061 then 800 + ceil(200 * (p-0.056) / (0.061-0.056))
        else 1201
    end as sub_level
    from table_source
),
t1 as
(
    select id,p,sub_level, 
    row_number() over(partition by sub_level order by p) as sub_order
    from t0
),
t2 as (
    select sub_level,(sum(cnt) over(order by sub_level) - cnt) as base_order
    from  
    (
        select sub_level,count(1) as cnt
        from t1
        group by sub_level
    ) t
)

select id,p,base_order + sub_order as global_order
from t1
left join t2 on t1.sub_level = t2.sub_level
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

这个sql相对之前粗暴分段的方式数据分布均匀多了,性能也大大提升。耗时不到原来的一半。

结语

  • 1.大数据处理任何时候都要有分布式处理的思想,避免把分布式问题变成单机任务的场景。
  • 2.分布式任务要尽量保证数据分布均匀,不均匀分布的数据任务就会出现长尾,导致任务耗时长,且容易单节点内存超限。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/486396
推荐阅读
相关标签
  

闽ICP备14008679号