nutch抓取双语资料速度提升tips

[未写完]

1. 优化的目标

抓取网页一般是为了得到某种类型的数据,例如房产数据、影片信息,而我是为了抓取更多的中外双语的结构化文本。所以单位时间内的双语文本数量就是我的优化的目标,而单语的就算抓取很快,对我们的产出也没有任何意义。

2. 评估指标

上面提到的,是我们的最终的目标,除了最终目标外,还需要子目标来帮助我们的评估工作的。

  1. 抓取的页面数
    ./runtime/deploy/bin/nutch readdb /user/dict/crawler/normal/data/crawldb -stats &> normal201608072117 &
  2. 抓取的数据量大小
    hadoop fs -du -h /yourpath/segments)

  3. 每一个机器的处理情况可以从hadoop的job status和log里面看到,需要在firefox中安装foxyProxy Standard,导入url模版,并且配置sucks.inner.youdao.com:port,选择socks v5,这样就可以算出每一台机器的处理的速度了。如下:
    http://lunaspark.corp.youdao.com/cluster/scheduler->ApplicationMaster->MapReduce Application application->Map->每一个任务中->logs。 可以看到status:1000 threads, 580 queues, 10704 URLs queued, 19699 pages, 16000 errors, 47.0 (14) pages/s, 13211.0 (395398) kbits/s

    这里可以看到页面错误率太高了,196699个page,居然有16000个是error,跟进log里面,可以看到确实是read time out导致的问题。

  4. 抓取流程占一个完整流程的时间比例,需要越低越好。最好的情况是一直都在抓取,但我们用的是generate->fetch->parse->update->(index)这样的流程,而parse流程占用的内存以及计算资源也比较多,所以需要尽量减少这样的任务的复杂度和时间。例如parse中我们可能只需要提取外链,那meta信息之类的真就不一定需要解析了。至于index一般我都是直接不做了的。

2. 机器方面优化

  1. 需要关注hadoop集群,每台机器是否有外网访问权限以及带宽速度需要了解清楚。有一段时间没有看每台机器的情况,发现有10几台机器外网权限没有了,所以压根没有用上。

  2. 一般来说,我们的抓取线程数数是有上限的。线程数多到一定程度,线程调度的开销会变大,反而影响抓取的效率。

  3. 对于http请求,使用TCP连接,会受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄), 可以使用ulimit -n命令来看数量,默认的话可能只有1024,需要找系统管理员调大,我们目前是:1048576。

  4. 查看网络情况
    很多情况下一些工具并没被安装,sar这个基本都装了 sar -n DEV interval count
    sar -n DEV 1 4
    IFACE:LAN接口
    rxpck/s:每秒钟接收的数据包
    txpck/s:每秒钟发送的数据包
    rxbyt/s:每秒钟接收的字节数
    txbyt/s:每秒钟发送的字节数

  5. Linux系统级的最大打开文件数限制,使用如下命令可以看到:cat /proc/sys/fs/file-max

  6. 磁盘的影响:保存数据需要写磁盘,如果我们网络过来的数据大于磁盘的才需要考虑磁盘的优化。 iostat -d -k 1 10可以用来查看磁盘的工具情况,参数 -d 表示,显示设备使用状态;-k某些使用block为单位的列强制使用Kilobytes为单位;1 10表示,数据显示每隔1秒刷新一次,共显示10次。

3. 配置参数优化

3.1 hadoop配置的优化

hadoop任务队列可能会有多个,例如我们的机群就分了default与prior两个,一个60%的内存另一个40%,但很可能大家都在default上面提交job,导致很多job的等待时间特别长。
可以在使用的hadoop中进行配置:

hadoop/etc/hadoop/mapred-site.xml中加入:  
    <property>   
        <name>mapreduce.job.queuename</name>   
        <value>prior</value>        
    </property>

hadoop需要时不时关注一下机器运行情况,有可能别的人占用了很多的内存导致自己的任务迟迟不能开始,其实还是很影响效率的。
建议在脚本中加一下统计时间,也就是真实的fetch的时间以及做别的事的时间,还有任务纯开始和结束的时间比,可以算出任务的效率。

3.2 crawl脚本配置的优化

src/bin/crawl这个脚本可以帮助我们一轮轮的去抓取,本身会调用src/bin/nutch这个工具,那调用的时候也会有一些参数需要配置。

numSlaves=48//这个可以弄成hadoop集群的机器数

numTasks=`expr $numSlaves \* 6`//这个是上面的数据*6,为啥时6呢,因为按建议是1.5(因子)*4(每台机器的cpu core数目)

sizeFetchlist=`expr $numSlaves \* 50000`//generate时一次迭代需要抓取的URL总数,这个如果搞得太大,后续的parse占用的内存就会越多,从而有可能会parse job failed.太小的话迭代次数过多,使得真正fetch的时间比例减小,同样长的时间内真实的抓取工作量就少了。一般我弄成了5万或者10万。这个也还是看机群的能力吧。

timeLimitFetch=60//每一轮抓取的最长抓取时间,超过这个时间,没有抓取完,也会停止,这样相当于对很慢的抓取队列进行止损。

numThreads=100//每一个抓取task开的抓取线程数。太多的话可能也会有问题,因为同一时间对同一个站点的线程数过多,被封禁的可能性会增加,反而得不偿失。有时候对于单点抓取,我会把这个改成1,每台机器就一个线程去抓取。一般弄成10或者100,1000的话有点大了。

