Heritrix源码分析(十四)
近段时间在搞定Lucene的一些问题,所以Heritrix源码分析暂时告一段落。今天下午在群里有同学提到了Heritrix异常终止的问题以及让Heritrix不停的抓取(就是抓完一遍后载入种子继续抓取,目前他是写个定时器,定时检查Heritrix是否停止,如果停止了则重新初始化Heritrix,让Heritrix重新抓取,但这个方法就不可避免的会导致抓取重复URl,除非从recover.gz导入)。我想这2个问题都可以用我下面这个方法,但对于Heritrix异常终止的问题这个方法也只是治标不治本,要改动的地方蛮多,涉及到Heritrix的设计以及结构,不是一时可以完成。下面就介绍原理以及方法:
1.原理:
Heritrix的自然停止(就是非人为以及不可抗力因素,如Web UI界面出发停止命令)的依据是判断调度器里面是否还有URL可抓取,如果没有则当前线程退出,如果是单线程抓取的话,则也意味着Heritrix的结束。如果是多线程抓取的话,则每个线程在获取不到URL的时候都会置不在活动状态,当最后一个活动状态线程也获取不到URL的时候则Heritrix也会进入自然停止。所以我们可以在判断Heritrix是否还有URL可抓取的时候做一些处理,比较简单的方法就是重新载入种子以及唤醒所有抓取线程。但由于处在多线程抓取模式中,每个线程都会判断,如此会导致多次载入种子,造成不必要的浪费,所以这里也要做一些同步控制。不要导致过分载入种子,而是每抓完一次则重新载入种子。
2.方法:
修改org.archive.crawler.frontier.WorkQueueFrontier中的public CrawlURI next()方法,这里也对该方法做一些介绍,具体请看源码注释,改成如下,红色部分为改动部分:
- /**
- * 从调度中心获取下一个要抓取的URL
- *
- */
- public CrawlURI next() throws InterruptedException, EndedException {
- while (true) {//一直不停的循环,直到遇到异常或终止
- <span style="color: #ff0000;">// 郭芸修改,用于当队列里没有可抓取的URL的时候去获取种子继续
- synchronized (this) {
- if (this.controller.getFrontier().isEmpty()) { //如果没有可抓取的URL
- loadSeeds(); //重新载入种子
- this.controller.getToePool().notifyAll(); //唤醒所有抓取线程
- }
- }</span>
- long now = System.currentTimeMillis();//开始获取时间
- // 检查是否有暂停命令、结束命令以及宽带控制,这里会导致Heritrix结束
- preNext(now);
- /*
- * 允许最多一个线程去填充准备队列(readyClassQueues)
- */
- if (readyFiller.tryAcquire()) {// 表示没有线程去使用当前变量,当前类1次只允许1个线程同时使用
- try {
- // 空闲队列数=目标队列数-准备队列数
- int activationsNeeded = targetSizeForReadyQueues()
- - readyClassQueues.size();
- // 如果空闲队列数大于0,并且不在活动状态的队列数不是空的,则表示需要将不在活动状态的队列转移到准备队列
- while (activationsNeeded > 0 && !inactiveQueues.isEmpty()) {
- activateInactiveQueue();//将不在活动状态队列的URL转移一定数目到活动状态队列
- activationsNeeded--;
- }
- } finally {
- readyFiller.release();// 必须释放,这样下次才可以继续使用
- }
- }
- WorkQueue readyQ = null;//准备工作队列
- // 获取并移除此准备队列表示的队列的头部(即准备队列的第一个元素)如果该队列没有可用元素,则等待指定的时间,这里是1000毫秒也就是1秒
- Object key = readyClassQueues.poll(DEFAULT_WAIT,TimeUnit.MILLISECONDS);// 获得classKey,然后再通过classKey去获得队列
- if (key != null) {
- readyQ = (WorkQueue) this.allQueues.get(key);// 获得工作队列WorkQueue
- }
- if (readyQ != null) {
- while (true) { // 一直循环,直到抛出异常或终止
- CrawlURI curi = null;
- synchronized (readyQ) {//锁定准备队列,让其他线程无法获取,避免脏读
- curi = readyQ.peek(this); // 从数据库pendingUrls中获取CrawlURI
- if (curi != null) {
- // 检查该curi是否属于不同的队列
- String currentQueueKey = getClassKey(curi);
- if (currentQueueKey.equals(curi.getClassKey())) {
- //在正确的队列,排放它
- noteAboutToEmit(curi, readyQ);
- inProcessQueues.add(readyQ);// 加入已处理队列
- return curi;
- }
- curi.setClassKey(currentQueueKey);
- readyQ.dequeue(this); //从调度器中删除刚获取到的URL
- decrementQueuedCount(1); //计数
- curi.setHolderKey(null);
- } else {
- readyQ.clearHeld();
- break;
- }
- }
- if (curi != null) {
- sendToQueue(curi); //将获取到的URL发送到它该属于的队列
- }
- }
- } else {
- if (key != null) {
- logger.severe("Key " + key
- + " in readyClassQueues but not allQueues");
- }
- }
- //如果该强烈退出,则抛异常结束循环
- if (shouldTerminate) {
- throw new EndedException("shouldTerminate is true");
- }
- //如果没有处理中的队列,则刷新该队列
- if (inProcessQueues.size() == 0) {
- this.alreadyIncluded.requestFlush();
- }
- }
- }
Heritrix源码分析(十四)的更多相关文章
- Heritrix源码分析(十四) 如何让Heritrix不间断的抓取(转)
欢迎加入Heritrix群(QQ):109148319,10447185 , Lucene/Solr群(QQ) : 118972724 本博客已迁移到本人独立博客: http://www.yun5u ...
- ABP源码分析十四:Entity的设计
IEntity<TPrimaryKey>: 封装了PrimaryKey:Id,这是一个泛型类型 IEntity: 封装了PrimaryKey:Id,这是一个int类型 Entity< ...
- jQuery 源码分析(十四) 数据操作模块 类样式操作 详解
jQuery的属性操作模块总共有4个部分,本篇说一下第3个部分:类样式操作部分,用于修改DOM元素的class特性的,对于类样式操作来说,jQuery并没有定义静态方法,而只定义了实例方法,如下: a ...
- Vue.js 源码分析(十四) 基础篇 组件 自定义事件详解
我们在开发组件时有时需要和父组件沟通,此时可以用自定义事件来实现 组件的事件分为自定义事件和原生事件,前者用于子组件给父组件发送消息的,后者用于在组件的根元素上直接监听一个原生事件,区别就是绑定原生事 ...
- Heritrix源码分析(十五) 各种问题总结(转)
开博客以及建立Heritrix 群有一段时间了(这里谢谢大家的关注),这篇博客将整理这段时间所遇到的问题.同时由于自己从今年5月份开始就不怎么接触Heritrix,很多东西开始遗忘(不过里面思想没忘) ...
- Heritrix源码分析(十五)
开博客以及建立Heritrix 群有一段时间了(这里谢谢大家的关注),这篇博客将整理这段时间所遇到的问题.同时由于自己从今年5月份开始就不怎么接触Heritrix,很多东西开始遗忘(不过里面思想没忘) ...
- Heritrix源码分析(十二) Heritrix的控制中心(大脑)CrawlController(一)(转)
本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/650694 本博客已迁移到本人独立博客: http://www.yun5u.com/ ...
- Heritrix源码分析(十) Heritrix中的Http Status Code(Http状态码)(转)
本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/649737 本博客已迁移到本人独立博客: http://www.yun5u ...
- [Abp 源码分析]十四、DTO 自动验证
0.简介 在平时开发 API 接口的时候需要对前端传入的参数进行校验之后才能进入业务逻辑进行处理,否则一旦前端传入一些非法/无效数据到 API 当中,轻则导致程序报错,重则导致整个业务流程出现问题. ...
随机推荐
- android中控件的使用
http://www.cnblogs.com/linjiqin/category/284058.html
- java关键字 (jdk6),各自的含义是什么?
Abstract 抽象的 一个Java语言中的关键字,用在类的声明中来指明一个类是不能被实例化的,但是可以被其它类继承.一个抽象类可以使用抽象方法,抽象方法不需要实现,但是需要在子类中被实现. bre ...
- XIB自定义视图的整理
- (void)setAppInfo:(AppInfo *)appInfo { _appInfo = appInfo; _icon.image = appInfo.image; _label.text ...
- PULL生成XML文件
package xmlpulldemo; import java.io.FileNotFoundException; import java.io.FileOutputStream; import j ...
- java(try块语句变量,和匿名类变量生存时间
在try块定义的变量不能作用于快外 // int a=2; try{ int a=3; System.out.println(a); } catch(Exception e){} System.out ...
- iOS开源 框架
UI界面类项目: Panoramagl ——720全景展示 Panorama viewer library foriPhone, iPad and iPod touch MBProgressHUD — ...
- javascript sort()与reverse()
javascript 中提供了两个对数据进行排序的方法,即sort()和reverse() 在理解的时候犯了一个非常低级的错误,现记录如下: reverse()不包括排序的功能,只是把原来的数组反转. ...
- Remoting通讯实例
Remoting通讯可以实现不同应用程序域之间的通信(可以为一台机器不同程序,也可以不同机器上的不同程序) 实例步骤: (1)编写透明代理类 新建一个类库,命名空间:MyRemoting 在该类库中建 ...
- 23个phpcms v9模板制作及二次开发常用代码案例
0:调用最新文章,带所在版块 {pc:get sql="SELECT a.title, a.catid, b.catid, b.catname, a.url as turl ,b.url a ...
- cnetos6.4 x64 阿里云环境初探--安装pip,及pymysql
由于以前帮朋友买过阿里云服务器,一直以为,不能再体验新用户免费了,由于最近比较有心情研究python,linux,就报着侥幸的心理,重新注册一个帐号试一下,注册完之后,惊奇的发现,原来阿里只要是新注册 ...