`
guafei
  • 浏览: 322761 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

访问量定时程序总结

阅读更多
感谢当当,在跑写这个程序的时候,当当让我了解了很多新的知识

这是两个比较经典的提问:
http://topic.csdn.net/u/20071119/23/8af044b3-8c28-4db0-8303-4a8679f2356d.html
http://topic.csdn.net/u/20071209/10/c01ad9da-08cb-452c-9230-dff429619361.html

本程序要做的事情是:从cache服务器中读取店铺访问量数据,然后入库。
问题的难点 :
1 :全国所有店铺的key(city_storeId)有750万,数据量很大,导致跑的时候经常内存溢出
2 :解决了读数据的问题,但是跑这么多数据速度很慢,需要6个多小时,则思考了很多方法


问题一解决方式:
之前我是用buffedreaded类的readline方法一行一行的读取,然后放在list里面,在通过遍历list去做更新操作。这明显是不行的,把所有数据放在list导致内存溢出,放不了那么多数据。
之后放弃这个方式,在buffedreaded类的readline方法读取时就进行数据库的入库操作,因为readline方法每次读取一定量的数据到内存,假设100条key,然后放到队列里,接着就一条一条的更新,所以不会导致内存溢出,但是出现一个问题,就是跑的时间太慢

问题二解决方式:
想了很多方式:有想到用NIO来提高IO读取的效率,也有想到用多线程,分割文件来跑,最后还是用到了多线程,这个要感谢当当,有个例子给我,也让我第一次接触了多线程的current包(想当初就是没有回答上这个包,才被淘宝拒绝的)。刚开始进入了一个误区,还以为是读取文件慢了,结果是因为操作数据库太慢了。mysql数据库每秒可以接受500-1000的并发量,那么750万数据,怎么算都至少跑2个小时(7500000/1000/3600)。所以只能通过加mysql数据库集群才能使速度加快。

找个时间好好学习下current包
ExecutorService fixedPool =Executors.newFixedThreadPool(poolSize); 

还有用多线程跑的时候还出现了内存溢出的问题,问了当当之后,通过调整了eclipse的jvm虚拟机的内存(从原来的252M调整到1G),还有就是把线程引用对象读到队列里的时候,每50万条,sleep(5000),不要一下子加载。

下面是代码:

线程类代码
       //判断静态类是否有重复创建,可以用此来判断
        private static int count = 0;
       private static Score dianHitsScore;
private static IStoreExtService storeExtService;
public ThreadForVisit(String data) {
this.data = data;
}
static {
ApplicationContext context = new ClassPathXmlApplicationContext(
"CateVisitTimer.application.xml");
dianHitsScore = (Score) context.getBean("dianHitsScore");
storeExtService = (IStoreExtService) context.getBean("storeExtService");
}
public void run() {
Integer score = null;
//    int entity_total = 0; // entity为null数据条数的总数
// int cache_total = 0; // cache中无数据的条数的总数
// int update_total = 0; // 访问量更新的数据条数的总数
try {
String storeId = getCityAndStoreId(data);
score = dianHitsScore.get(data);
if (score != null && score.intValue() > 0) {
StatisticEntity entity = storeExtService.getStatisticById(storeId);

if (entity != null) {
entity.setTotal(score.intValue());
// 这个读取数据库的操作已经用了多线程
storeExtService.updateStatistic(entity, storeId);
//update_total++;
//logger.info(data + "=" + entity.getTotal());
//Thread.sleep(100);
} else {
//entity_total++;
//logger.info(entity + "为null!");
}
} else {
//cache_total++;
//logger.info(data + "cache 中无数据!");
}
count ++;
if(count % 10000 == 0){
System.out.println("=============="+count);
}
} catch (Exception e) {
logger.info("ThreadForVisit类的run方法中的Thread.sleep(100)出问题");
}
}

main函数跑的代码
ExecutorService fixedPool = Executors.newFixedThreadPool(poolSize);

int count = 0;
if (data != null) {
try {
//速度慢不是由于读文件上的浪费,而是对数据库操作时候的慢
BufferedReader buff = new BufferedReader(new FileReader(data));
while ((data_part = buff.readLine()) != null) {
fixedPool.execute(new ThreadForVisit(data_part));
if((++count % 500000) == 0){
System.out.println("数据达到50万");
Thread.sleep(5000);
}
}
} catch (Exception e) {
logger.info("store访问量定时程序异常");
}
}


其实里面还设计到很多调试代码的技巧:分开测每个数据库操作所需要的时间
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics