大数据处理中的隐藏杀手 —— 数据倾斜,你了解多少?

在大数据的广袤世界里,我们怀揣着让数据创造价值的美好愿景,构建起复杂而庞大的数据处理系统。但在这看似有序的数字宇宙中,数据倾斜如同隐藏在暗处的杀手,悄然威胁着系统的高效运行。今天,就让我们一同揭开数据倾斜的神秘面纱,深入了解它的表现、成因以及应对之策。​

一、数据倾斜的表现​

数据倾斜,简单来说,就是数据分布不均匀,大量数据集中到一点,形成数据热点的现象。在分布式计算框架(如 Hadoop、Spark)和分布式数据库(如 Hive、HBase)中,这一问题尤为常见。其具体表现如下:​

1.1 任务进度异常​

在任务执行过程中,你可能会发现任务进度长时间维持在 99% 或者 100% 附近,仿佛陷入了无尽的等待。查看任务监控页面,会惊讶地发现只有少量 reduce 子任务未完成,而它们处理的数据量与其他 reduce 子任务相比,简直是天壤之别。就像一场马拉松比赛,大部分选手都已冲过终点,只有寥寥几个还在遥远的赛道上艰难跋涉,严重影响了整个比赛的结束时间。​

1.2 处理时间失衡​

单一 reduce 处理的记录数和平均记录数相差巨大,通常能达到好几倍之多。而且,其最长处理时间远大于平均时长。这就好比一个班级里,大部分学生都能在规定时间内完成作业,而个别学生却需要花费数倍的时间,不仅拖慢了自己的学习进度,也影响了整个班级的教学节奏。在数据处理中,这种时间失衡会导致整个任务的执行效率大幅降低,消耗更多的资源和时间成本。​

二、数据倾斜出现的原因​

数据倾斜的根本原因,是大量相同的 key 被分配到一个 reduce 里,使得一个 reduce 任务不堪重负,而其他 reduce 任务却闲置一旁,无事可做。这就像一场接力赛,所有的接力棒都集中在了一个选手手中,他累得气喘吁吁,而其他选手只能眼巴巴地看着,无法发挥自己的作用。下面,我们来详细探讨常见的数据倾斜原因。​

2.1 数据类型不一致造成的数据倾斜​

在数据的世界里,数据类型就如同人们的语言,如果交流双方使用不同的语言,就会出现沟通障碍。数据类型不一致也是如此,它可能引发数据倾斜的问题。例如,用户表 users 中 user_id 字段为 int 类型,而 logs 表中 user_id 字段为 string 类型。当对这两张表进行关联操作时,由于数据类型的差异,它们可能无法正确匹配,导致大量数据被错误地分配到同一个 reduce 中,从而引发数据倾斜。这就好比将来自不同国家、说着不同语言的人聚集在一起,却没有提供翻译,交流自然会陷入混乱。​

解决方法:将数据类型转成一致的。在进行关联操作前,仔细检查相关字段的数据类型,确保它们一致。可以使用数据转换函数,将不同类型的字段转换为相同类型,消除因数据类型不一致带来的隐患。​

2.2 数据中出现大量 null 值​

数据中的 null 值就像隐藏在黑暗中的幽灵,可能会对数据处理产生意想不到的影响。在数据倾斜问题上,null 值主要分为两种情况。​

2.2.1 null 是异常值​

当 null 值是异常值,不应该出现时,比如 userId 出现 null。这种情况下,如果不需要这些异常值,最好在 left join 前直接在 where 条件里过滤掉。这样做不仅可以避免数据倾斜,还能大大减少计算量,提高数据处理的效率。就像在整理书架时,发现一些破损、无用的书籍,直接将它们清理出去,书架会变得更加整洁,查找书籍也会更加方便。​

2.2.2 null 是正常数据​

当出现 null 的数据不是异常数据,而是需要保留的正常数据时,问题就变得有些棘手了。由于某个 key 为空对应的数据很多,且必须包含在 join 的结果中,此时我们可以给表中 key 为空的字段赋一个随机的值,使得数据随机均匀地分布到不同的 reducer 上。这就好比在分配任务时,对于那些没有明确负责人的任务,随机指定一个人来承担,从而避免所有任务都堆积在一处。​

2.3 单表 group by 出现数据倾斜​

在单表进行 group by 操作时,数据倾斜也可能悄然降临。导致这种情况的主要原因在于按照 Key 分组以后,少量的任务负责绝大部分数据的处理。想象一下,一个班级里,老师让同学们分组讨论问题,结果大部分同学都集中在少数几个小组,这几个小组的讨论压力巨大,而其他小组却冷冷清清,效率自然无法得到保障。​

