一个网络爬虫的项目总结—ActiveMQ部分
项目还没完全完工,但是关于爬虫相关的部分已经不会再有什么更改了。
还会进行大改的,是用Lucene存储链接的对应模块,设计方案已经通过讨论,只剩下实现。
那么就到写项目总结的时间了。
这个爬虫经历过一次完全构架的重新选择:从基于Nutch的体系改为了自己写很多东西
之前,我对Nutch+Hadoop做了二次开发并把系统搭建好,但是Fetcher部分的性能不好搞。
Nutch的任务都是基于Hadoop的,然后Input和Output都严重依赖于HadoopIO。我在把主体代码写完后,有试着虚构一个假的RecordReader给Fetcher以启动它。但是只写了一个Demo就没往下写了。只凭第一感觉的话,大概是可以的。但是因为对Hadoop的不熟悉,而且时间也不足够,也就没往下再深究了。此时领导也已经决定抛弃Nutch,转用自己实现多数东西。
新一版本的爬虫,Fetcher部分我移用了Nutch带的httpclient实现的一些代码,这个不重要。
重要的是URL来源,领导选用了ActiveMQ来做:各部分都从MQ里取任务,做完后可能继续往里面塞任务。
(个人感觉不大好,因为ActiveMQ我们用了MySQL存储,里面的消息内容都是二进制的,根本没法读取,程序拉出来读又会把消息消费掉,这样一个中间件使得很多东西必须额外的写了)
在此还是先说一些和ActiveMQ相关的点吧
- 当数据量上去以后(超过500W),基本都得把Journal给整上,否则没法用,完全没法用
- ACTIVEMQ_MSGS里的PRIORITY项,MySQL不支持order by int desc的优化(?),所以应该把desc去掉
Journal在清理旧数据的时候,会非常非常的慢,代码在
package org.apache.activemq.store.jdbc.adapter;
public class DefaultJDBCAdapter {
public boolean doDeleteOldMessages(TransactionContext c) {}
}
处
解决办法
一、去除旧数据的持久化,我们是这样做的
二、更改doDeleteOldMessages的代码,我做了下,但是没有实际的运行出效果(因为我们没用持久化嘛),思路很简单,就是把
package org.apache.activemq.store.jdbc;
public class Statements {
public String getDeleteOldMessagesStatementWithPriority() {}
}
方法分成两句,消除子查询(MySQL的子查询根本就没有效率可言。。。),将执行一次SQL改为两次
具体代码不给出了,也挺简单
- 如果ActiveMQ遇到了内存泄露的问题,那么,检查一下你代码里面,重用的IO对象是什么?有没有哪些非重用对象是打开了但是忘了关闭了
- 重用的对象可以是sender/receiver/producer/consumer/session/connection,我的代码是重用connection,而我领导重用的producer/consumer
- 临时打开的IO对象用完不关是内存泄露的主要原因,我们遇到的内存泄露问题的根源就是它
- 如果你有用jconsole去查看内存使用的话,那么,很多时候这些IO对象调用close()方法都会导致jconsole的output弹出错误警告。这个非常非常的恼人。所以完全不推荐用jconsole去查看ActiveMQ的内存使用。(一开始不明白原因,于是我还在Twitter上抱怨ActiveMQ的实现烂。。。)
- 推荐在ActiveMQ的本机用JProbe来查看内存、辅助查看瓶颈所在,这玩意儿也是可以破解的嘛
重要:养成良好的编程习惯太重要了。打开的IO对象,切记在finally块里关闭它!这回我们就遇到了这问题。领导反复让我改代码,但是问题一直都没解决。最后他有其他项目的事情去做,然后问题丢给我。我把他的代码拿来,直接查看了几个关键方法,然后就改了。结果问题就这样解决了。原来4G的内存,跑一晚上就挂掉。现在2G的内存,跑三四天,内存占用也不过1G左右。
| anyShare分享到: | |
| |