`
Donald_Draper
  • 浏览: 953677 次
社区版块
存档分类
最新评论

百万级数据-程序迁移

阅读更多
JVM学习笔记:http://blog.csdn.net/cutesource/article/details/5904501
堆内存设置原理:http://blog.csdn.net/sivyer123/article/details/17139443/
JVM 之 GC日志分析 :http://blog.csdn.net/lan861698789/article/details/51985188
JVM client模式和Server模式的区别:http://developer.51cto.com/art/201009/228035.htm
垃圾收集器:http://yueyemaitian.iteye.com/blog/1185301
VisualVM分析器:http://www.cnblogs.com/linghu-java/p/5689227.html
MemoryAnalyzer使用:http://wensong.iteye.com/blog/1986449
MAT中Retained和Shallow区别:http://bjyzxxds.iteye.com/blog/1532937
应用场景:先需要将Mdb中的表中数据,全量迁移到Sdb中,一种方法用工具Kettle,第二种编写脚本,第三种程序迁移,第一与第二种迁移对大表没有问题,第三种,由于百万级数据表,全量从Mdb取出,再全量插入的Sdb,对内存的要求较高,比较有效的方法是分页查询,再插入;今天我们不讲的分页查询插入,来看全量从Mdb取出,再分批量插入的Sdb,关于分页分批插入(为应对内存问题,可以将查询结果存到文件,再从文件中读取插入),后续再讲。
主要代码:
int counts =0;//记录数
//Data d = null;
while (rs.next()) {
	Data d = new Data();
	d = getData(rs);
	insertList.add(d);
	pd = null;//待gc回收
	if(counts%5000==0){
		batchSave(insert, insertList);
		insertList.clear();
		log.info("============RecordsSave:"+counts);
	}
	if(rs.isLast()){
		batchSave(insert, insertList);
		insertList.clear();
	}
  log.info("============Records:"+counts);
  counts++;
}

下面的测试表记录数为28万
Tomcat:JavaOPT 默认
-client
-Xmx256M
JVM虚拟机默认启动时,client模式,垃圾模式为Serial New + Serial Old
当counts%10000==0,批量为10000,抛出OOM:java heap space
当Data d = new Data();放在循环外定义:Data d = null;抛出OOM:java heap space
当批量为5000时:
JConsole 堆信息:
2016-09-29 16:40:42
已使用: 107,876 Kb
分配: 253,440 Kb
最大值: 253,440 Kb
GC 时间: 
Copy(326 项收集)所用的时间为        2.518 秒
MarkSweepCompact(171 项收集)所用的时间为       1 minute
所用时间s:220.66
VisualVM:



Viusal GC:



去除log.info("============Records:"+counts);
JConsole 堆信息:
时间: 2016-09-29 16:25:44
已使用: 244,748 Kb
分配: 253,440 Kb
最大值: 253,440 Kb
GC 时间:
Copy(332 项收集)所用的时间为  2.456 秒
MarkSweepCompact(114 项收集)所用的时间为 39.902 秒
所用时间s:163.09
这说明,不要打,不必要的log
VisualVM:





Viusal GC:



当批量为2000时:
JConsole 堆信息:
2000
时间: 2016-09-29 16:50:28
已使用: 252,652 Kb
分配: 253,440 Kb
最大值: 253,440 Kb
GC 时间:
Copy(321 项收集)所用的时间为        2.369 秒
MarkSweepCompact(106 项收集)所用的时间为       36.438 秒
所用时间s:145.524

VisualVM:




Viusal GC:





对比5000可以看出,堆内存的趋势图,更平缓,Copy及MarkSweepCompact收集次数减少,故所用时间降低。

当批量为1000时:
JConsole 堆信息:
时间: 2016-09-29 17:03:10
已使用: 249,215 Kb
分配: 253,440 Kb
最大值:253,440 Kb
GC 时间: 
Copy(330 项收集)所用的时间为        2.299 秒
MarkSweepCompact(100 项收集)所用的时间为       34.530 秒
所用时间s:159.459
从所用时间和Copy及来看,比2000批次还有,MarkSweepCompact收集次数减少了6次
从5000,2000,1000来看说明,批次处理量对处理的速度有影响,应选择合适的批次数量。

下面调整一下
JavaOPT
-server
-XX:+PrintGCDetails
-Xloggc:E:\gc.log
Server模式下,垃圾回收器默认为PS Scavenge+ PS-Old
我的机器内存是8G,默认Server模式下,Xmx1024M ,同样的处理逻辑:
当批量为2000时:
JConsole 堆信息:
时间: 2016-09-29 17:12:41
已使用: 337,969 Kb
分配:  574,784 Kb
最大值:  932,096 Kb
GC 时间: 
PS MarkSweep(6 项收集)所用的时间为        1.475 秒
PS Scavenge(74 项收集)所用的时间为        1.090 秒
全量更新所用时间s:114.25

当批量为5000时:
时间: 2016-09-29 17:19:26
已使用: 365,969 Kb
分配: 547,968 Kb
最大值: 932,096 Kb
GC 时间: 
PS MarkSweep(6 项收集)所用的时间为        1.400 秒
PS Scavenge(70 项收集)所用的时间为        1.212 秒
所用时间s:107.12
从上可以看出新生代的收集次数减少,所用时间减少,这说明当堆内存增大时,可以相应的调整批量处理数,以提高处理效率。


我们来看看在-server,模式下能处理的最大记录数:
java OPTS:
-server
-Xms512M
-Xmx1024M
-XX:NewSize=384M
-XX:ParallelGCThreads=4
-XX:+PrintGCDetails
-Xloggc:E:\gc.log
时间: 2016-09-29 18:16:19
已使用: 1,004,657 Kb
分配: 1,028,288 Kb
最大值:  1,028,288 Kb
GC 时间:
PS MarkSweep(424 项收集)所用的时间为     10 minutes
PS Scavenge(121 项收集)所用的时间为        3.631 秒
在上述配置下,能够处理的最大记录数为1040000
总结:
从上的分析来看,批量处理的数量,应该根据堆内存的变化而调整,已达到立项的处理效率;
在1G的堆内存,处理百万级以下的数据量,还是可以滴。
分页分批次处理:
java opts:
-server
-Xms1024M
-Xmx1536M
-XX:NewSize=512M
-XX:ParallelGCThreads=4
主要逻辑:
  sql = "SELECT COUNT(*) FROM " + test;
	ps = con.prepareStatement(sql);
	countResultSet = ps.executeQuery();
	int sums =0;
	while(countResultSet.next()){
		sums =countResultSet.getInt(1);
	}			
	int batches = 0;
	if( sums > 100000){
		if(sums % 100000 ==0){
			batches = sums/100000;
		}
		else{
			batches = sums/100000  + 1;
		}
	}
	int counts =0;//记录数
	for(int i =1;i<=batches;i++){
	logger.info("==============第"+i+"页start==========");
	counts+=InsertRecordByPages((i-1)*100000+1,(i)*100000);
	logger.info("==============已更新记录数:"+counts);
	logger.info("==============第"+i+"页end==========");
       }

在InsertRecordByPages函数中,不用的局部变量要null化
结果:可以处理140万的数据
==============第15页start==========
2016-09-30 16:16:10 -885050 ==============已更新记录数:1409864
2016-09-30 16:16:10 -885050 ==============第15页end==========
再大,只能用工具迁移了。











  • 大小: 58 KB
  • 大小: 32.5 KB
  • 大小: 55.2 KB
  • 大小: 31.3 KB
  • 大小: 44.5 KB
  • 大小: 30.8 KB
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics