0x01
今天,由于公司要进行新老数据仓库的迁移,于是顺便接手了其中一部分的工作,其实大部分迁移工作都比较简单,就是把从ods层-dw层-dm层-sh展示层中涉及到旧仓库的表替换成新仓库的表,并且检查其中字段的差异性,并进行相应的操作。于是撸起袖子开工。
0x02
- 前期的进展很顺利,很快就完成了几张表的迁移,心想着按这个进度,不到一个小时就能完成了。Orz
- 在进行到第五张表的迁移时,发现很久没有完成,于是检查了日志,发现卡在了reduce阶段,从60%作用开始,基本上每隔10分钟左右进度才增加1%。
- 遇到这种情况,第一反应就是发生了数据倾斜,于是马上进行数据源的排查,在这里先说明一下查询语句主体,大致如下
select xxx from t1 left join on t2 where t1.sid = t2.sid left join t3 on t1.uid = t3.uid
。其中t2和t3均已经进行了去重和选定分区的处理。 - t1以及t2的数据量在百万级别,t3在亿级别作用。然后对t1进行了count(distinct uid)后,发现了异常数据 null的量在千万级别,于是采取了直接剔除null的解决方案,心想这个应该就不会进行数据倾斜了,于是再次运行脚本,然后等待,结果出乎我的意料,这次没有卡在60%,而是卡在了65%,泪崩啊。
- 再次检查日志,发现reduce个数只有一个,心想大概是hive自动判断reduce个数不准确,于是手动强制设定了reduce的个数
set mapred.reduce.tasks=800;
。再一次运行,等待,60%–70%–80%–90%–95%…,这下终于正常了。…99%–99%–99%–99%…,在看到一连串的99%不断刷新的同时,我终于接受了还有错误的事实。 - 到底哪里出错了呢,按说数据量也并不是特别大呀,想了想,还有一个办法,就是使用
hive.groupby.skewindata=true;
来进行当有数据倾斜时进行负载均衡,其实理性告诉我,和这个关系不大,但是没办法了呀,只能试一下了。结果不出我所料,还是卡在了99%。 - 还有半小时就到饭点了,怎么办,这时候同事对我随口提了一句,检查一下数据类型,说不定是数据类型不一致造成的呢。”不应该呀”,我嘀咕着,抱着死马当活马医的态度,我看了一些表结构,发现还真不一样,t1的是bigint,而t2和t3的是string。但是我记得hive有自动隐式转换机制的呀,为了验证我的观点,我进行了
select cast(1010000001000390061 as bigint) = cast(1010000001000390061 as string)
查询,结果就是返回true,应该不是这个原因。是的。 - 但是也想不到别的办法了,于是再去吃饭之前,我还是提交了这个微小的改动,
cast(t1.sid as string) = t2.sid
,在吃饭的过程中,我一直在想解决的办法,吃完饭回来,奇迹发生了,居然就是这个原因!!! - 突然想起来,之前有过一次,好像也是数据类型的原因,在使用join时,对两个bigint类型和string类型进行等值操作时,乍一看,操作没问题,可是仔细一看,返回的数据不对啊。当时也没注意这个细节。
- 难道是超出了bigint范围?在查询了
select cast(10010000001000390061 as bigint)
后,惊奇的发现居然返回了9223372036854775807,这下明白了,应该是在join时,由于t3的uid字段超出了bigint的范围,从而使得最后的连接后数据量剧增,想一下,百万 * 百万 * 亿 ,大概有10的20次方,难怪卡在了99%。
0xff
- 回顾这一次填坑之旅,不仅意识到了不能完全依赖于平台提供的便利功能,而疏忽了其背后原理性的东西。如自动转换类型的原理,以及相关的限制。
- 对于不同层的表的维度字段的定义,尽量保证维度字段的类型保持一致,不然有可能会出现一些奇怪的问题,比如我这次遇到的由于超出范围而造成自动转换的结果不准确的bug。
- 在遇到问题迟迟不能解决的时候,不妨问问身边的人,俗话说的好,当局者迷,旁观者清嘛。Orz