屠龙记
我是一个正经的大龄c#程序员,突然接到了一个大数据报表需求,开发语言python,框架pyspark,脚本运行环境juypter.
需求是这样的:
工厂有很多生产线,每个生产线都有一套工序,每个工序都要扫码,我的任务就是得到工序之间的时间差,计算一个叫leadtime的指标,分析每条产线的哪个环节耗时比较多。
工厂每天大概扫码1000w左右,所有扫码信息都存在一个pg数据库的一个表里面,格式大概为一个编码列,一个json列。编码列主要存储玻璃码信息,json列里面含有各种信息需要提取。数据库尺寸非常庞大,会定期做归档。
一个产线的扫码大致是这样的,白片阶扫白片码,镭码工序有白片码和成品码,成品阶之后只扫成品码。意思就是说一个产品线的工序之间没有一个码贯穿,必须通过镭码工序衔接。当然这是典型的情况,也有其它情况。
拿到这个需求,头很大,有没有。公司要求2个月搞定,慌不慌?
既来之则安之。
python不会怎么办,恶补,spark不会怎么办,现找资料。以上工作大概2周弄了个大概,开干。
大致理了一下思路:
1把数据同步到ods层(hive)
2清洗json,提取白片码,成品码,工序,产品线,扫码时间等关键信息(dwd层)
3dws层,这层很头疼,到底该如何计算?如何存储?
4dm层,好像没啥太大难度
5报表绑定,也很容易
问题主要就卡在第三步,如此大的数据量算两两之差到底盖如何设计表?
找了几个程序员头脑风暴了一番,感觉都没啥好的思路,能说服我就那样或者这样干。都把它当成在sql数据库的常识来看待问题了,如何设置主键,设置索引,如何分区,同事们想到的大多是一行一个码,工序,时间,产线。转码如何从头到尾关联,数据量如此庞大如何处理?关于计算方面,也没啥好的建议,反正比较乱,感觉不靠谱。既然都没有这方面经验借鉴,看来还得自己努力!
思索几天,突然灵光一闪,列式存储。数据行数将大大减小。虽然每个产品线的工序数量不一样,但是完全可以做点冗余,工序默认30列,那么差值就是29列。这样既方便计算又方便检验。
工序如何和列名对应呢?首先列名肯定不能是工序名,工序名是配置的,不固定,肯定不行。然后是如何体现工序的顺序呢?思来想去一个想法涌现出来:工序列就叫p1,p2,p3,差值列叫diff1,diff2...,后面再根据工序,产线配置表确定p1,p2是什么意思。
接着是下一个问题,码到底应该如何处理?特别是转码,如何像糖葫芦一样形成一个串?
只存白片码?只存成品码?白片成品都存?hive还是kudu?一时之间不好定夺。既然不好定夺,那就撸起代码再说。三套方案:
1hive表存,假设hive sql非常强大,直接sql join搞定
2hive表存,假设spark join运算能力优秀,搞定
3kudu表,做upsert操作(根据主键做insert或者update)
代码1 方案1思路,上sql,实验直接报废,join太多,第一个工序和最后一个工序的时间差值可能很大,数据量太大,直接能跑死
代码2 方案1思路,sql结合spark编程,虽然对过程做了一些分解,依然算死
代码3 全spark写法,依然被斩落马下
.
.
.
代码m 依旧没能成功
虽然没成功,却积累了很多经验。所谓大数据平台,所谓map计算,也不是吊炸天的存在!必须对任务进行友好划分,任务大小需要均匀分布才有可能打开成功的门。
有了前面的积累开始卷土重来,开始实验方案3,写了4个版本之后,第5个版本终于迎来了曙光,能跑出数据来了!虽然能跑出数据,耗时却很高,另外一个问题就是cpu被我的程序抢太多了,其它程序运行不好。这时候ai发挥了强大这时ai起到了很大作用,对着ai一大堆灵魂拷问,终于调对了spark参数,问题基本得到解决。(ai还不是特别精确,经常会给出错误的东西,所以还是需要不断尝试)