场景:
一个文件由2672094万条数据,每个数据信息以|分割。例如: 1926717087|1||BOC_EPOS_CREDIT_ZHBZ8011|2014-08-09|1540.00|||1.54||0||||
首先,按“|”把每条数据拆开,分别对每一列进行格式校验,如非空,日期格式,金额格式(小数点两位,非负数)。每条都进行校验。
其次,进行业务校验,校验其是否符合某个规则。每条都需要校验。不合法数量较多,大约三分之一,不合法的数据通过异常返回。
每条进行业务校验的同时,还会返回一些数据,例如,上面一条数据,传过去之后,可能还会返回10个字段的数据。
最后,将不合法的数据插入bad表,将合法的数据插入good表(50多个字段)。
问题:格式校验较快,不到20秒。业务校验比较慢。其中每条业务校验时,我都会把传递的参数记录下来,如:
2016-05-14 15:45:00 [WARN] args: clearDate:2014-08-06 DeptBI:OTHER_BANGFUTONG DeptID:31 Matcher:I0** sucDate:2016-05-16 TxAmt:100
现在程序大约执行了6个小时还没有执行完,并且jvisualvm(JDK自带工具)检测jvm参数,显示堆内存的使用量已经达到10G(设置tomcat对内存为10G)。
并且用top命令查看,tomcat占的进程的CPU到达1200多(此时程序执行一段时间,暂停一段时间,我怀疑是在进行垃圾回收,但是回收效果不明显)
我现在怀疑性能出现在如下几个方面:
1、日志太多,不应每条记录日志。
2、业务校验程序写的有问题
3、不明白的问题,堆内存最后一直10G不下降?
不知道大家对这个有什么看法
1、NIO:采用NIO的MappedByteBuffer
类读写,并且不要每处理一行就写入一次,批量写入
2、多线程:由一个专门的调度线程负责读取文件里的记录,然后插入任务队列,再由一个线程池去任务队列里取任务,然后处理业务逻辑校验什么的,线程池可以直接用Concurrent包里的线程池实现
3、异常:慎用异常,异常是重量级对象,非法数据不要通过异常返回,可自定义错误码返回,异常对性能影响很大的(单次可能不明显,但对你这种大数据量批处理任务就很可观了)
4、仔细检查业务校验逻辑代码,看能不能调优,原因跟3一样,细节的优化对单次性能提升不明显,但累加效应就很可观了。一些小的优化细节建议:
使用性能更优的字符串方法,比如谨慎使用JDK1.6的substring,使用不当可能会导致内存不能释放,应该用new String(str.substring(..))
、优先用StringTokenizer
而不是split进行字符串拆分、优先使用charAt和indexOf、使用StringBuilder
和StringBuffer
处理字符串拼接并提供预估长度参数
尽量保证代码对GC友好,比如尽量让对象小而生命周期短,尽量不要让老年代的对象引用年轻代对象(避免YGC时卡表扫描代价太高),比如static变量引用方法局部变量应该避免
逻辑能简化则简化,看看能不能用一个正则进行完全匹配,正则匹配效率可能高些
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。