用 scrapy 写爬虫时 ,过程中碰到有一些网页元素需要通过 JS 加载,而且获取数据的 API 限制重重,这种情况下选择 splash 来进行渲染往往是最好的选择了。然而使用下来的体验,包括网络上也有相同的抱怨,那就是 splash 虽好,但太不稳定了。在高强度负载下,挂掉几乎是必然的。接下来记录我遇到的其中一种死法:
问题
操作系统:macOS 10.13.4
Docker 版本:18.03.0-ce
splash 版本:3.2
描述:
对页面进行持续渲染时,scrapy 会突然抛出 splashrequest 返回 timeout 的异常,这时 splah 服务其实已经挂掉了。在 docker 中查看容器,发现状态为Exited (1)
,接着在日志中发现挂之前留下的最后记录为:
The X11 connection broke (error 1). Did the X11 server die?
在 splash 运行一段时间后,这个问题总是会随机出现。
解决
问题出现以后上网查了下相似的情况,发现不是很多,而且并不是 splash 的特有问题,在尝试了调整延时、修改 Docker 使用的内存大小无效后,最后在 splash 的 github 中的一个 iusses 里,找到了一个方法:
This may just be coincidence and may not apply to everyone else's crashing but I noticed that Docker started crashing when I added the following and stopped crashing when I removed it.
splash.images_enabled = false
恰好我的设置里也包含了这一项,不加载图片可大大提高爬虫效率,一开始看到时不认为这个设置会导致问题的发生,最后将这一项设为true
后,问题竟然解决了...
如果你的情况和我一样,可以尝试使用这个方案,但不能保证一定能解决你的问题。
曲线救国
因为每次修改后需要长时间运行来检测问题是否被解决,所以解决这个问题用了较长的时间,最后问题虽然解决了,但仍旧不知道具体原因,可谓是一次失败的 debug 了。
是否有更好的解决方案?答案是肯定的,既然 splash 老挂又找不到原因,那么我们可以让其挂了以后 restart 嘛,后来在官方 FAQ 中发现了如下方法:
A command for starting a long-running Splash server which uses up to 4GB RAM and daemonizes & restarts itself could look like this:
$ docker run -d -p 8050:8050 --memory=4.5G --restart=always scrapinghub/splash:3.1 --maxrss 4000
上述语法可以限制容器所用内存,并在占用内存超过设定值/容器挂掉时重启容器,一种曲线救国的方法。
写到这里不禁反思,在产品设计中许多场景也是这样,虽然好的产品设计和用户体验通常是正相关的,但在现实中,由于种种原因(技术限制、终端差异、用户素质),我们必须在好设计和好体验中找到平衡。
后记
其实心里一直有个疑问,这个错误日志究竟是什么意思?在这里稍作记录:
X11 是什么?
X11 是 unix 和 linux 控制和显示图形界面的协议,和 http 协议类似,X 程序端通过 X 协议向 X server 传输需要在显示器上显示的信息,并由 X server 负责执行,X server 同时负责将用户输入的信息返回 X 程序端。和 http 协议不同的一点是,这里的 X server 通常是面向用户的。
splash 为什么会用到 X ?
splash 的运行依赖 Docker ,而 Docker 的守护进程是基于 linux 的。由于 splash 支持WebKit 中的 Web Inspector ,所以会用到 X 。(待考证)
说了这么多,到底为什么会 crash ?
很遗憾,目前仍旧未知。留个坑,希望以后可以为自己解答吧....
网友评论