6.4 项目部署:定时任务与运行监控 本节摘要:部署要解决三件事:环境隔离地搬上服务器、任务定时或持续地跑、出了事有人知道。本节给出从零到无人值守的最短路径——工程同步、定时调度、日志轮转、失败告警与最少监控项,并简述专用部署组件的定位。 本地开发与线上运行是两个世界。本地出了错你当场看到;线上爬虫半夜三点静默死掉,第二天才发现数据断了一截——部署的全部意义,就是把"静默失败"变成"有人知道"。本节按最短路径走:环境、调度、观测。 第一步:工程上服务器 环境隔离的原则第 1 章就定了,服务器上照做: requirements.txt 从开发机导出: 。版本要锁死——线上环境与开发环境依赖不一致,是最冤枉的一类故障。
本节摘要:部署要解决三件事:环境隔离地搬上服务器、任务定时或持续地跑、出了事有人知道。本节给出从零到无人值守的最短路径——工程同步、定时调度、日志轮转、失败告警与最少监控项,并简述专用部署组件的定位。
本地开发与线上运行是两个世界。本地出了错你当场看到;线上爬虫半夜三点静默死掉,第二天才发现数据断了一截——部署的全部意义,就是把"静默失败"变成"有人知道"。本节按最短路径走:环境、调度、观测。
环境隔离的原则第 1 章就定了,服务器上照做:
# 服务器侧:代码与依赖各就各位 git clone git@git.example.com:team/bookstation.git /srv/bookstation cd /srv/bookstation python -m venv venv && venv/bin/pip install -r requirements.txt venv/bin/scrapy list # 部署自检:能列出爬虫即装好了 # books
requirements.txt 从开发机导出:pip freeze > requirements.txt。版本要锁死——线上环境与开发环境依赖不一致,是最冤枉的一类故障。
轻量方案用系统定时器直接驱动,一条命令即是一个任务:
# crontab:每天凌晨三点跑一次,日志按天落盘 0 3 * * * cd /srv/bookstation && venv/bin/scrapy crawl books -s LOG_FILE=logs/books-$(date +\%F).log
断点续抓在这里正式登场:给任务配 JOBDIR(3.1 节),中断的旅程下次启动接着走:
0 3 * * * cd /srv/bookstation && venv/bin/scrapy crawl books -s JOBDIR=crawls/books-001 -s LOG_FILE=logs/books-$(date +\%F).log
任务多了以后,裸定时器会露出管理短板:任务互相依赖、失败重跑、并发互斥都要手工管。这时换专用部署组件(如社区常用的远程调度平台),它的定位是"爬虫的任务管理器"——把工程打包上传、按计划调度、界面看运行历史。组件选型见 6.5 节生态地图,本节先把裸定时器跑通,管理痛点真的出现了再升级。
长跑任务的日志管理两条硬规矩:按天轮转、落盘留档。上面 crontab 里的按天文件名是一种朴素实现;更规范的做法在配置里指定文件,交给系统的日志轮转工具管理。
告警的最小可用版:任务收尾时检查统计里的关键计数,异常即发通知。用第 3 章的信号系统实现收尾检查,是最顺手的挂载点:
class DeployGuardExtension: def __init__(self, crawler): crawler.signals.connect(self.on_close, signal=signals.spider_closed) self.crawler = crawler @classmethod def from_crawler(cls, crawler): return cls(crawler) def on_close(self, spider, reason): stats = self.crawler.stats.get_stats() items = stats.get("item_scraped_count", 0) errors = stats.get("spider_exceptions", 0) # 阈值判据:产出为零 或 关闭原因异常 即告警 if items == 0 or reason != "finished": spider.logger.error("运行异常:产出 %s,原因 %s,异常 %s", items, reason, errors) notify_ops("bookstation 运行异常,请查日志") # 接你的通知渠道
告警判据的经验值:产出为零必告警;产出环比骤降(今天只有昨天的一成)也值得告警——那多半是站点改版击穿了选择器,爬虫本身"正常"跑完却一无所获。这正是第 5 章说的拆包失效,监控是它的最后一道网。
背景:第 2 章到第 6 章一路打磨的图书采集工程要交付运营,要求每日凌晨自动运行、失败能当天发现。上线动作按时间顺序记录如下。
操作一,打包同步:requirements 锁版本、代码进版本库、服务器克隆加建虚拟环境,scrapy list 自检通过。操作二,首次线上试跑:手动触发,带保险丝限两百页,核对统计与产出文件——这一步专抓环境差异(线上缺某个系统库、时区不对之类)。操作三,配定时:crontab 每日三点,日志按天落盘,JOBDIR 断点目录就位。操作四,挂告警:收尾扩展部署上去,通知渠道对接运维群。操作五,演练故障:故意把某个选择器改成必然失配的版本跑一次,验证"产出为零"的告警真的会响——告警没演练过的部署不算部署完成。
# 上线核验三连(每次发布后跑) venv/bin/scrapy list venv/bin/scrapy crawl books -s CLOSESPIDER_PAGECOUNT=50 -o /tmp/preflight.jsonl grep "finish_reason" logs/preflight.log
结果:上线两周内告警触发一次——某分类页改版导致该分类产出为零,当天修复重跑,损失控制在日更窗口内。解读:这次告警抓到的是 5.3 节预判过的"拆包失效",监控的价值不在防错,而在把错误的发现时间从"数周后对账"提前到"当天"。变式:任务升级为多机后(6.3 节),上线核验加一条——三台机器的指纹共享连通性测试,防止某台机器悄悄变成"重复劳动户"。
无人值守的底线监控,五项足够起步:
| 监控项 | 数据来源 | 告警条件 |
|---|---|---|
| 任务退出原因 | 统计 finish_reason | 非 finished |
| 产出量 | item_scraped_count | 为零或环比骤降 |
| 失败率 | retry 与 exception 计数 | 超过基线数倍 |
| 运行时长 | 任务起止时间 | 超常态一倍 |
| 磁盘占用 | 日志与断点目录 | 超过阈值 |

⚠️ 常见坑:用 root 跑定时任务。权限最小化原则在部署里同样成立——专用账号、受限目录、独立虚拟环境,事故时破坏面小得多。
无人值守跑起来了。最后一节逛逛生态:轮子在哪、惯例是什么、继续往哪走。