mode=distributed//机群抓取这个一定是这样的

invertlinks任务和solrindex、solrdedup任务我是直接注释掉的,因为这个是做索引相关的,和主要的抓取任务无关。

3.3 nutch配置的优化

这部分的优化与抓取的性能更加相关,有更多的细节需要调优。

0.4
namevaluedescription
file.content.limit165536页面下载的最长字节数,超过会被截断,file:// protocol中的。其实一般是65535
http.robots.403.allowtrue有些服务器在没有robots文件的时候会返回403错误,这时我们就能随意爬取内容。但是如果这个值被设置成false,我们就无法爬取这个网站。
http.timeout5000这个是一个比较重要的参数:http请求的超时参数,太短的话对于一些访问慢的网站可能就会出现connection time out的问题
http.max.delays1在爬取网页的时候,线程的最多等待次数。每次线程发现主机繁忙的时候,线程就会等待fetch.server.delay这么长的时间,如果总的等待次数超过这个值,nutch则不再在本轮抓取中爬取该网页
http.content.limit165536http请求结果的最长字节数,超过会被截断,http:// protocol中的
http.redirect.max3抓取的url如果有redirect,抓取线程会跟进去,最多跳转这么多次。我觉得3次应该差不多了
http.accept.languagezh-cn,zhHTTP request head中的Accept-Language的设置,如果只抓取某一种语言的,可以只使用这个,也可以使用en-us,en-gb,en;q=0.9,*;q=0.1来做偏好
ftp*这些的保留现状就成
db.fetch.interval.default259200030天后抓取成功的网站会被更次抓取,因为可能会有更新了
db.fetch.interval.max7776000最长90天就需要更新了,不管现在这个页面的状态是啥样的
db.fetch.schedule.adaptive.inc_rate如果重新下载网页并更新数据库的时候,发现这个网页没有发生变化,那么这个网页的更新时间间隔会变成:原来的时间间隔*(1+设置的这个值),不能超过0.5
db.fetch.schedule.adaptive.dec_rate0.2如果重新下载网页并更新数据库的时候,发现这个网页发生了变化,那么这个网页的更新时间间隔会变成:原来的时间间隔-设置的这个值(这个值不能超过0.5)
db.fetch.schedule.adaptive.min_interval60.0最小的网页更新时间间隔。单位是秒
db.fetch.schedule.adaptive.max_interval31536000.0最大的网页更新时间间隔。如果一个页面大于了db.fetch.interval.max,而一定会被抓取
generate.max.count100000-1则无限制。一轮抓取时,每一个队列最大的url数,这个在generate时一般都会自己带上。所以在这里设置也一般也没啥作用。
generate.count.modehost/domain生成上面的队列时,是按哪种方式分类。
generate.update.crawldbfalse对于高并发的环境来说,可能发生generate/fetch/update循环重叠的情况。如果设置为true,即使没有中间updatedb,可以以运行一个额外的job来更新crawldb达到目的。 如果设置为false,在没有中间updatedb的情况下,则有可能产生两个相同的下载队列。我一般不会多个同时执行,所以默认的就成
partition.url.modebyHost/byDomain/byIP其实我做的应该是byURL,可以看代码逻辑的优化这块
fetcher.server.delay1设置对同一server成功请求的时间间隔。其实我觉得0可能会更好
fetcher.server.min.delay0成功请求同一个服务器的最小时间间隔,fetcher.threads.per.host大于1才会有效,这个与上线的区别还需要更看一下源码
fetcher.threads.per.host10每一个节点去一个host去抓取页面的最大线程数,所有同时会有这个值*运行的task数目的线程在对一个站点进行抓取
fetcher.max.crawl.delay10如果robots协议中说抓取间隔需要大于这个值,那么这个站点就会被跳过。-1则不管咋样都去按自己的节奏抓取
fetcher.store.contenttrue保存抓取的内容,不保存抓取有啥用。。。
fetcher.threads.fetch10每一个节点的抓取线程数
fetcher.queue.modebyIP/byDomain/byHost这个是在取线程时看会分到哪个线程里面去抓取,没啥用
fetcher.threads.per.queue10每一个队列的抓取线程数
fetcher.timelimit.mins60一轮抓取的最长抓取时间,分钟为单位。超过了这个时间,则一定会停止,不管是否抓取完毕。在前面的配置中也有说过,为了止损用的。
fetcher.throughput.threshold.pages-1异常检测:如果每秒抓取能力低于这个值,抓取线程会停止
fetcher.max.exceptions.per.queue-1异常检测:如果一个队列中的异常次数大于这个值,就会队列全清空,止损

还有一些别的,后续再慢慢补全。

4. 代码逻辑优化

4.1 URLPartitioner

原来的URL partition的逻辑是更加有礼貌的抓取,只能按host/domain/ip来分配到同一个partition上面导致抓取的时候机器只能有一台发挥作用。 但是我们如果做定点抓取,例如某百科的,这样还是太慢了,可以将getPartition()方法只取URL的hashCode就成了

4.2 generate打分逻辑优化

在泛抓取的时候,我们可能只需要尽快的抓取更多的页面,所以如果一个站点抓取超时了的话,后续的分数应该是需要降低的。 另外,所抓取的网站,可能并不是我们所需要的某种类型的网站。例如我需要有双语的网站越多越好,抓取一大堆我不需要的单语站点其实也是没有意义的。 所以需要对排序打分逻辑进行修改。 在这里:

comments powered by Disqus