sparkstreaming性能调优记录

场景:
RDD<JSONObject>,JSONObject里面有TBNAME字段和PAYLOAD字段,分别代表表名和原始日志内容
需要1.在原始内容里加入系统时间字段 2.按表名取系统时间逆序取前100条入库
30s时间窗口,处理2w条数据;4张表,但打的数据均为1张表的数据
以下我说明的时间都是有数据的表的处理时间(1张表有数据处理,在过其他表时也需要filter表名,需要耗时;所以总体的批处理时间会比我描述的时间要大)


资源:executor-cores:4,core-memory:2g,driver-memory:512m(没办法,资源要省着用,目前这个资源对运行环境而言已经算奢侈了)

PS:机器为虚拟机,所以这里的核的计算能力与实体机的计算能力是不能相提并论的(是一台实体机虚拟了5个虚拟机组装的集群)



a.实现方式
for循环表名->按表名filter->并map(取PAYLOAD字段)->takeOrder(num[取的条数],comparator[按时间逆序])
结果:27~30+s


b.实现方式
filter(按需要取的所有表名)->mapToPair(Tuple2<表名,PAYLOADJSONObject[已经加上系统时间字段]>)->groupByKey(得到JavaRDD<表名,Iterator>)->mapToPair(从Iterator取出JSONObject按系统时间排序,sublist得到需要的数目的JSONObject)->collectMap
结果:会导致Java Heap OutOfMemory


c.实现方式
filter(按需要取的所有表名)->mapToPair(Tuple2<表名,PAYLOADJSONObject[已经加上系统时间字段]>)->for循环表名->JavaPairRDD按key filter->map只取value返回,得到JavaRDD<JSONObject[PAYLOAD]>->takeOrder
结果:47~1min+


以上RDD均是JavaRDD<JSONObject>或者JavaPairRDD<String,JSONObject>


d.实现方式
filter(按需要取的所有表名)-> 并map(取PAYLOAD字段;组成string:tablaname#systemtime#BASE64.encode(JSONSTRING)(PAYLOAD含有SYSTEM字段),成为JavaRDD<byte[]>)->for表名->filter(按#第一个字段过滤)->takeOrder(按#第二个字段排序)->得到前100的list->按#第三个字段生成List<JSONObject>
场景: 11w+数据量(应该是之前数据量的5、6倍),处理时间 几秒~十几秒


虽然有本质的提高,但目前仍不满足要求;还应该继续调试


e.实现方式(采用d的实现方式的基础上),同时再进行优化
我们job使用的cores和kafka的partition的数目相差比较大,cores=4,parttions=16
所以考虑在DStream transform时,对于rdd进行coalesce(cores,false)---即对rdd进行重新分区保证和cores数目相同,而且shuffle=false,因为是partition的合并,不需要shuffle

场景:11w+数据量(应该是之前数据量的5、6倍),处理时间 5秒~7秒;此时记录批处理时间比较有意义,批处理时间为11~15左右(4张表)


另外,还尝试了用多线程分别过滤4张表,takeOrder并入库;但由于机器的cores计算能力并不强,所以反而在并发执行时每个JOB的执行时间变长,并发执行完的整体时间和目前的运行整体时间差不多。所以在cores不多,且机器运算能力不强的情况下,不考虑使用此方法。

真实场景下数据会分散多个表的数据,每个Job的压力会相应减少,运行时间会比较目前的运行时间短。总体时间也许短或者与现在一致。


f.实现方式(在d+e的基础上)
mapPartitions(得到的Iterator按表名过滤,并取每张表时间最新的100条放入list中)[理论上每张表的100条应该就等于表在每个分区最新100条再取100条]->for循环->filter(按#第一个字段过滤)->takeorder(按第二个字段排序)->得到前100的list->按#第三个字段生成list<JSONObject>
目前实验结果中f方式最好,第一张表的时间较长需要7~9秒,2,3,4表在persist的基础上取都花费毫秒级的时间,所以总处理时间10秒左右


总结一下:
1.每个表的最新一百条,等于这个表在每个分区上取最新一百条之后的集合中再取一百条;这样就可以降低后面filter和takeorder的数据量
2.JavaRDD<JSONObject>序列化/反序列化代价很大,能用JavaRDD<byte[]>尽量用
3.如果core比较少且core计算能管理不强,缩小分区数目减少任务数;因为一个core并发运行多个任务,线程之间的切换也会造成耗时


重大发现,之前persist RDD时的触发action是isempty,isempty判断会短路判断(比如第一个分区有数据就不再继续往下判断),那么RDD persist的只有1个分区,时间又长,而且不是全部分区能够被后续复用;改为rdd.count()==0,判断完成后,RDD的4个分区均可以被复用。后面的takeorder job在使用f方法的情况下4个加起来耗时1秒左右。非常振奋人心,不仅减少了实时监控的耗时,而且这个RDD还可以被后面的气泡图和黑白灰用。

截图留念:


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值