Apache StormCrawler 3.6.0 配置参数详解
Apache StormCrawler 3.6.0 配置参数详解:配置加载链(crawler-default.yaml 内置默认、crawler-conf.yaml 覆盖、Flux 注入),拓扑并发、HTTP 协议、抓取调度、重抓策略、解析、索引、元数据与后端八类核心参数的默认值与改法,含生产配置模板与 FAQ,全程实测。
Apache StormCrawler 3.6.0 配置参数详解
目标:系统讲解 Apache StormCrawler 3.6.0 的配置体系与核心参数。StormCrawler 的配置分两层:StormCrawler 自带的内置默认配置(core jar 内的 crawler-default.yaml)与用户自定义覆盖(archetype 生成的 crawler-conf.yaml),再经 Flux 拓扑的 includes 机制合并后传入拓扑。本文给出参数查看方式、参数总览、八类核心参数详解与生产配置模板。所有默认值均在 Ubuntu 22.04.5 + StormCrawler 3.6.0 环境实测提取,合并后的完整配置已在拓扑启动日志中核实。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS
- Java:OpenJDK 17.0.20.1
- StormCrawler 版本:3.6.0(官方 archetype 生成工程 /root/build/crawler-demo/)
- Storm 运行时:Apache Storm 2.8.8(/opt/apache-storm-2.8.8/)
- 配置载体:crawler-default.yaml(内置默认)+ crawler-conf.yaml(用户覆盖)+ crawler-local.flux / crawler.flux(拓扑定义)
- 演示账号:root
二、前置条件
已按《Ubuntu 22.04 安装 Apache StormCrawler 3.6.0 指南》完成工程生成与构建,可正常编译:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
cd /root/build/crawler-demo
mvn -B clean package
实测结果:BUILD SUCCESS。
三、参数查看与修改方式
3.1 配置加载链
StormCrawler 启动时按以下顺序合并配置(后者覆盖前者):
| 顺序 | 载体 | 位置 | 作用 |
|---|---|---|---|
| 1 | crawler-default.yaml | stormcrawler-core-3.6.0.jar 内 | 全部内置默认值 |
| 2 | crawler-conf.yaml | 工程根目录 | 用户自定义覆盖 |
| 3 | flux 拓扑文件 config 段 | crawler-local.flux 等 | 拓扑级覆盖(含 topology.kryo.register 等必选项) |
flux 的 includes 段声明了合并顺序(archetype 生成的拓扑文件实测内容):
includes:
- resource: true
file: "/crawler-default.yaml"
override: false
- resource: false
file: "crawler-conf.yaml"
override: true
3.2 查看合并后的生效配置
storm local(或 storm jar)启动时,StormSubmitter 会把合并后的完整配置打印到日志(Submitting topology ... with conf {...}),可直接检索确认任意参数的生效值。实测片段(节选):
13:27:21.636 [main] INFO o.a.s.StormSubmitter - Submitting topology crawler-local in distributed mode with conf {"http.content.limit":65536,"fetcher.threads.number":50,"http.agent.name":"DemoCrawler","http.protocol.implementation":"org.apache.stormcrawler.protocol.okhttp.HttpProtocol","parser.emitOutlinks":true,"scheduler.class":"org.apache.stormcrawler.persistence.DefaultScheduler","urlbuffer.class":"org.apache.stormcrawler.persistence.urlbuffer.SimpleURLBuffer",...
3.3 查看内置默认值
内置默认值可从 core jar 中直接提取查看:
python3 - <<'EOF'
import zipfile
z = zipfile.ZipFile("/root/.m2/repository/org/apache/stormcrawler/stormcrawler-core/3.6.0/stormcrawler-core-3.6.0.jar")
data = z.read("crawler-default.yaml")
open("/tmp/crawler-default.yaml", "wb").write(data)
EOF
grep -n "http.content.limit" /tmp/crawler-default.yaml
实测回显:
122: http.content.limit: -1
💡 说明:crawler-conf.yaml 把
http.content.limit覆盖为 65536,故启动日志中生效值为 65536;内置默认为 -1(不限制)。
3.4 修改方式
修改用户层配置 crawler-conf.yaml 后重新 mvn package(配置打包进 uberjar)再运行;仅调临时参数也可直接改 flux 拓扑文件的 config: 段。Java 进程堆参数用 STORM_JAR_JVM_OPTS 或 topology.worker.childopts 调整(建议限制在 256-512MB 并用 jps -v 核实)。
四、参数总览
以下默认值均提取自 crawler-default.yaml(3.6.0 实测);crawler-conf.yaml 覆盖值一栏为 archetype 生成工程的实际值。
| 参数 | 内置默认值 | archetype 覆盖值 | 作用 |
|---|---|---|---|
| fetcher.threads.number | 10 | 50 | 抓取线程总数 |
| fetcher.server.delay | 1.0 | 未覆盖 | 同一主机两次抓取的最小间隔(秒) |
| fetcher.threads.per.queue | 1 | 未覆盖 | 每个抓取队列的线程数 |
| fetcher.queue.mode | byHost | 未覆盖 | 队列组织模式(byHost/byIP/byDomain) |
| fetcher.max.crawl.delay | 30 | 未覆盖 | 尊重 robots Crawl-delay 的上限(秒) |
| partition.url.mode | byHost | 未覆盖 | URLPartitionerBolt 分区依据 |
| urlbuffer.class | ...urlbuffer.SimpleURLBuffer | 未覆盖 | spout 端 URL 缓冲实现 |
| http.protocol.implementation | ...protocol.httpclient.HttpProtocol | okhttp 版 | HTTP 协议实现类 |
| http.content.limit | -1 | 65536 | 响应体大小上限(字节,-1 不限) |
| http.timeout | 10000 | 未覆盖 | HTTP 超时(毫秒) |
| http.allow.redirects | false | 未覆盖 | 是否跟随重定向 |
| http.robots.403.allow | true | 未覆盖 | robots.txt 返回 403 时是否仍允许抓取 |
| robots.cache.spec | maximumSize=10000,expireAfterWrite=6h | 未覆盖 | robots 规则缓存 |
| scheduler.class | ...persistence.DefaultScheduler | 未覆盖 | 抓取调度器 |
| fetchInterval.default | 1440 | 1440 | 成功抓取后的重抓间隔(分钟) |
| fetchInterval.fetch.error | 120 | 120 | 抓取失败(临时错误)重试间隔(分钟) |
| fetchInterval.error | -1 | -1 | 永久错误重抓间隔(-1 不重抓) |
| max.fetch.errors | 3 | 未覆盖 | 单 URL 最大错误次数 |
| status.updater.use.cache | true | 未覆盖 | 状态组件 DISCOVERED 去重缓存开关 |
| status.updater.cache.spec | expireAfterAccess=1h,softValues | 未覆盖 | 该缓存的 Guava 规格 |
| parser.emitOutlinks | true | 未覆盖 | 解析时是否输出外链 |
| jsoup.treat.non.html.as.error | true | false | 非 HTML 文档是否按错误处理 |
| sitemap.discovery | false | true | 是否自动发现 sitemap |
| detect.mimetype | true | 未覆盖 | 内容嗅探 MIME 类型 |
| indexer.url.fieldname | url | url | 索引文档的 URL 字段名 |
| indexer.text.fieldname | content | content | 索引文档的正文字段名 |
| indexer.text.maxlength | -1 | 未覆盖 | 正文字段长度上限(-1 不限) |
| indexer.ignore.empty.fields | false | 未覆盖 | 是否忽略空字段 |
| metadata.track.path / depth | true / true | 未覆盖 | 元数据是否记录路径/深度 |
💡 说明:
http.agent.name在内置默认中为注释状态(示例值 AnonymousCoward),必须由用户显式设置,否则启动报错;archetype 生成值实测为DemoCrawler。
五、核心参数分类详解
5.1 拓扑与并发参数(topology.*)
archetype 生成 crawler-conf.yaml 中的实测值:
config:
topology.workers: 1
topology.message.timeout.secs: 300
topology.max.spout.pending: 100
topology.debug: false
topology.worker.childopts: "-Xmx2g -Djava.net.preferIPv4Stack=true"
topology.kryo.register:
- org.apache.stormcrawler.Metadata
- org.apache.stormcrawler.persistence.Status
| 参数 | 说明与建议 |
|---|---|
| topology.workers | worker 进程数。本地调试用 1;生产按抓取量横向扩到多个 worker 并配多 supervisor |
| topology.message.timeout.secs | 元组完整处理链的超时秒数。慢站点多时可保持 300 |
| topology.max.spout.pending | spout 未完成元组上限,控制抓取并发与背压,100 为保守起步值 |
| topology.worker.childopts | worker JVM 参数。默认 -Xmx2g 偏大,生产建议 256-512MB 起步按需上调,并保留 -Djava.net.preferIPv4Stack=true |
| topology.kryo.register | Flux 模式必配项,注册 Metadata 与 Status 的 Kryo 序列化,缺省会导致元组序列化异常 |
5.2 HTTP 协议参数(http.*)
| 参数 | 默认/覆盖值 | 说明 |
|---|---|---|
| http.agent.name | 必填(实测 DemoCrawler) | 代理名,RFC 9309 合规,用于 robots.txt 匹配 |
| http.agent.version / description / url / email | archetype 生成 1.0 / Demo crawler for local test / http://www.example.com / root@example.com | 组成完整 User-Agent |
| http.protocol.implementation / https.protocol.implementation | 默认 httpclient 实现;archetype 覆盖为 okhttp 实现 | 切换协议栈改这两项 |
| http.content.limit | 默认 -1;archetype 65536 | 响应体截断字节上限 |
| http.timeout | 10000 | 单请求超时毫秒 |
| http.accept | text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 | Accept 头 |
| http.accept.language | en-us,en-gb,en;q=0.7,*;q=0.3 | Accept-Language 头 |
| http.allow.redirects | false | true 时抓取端跟随重定向,false 交给 RedirectionBolt 处理 |
| http.retry.on.connection.failure | true | 连接失败自动重试 |
| http.store.headers | false | 是否把响应头写入元数据 |
⚠️ 注意:
http.allow.redirects: false(默认)时重定向由拓扑中的 RedirectionBolt(shunt 组件)处理并记录_redirTo元数据,不要同时开启抓取端跟随,避免重复抓取。
5.3 抓取调度参数(fetcher.* 与分区)
| 参数 | 默认值 | 说明 |
|---|---|---|
| fetcher.threads.number | 10(archetype 50) | FetcherBolt 全局抓取线程数 |
| fetcher.threads.per.queue | 1 | 每队列并发,1 保证对单主机礼貌抓取 |
| fetcher.server.delay | 1.0 | 同主机最小抓取间隔秒 |
| fetcher.server.min.delay | 0.0 | 同主机额外最小延迟 |
| fetcher.queue.mode | byHost | 可选 byIP/byDomain |
| fetcher.max.crawl.delay | 30 | robots Crawl-delay 钳制上限秒 |
| fetcher.max.crawl.delay.force / fetcher.server.delay.force | false | true 时无视钳制直接采用配置值 |
| fetcher.max.urls.in.queues | -1 | 队列内 URL 总量上限(-1 不限) |
| fetcher.thread.timeout / fetcher.timeout.queue | -1 | 单 URL/队列抓取超时秒(-1 不限) |
| partition.url.mode | byHost | URLPartitionerBolt 按 host 分区,与 fetcher 队列模式保持一致 |
5.4 重抓策略参数(scheduler 与 fetchInterval.*)
# revisit a page daily (value in minutes)
fetchInterval.default: 1440
# revisit a page with a fetch error after 2 hours (value in minutes)
fetchInterval.fetch.error: 120
# never revisit a page with an error (or set a value in minutes)
fetchInterval.error: -1
scheduler.class默认org.apache.stormcrawler.persistence.DefaultScheduler,按 fetchInterval.* 计算下次抓取时间;也可实现 Scheduler 接口或换成 AdaptiveScheduler。- 支持按元数据条件覆盖间隔(如
fetchInterval.isFeed=true: 10表示带 isFeed 元数据的页面 10 分钟重抓)。 max.fetch.errors: 3:单 URL 连续错误达 3 次后按fetchInterval.error处理。
5.5 解析参数(parser/textextractor/sitemap)
sitemap.discovery: true
parsefilters.config.file: "parsefilters.json"
urlfilters.config.file: "urlfilters.json"
jsoup.filters.config.file: "jsoupfilters.json"
textextractor.no.text: false
textextractor.include.pattern:
- DIV[id="maincontent"]
- DIV[itemprop="articleBody"]
- ARTICLE
textextractor.exclude.tags:
- STYLE
- SCRIPT
jsoup.treat.non.html.as.error: false
parser.mimetype.whitelist:
- application/.+word.*
- application/.+excel.*
- application/.+powerpoint.*
- application/.*pdf.*
parse.tika.config.file: "tika-config.xml"
| 参数 | 默认值 | 说明 |
|---|---|---|
| parser.emitOutlinks | true | 解析后输出外链到 status 流(递归抓取的来源) |
| parser.emitOutlinks.max.per.page | -1 | 单页外链输出上限(-1 不限) |
| textextractor.no.text | false | true 时不抽取正文 |
| textextractor.include.pattern | 空(默认全文抽取) | CSS 选择器白名单,命中元素才抽文本 |
| textextractor.exclude.tags | STYLE/SCRIPT | 排除的标签 |
| jsoup.treat.non.html.as.error | 默认 true;archetype 改 false | false 时非 HTML 转交 Tika 流而非报错 |
| parser.mimetype.whitelist | 内置 word/excel/powerpoint/pdf 四类正则 | 允许 Tika 解析的 MIME 白名单 |
| parse.tika.config.file | 无默认(archetype 引用 tika-config.xml) | Tika 解析器配置;archetype 不生成该文件,需自建 |
| sitemap.discovery | 默认 false;archetype 改 true | 解析页面时自动发现 sitemap |
5.6 索引参数(indexer.*)
indexer.url.fieldname: "url"
indexer.text.fieldname: "content"
indexer.canonical.name: "canonical"
indexer.md.mapping:
- parse.title=title
- parse.keywords=keywords
- parse.description=description
- domain
- format
indexer.md.mapping决定元数据到索引字段的转换:parse.title=title表示把元数据键 parse.title 映射为字段 title;不带=的条目(domain、format)用元数据键原名作字段名;还支持key[0]取第 N 个值与parse.*通配。indexer.text.maxlength(默认 -1)控制正文字段长度;indexer.ignore.empty.fields(默认 false)过滤空值字段。
实测输出对照(StdOutIndexer 打印的字段即来自上述映射):
content StormCrawler Local Test Site Welcome to the local crawler test site. Page One Page Two Page Three
url http://localhost:8080/index.html
domain localhost
format html
title Local Test Site
5.7 元数据传递与持久化(metadata.*)
metadata.persist:
- _redirTo
- error.cause
- error.source
- isSitemap
- isFeed
metadata.transfer:随外链传递给子页面的元数据键(支持follow.*通配),默认为空。metadata.persist:仅持久化到状态存储、不外传的键。默认持久化重定向目标_redirTo、错误原因error.cause/error.source与isSitemap/isFeed标记。metadata.track.path/metadata.track.depth(默认 true):在元数据中记录抓取路径与深度,供 MaxDepthFilter 等使用。
5.8 后端参数(urlfrontier.*)
archetype 默认拓扑使用 URLFrontier 状态后端,crawler-conf.yaml 实测值:
urlfrontier.host: "localhost"
urlfrontier.port: 7071
urlfrontier.max.buckets: 50
urlfrontier.max.urls.per.bucket: 10
| 参数 | 默认值 | 说明 |
|---|---|---|
| urlfrontier.host / urlfrontier.port | localhost / 7071 | URLFrontier gRPC 服务地址 |
| urlfrontier.max.buckets | 50 | 同时拉取的最大队列桶数 |
| urlfrontier.max.urls.per.bucket | 10 | 每桶单次拉取的 URL 数 |
💡 说明:若使用 OpenSearch / Solr / SQL 后端,对应参数(如
opensearch.addresses、sql.connection等)由其模块的默认配置文件提供,写法同为「crawler-conf.yaml 覆盖」;内存后端(MemorySpout/MemoryStatusUpdater)无任何配置项,仅限本地调试。
六、生产配置模板
💡 适用场景:4 核 8GB 内存、单 supervisor、日均百万级页面、增量抓取的生产节点。Java worker 堆按 256-512MB 起步。
config:
topology.workers: 1
topology.message.timeout.secs: 300
topology.max.spout.pending: 200
topology.debug: false
# worker 堆限制在 512MB,保留 IPv4 栈
topology.worker.childopts: "-Xmx512m -Djava.net.preferIPv4Stack=true"
topology.kryo.register:
- org.apache.stormcrawler.Metadata
- org.apache.stormcrawler.persistence.Status
fetcher.threads.number: 50
fetcher.threads.per.queue: 1
fetcher.queue.mode: "byHost"
fetcher.server.delay: 1.0
fetcher.max.crawl.delay: 30
http.agent.name: "YourCrawler"
http.agent.version: "1.0"
http.agent.description: "Production crawler"
http.agent.url: "http://www.example.com"
http.agent.email: "root@example.com"
http.protocol.implementation: "org.apache.stormcrawler.protocol.okhttp.HttpProtocol"
https.protocol.implementation: "org.apache.stormcrawler.protocol.okhttp.HttpProtocol"
http.content.limit: 262144
http.timeout: 10000
fetchInterval.default: 10080
fetchInterval.fetch.error: 120
fetchInterval.error: -1
max.fetch.errors: 3
sitemap.discovery: true
parser.emitOutlinks: true
parser.emitOutlinks.max.per.page: 1024
indexer.url.fieldname: "url"
indexer.text.fieldname: "content"
indexer.text.maxlength: 1048576
indexer.md.mapping:
- parse.title=title
- parse.keywords=keywords
- parse.description=description
- domain
- format
metadata.persist:
- _redirTo
- error.cause
- error.source
- isSitemap
- isFeed
| 场景 | 建议配置 |
|---|---|
| 本地调试(2GB 内存单机) | MemorySpout/MemoryStatusUpdater 内存后端 + StdOutIndexer + STORM_JAR_JVM_OPTS=-Xms256m -Xmx512m + fetcher.threads.number 10 |
| 中小规模生产(4 核 8GB) | URLFrontier/OpenSearch 后端 + topology.workers 1 + max.spout.pending 200 + 堆 512MB |
| 大规模抓取(多 supervisor) | URLFrontier 集群 + topology.workers 2 以上 + fetcher.threads.number 100+ + byHost 队列 |
| 礼貌抓取(对源站友好) | fetcher.server.delay 5.0 + fetcher.max.crawl.delay 30 + threads.per.queue 1 |
七、常见问题
Q1:改了 crawler-conf.yaml 不生效?
配置打包进 uberjar,改完必须 mvn package 重新构建;另外检查参数是否被 flux 拓扑 config 段覆盖(flux 层优先级最高)。最直接的核实方式是看启动日志 Submitting topology ... with conf {...} 中的生效值。
Q2:启动报错 http.agent.name 缺失或为空?
StormCrawler 要求显式设置 http.agent.name(内置默认仅是注释示例)。在 crawler-conf.yaml 中设置 RFC 9309 合规的代理名(仅字母、数字、下划线、连字符)。
Q3:robots.txt 拒绝导致全站抓不到?
检查目标站 robots.txt 与代理名是否匹配;http.robots.403.allow: true 仅在 robots.txt 返回 403 时放行。robots 解析结果缓存在 robots.cache.spec(默认 6 小时)定义的 Guava 缓存中,改规则后需等缓存过期或重启拓扑。
Q4:抓取本机/内网站点被过滤?
archetype 自带 default-regex-filters.txt 默认拒绝 localhost/127.x 与 10/192.168/172.16 私网地址(防 SSRF)。内网或本地测试需注释对应规则行并重新构建;公网生产请保持开启。
Q5:worker 内存占用过高?
默认 topology.worker.childopts: "-Xmx2g ..." 偏大。生产建议改为 -Xmx512m(或 256MB)起步;本地模式用 STORM_JAR_JVM_OPTS="-Xms256m -Xmx512m" 注入,并以 jps -v 核对生效值(实测回显含 -Xms256m -Xmx512m)。
Q6:重定向页面重复抓取?
保持 http.allow.redirects: false(默认)由 RedirectionBolt 统一处理;若开启抓取端跟随,重定向页会同时进入两个处理路径。
八、参考链接
- StormCrawler 官方配置文档:
https://stormcrawler.net/ - 内置默认配置源文件:
https://github.com/apache/stormcrawler/blob/main/core/src/main/resources/crawler-default.yaml - Apache Storm 配置说明:
https://storm.apache.org/releases/2.8.8/Configuration.html - Flux 拓扑定义规范:
https://storm.apache.org/releases/2.8.8/flux.html