2.3.1 解决方案一:使用参数优化​

当任务中存在 group by 操作,同时聚合函数为 sum 或者 count 时,可以通过设置参数来处理数据倾斜的问题。在 Hive 中,可以设置以下参数:​

-- 设置在map端进行聚合​

set hive.map.aggr = true;​

-- 设置在map端进行聚合操作的条目数目​

set hive.groupby.mapaggr.checkinterval = 100000;​

-- 有数据倾斜的时候进行负载均衡(默认是false)​

set hive.groupby.skewindata = true;​

开启负载均衡后,会生成两个 MRJob。第一个 MRJob 让 map 输出的结果随机分布到 reducer 中进行部分聚合,这样相同的 key 可能会分发到不同的 reduce 中,从而实现负载均衡;第二个 MRJob 根据第一个 MRJob 的结果,将相同的 key 分布到同一个 reduce,完成最终的聚合。这就好比在一场接力赛中,先让选手们随机分组进行初步的接力,减轻单个选手的负担,然后再根据最终的分组情况,进行正式的接力比赛,确保比赛的公平性和高效性。​

2.3.2 解决方案二:增加 reduce 的数量​

当数据中的多个 key 同时导致数据倾斜时,可以通过增加 reduce 的数量来解决问题。这就好比在班级分组讨论时,增加小组的数量,让同学们能够更加均匀地分布在各个小组中,每个小组的讨论压力就会相应减小,讨论效率也会提高。在实际操作中,可以根据数据量和集群的资源情况,合理调整 reduce 的数量,以达到缓解数据倾斜的目的。​

2.4 多表 join 出现的数据倾斜​

在多表 join 的复杂操作中,数据倾斜更是如影随形,给数据处理带来了诸多挑战。​

2.4.1 解决方案一:使用参数解决​

在编写 join 语句时,如果确定是 join 出现的数据倾斜,可以使用参数来解决。在 Hive 中,可以通过设置以下参数来优化:​


-- join的键对应的记录条数超过这个值则会进行拆分,值根据具体数据量设置​

set hive.skewjoin.key = 100000;​

如果开启了该参数,在 Join 过程中,Hive 会将计数超过阈值 hive.skewjoin.key(默认 100000)的倾斜 key 对应的行临时写进文件中,然后再启动另一个 job 做 map join 生成结果。通过 hive.skewjoin.mapjoin.map.tasks 参数还可以控制第二个 job 的 mapper 数量,默认 10000。这就好比在处理大量货物时,对于那些体积特别大、难以搬运的货物,先将它们单独存放,然后再用专门的工具和人员进行处理,以提高整体的搬运效率。​

2.4.2 解决方案二:大小表 join​

当进行大小表 join 时,可以使用 MapJoin。将小表写在 join 的左边,大表写在 join 的右边,这样 sql 语句会只走 mapJoin,没有 reduce 阶段,自然也就不会出现数据倾斜的问题。此外,还可以采用大表打散小表扩容的手段来解决。例如,将小表的数据进行复制和扩展,使其与大表的数据量更加匹配,然后再进行 join 操作,这样可以减少数据倾斜的可能性。这就好比在拼图游戏中,将小块的拼图进行适当的复制和调整,使其与大块的拼图更好地拼接在一起,从而完成整个拼图。​

2.4.3 解决方案三:大表大表 join​

当遇到两个大表 join 的情况时,可以使用 SMB join 来解决。SMB join(Sort - Merge - Bucket Join)是一种基于分桶和排序的连接算法,它通过对两个大表进行分桶和排序,然后在 map 阶段进行数据的匹配和连接,避免了在 reduce 阶段进行大量的数据传输和处理,从而有效地解决了大表 join 时的数据倾斜问题。这就好比在两个大型仓库中寻找匹配的货物,通过对货物进行分类和排序,然后在各自的仓库中进行匹配,大大提高了寻找货物的效率。​

三、总结与展望​

数据倾斜作为大数据处理中的一大难题,给我们的工作带来了诸多挑战。但通过深入了解其表现和成因,并掌握相应的解决方法,我们便能在数据的海洋中破浪前行。在实际工作中,我们要时刻保持警惕,对数据进行仔细的分析和预处理,合理运用各种优化手段,避免数据倾斜的发生。同时,随着技术的不断发展,相信会有更多更高效的解决方案出现,帮助我们更好地应对数据倾斜这一挑战,让大数据真正为我们创造价值。希望本文能为你在数据处理的道路上提供一些帮助,让我们一起在大数据的世界里探索前行!

你可能感兴趣的:(大数据,数据分析,sql,hive)