挖洋货这项目,因为没有公司的名头,也就无法备案,所以前端机放在阿里云香港ecs,另配一台阿里云杭州ecs来跑crontab——执行爬虫、保存图片到阿里云oss等。最近觉得杭州ecs有点多余了(原本还有个杭州rds的,统一搬到香港rds了),打算撤掉,就把杭州ecs上的crontab全部搬回香港ecs来跑,这下就引发不少问题了。
引发什么问题了呢?最核心的问题是香港ecs处在国际网络环境,访问大陆服务器时经常会出现网络抖动的现象,非常无解。具体一点来说,比如香港ecs向阿里云杭州open search(open search没有香港节点呀亲 ╥﹏╥...)查询的时候,经常报错;又比如香港ecs抓到图片后上传杭州oss(oss是有香港节点,问题是没有图片处理的服务啊,你们说这不是坑死人吗),慢是其次,经常卡住一段时间后才报错,这使得上传的效率极其低下(我会告诉你就因为这个原因,积压了好几千爬回来的商品等着上传图片才能上架吗)。
open search的问题还是很好解决的,sdk有提供超时的配置,我把超时限制设大了一点(5秒),基本上就不会报错了。
而oss的sdk根本没有提供这方面的配置,为了解决这个问题,我决定深入到这sdk来修改源码。
oss的sdk是通过php-curl来请求api的,经调查后,我发现此sdk有个名为requestcore.class.php的文件中定义了一个requestcore类,很明显,这个类就是负责发送请求的。其中,prep_request()负责配置curl,send_request($parse = false)则负责执行curl(即真正发送请求)。
首先来看看prep_request(),其中包含两个php-curl的两个超时配置:curlopt_timeout以及curlopt_connecttimeout
curl_setopt($curl_handle, curlopt_timeout, 5184000);
curl_setopt($curl_handle, curlopt_connecttimeout, 120);
curlopt_timeout好理解,就是整个curl请求过程(http request & response)的超时限制,以秒为单位,设置为0则无限制。
curlopt_connecttimeout比较难理解,目前确认的是,这是curl请求过程中的一小部分,因此必须要设得比curlopt_timeout小,不然curlopt_timeout无意义。网上的资料是这么说的:
curlopt_connecttimeout 在发起连接前等待的时间,如果设置为0,则无限等待。
这个发起连接前等待的时间比较模糊,我倾向于这指的是完成tcp三次握手过程前所耗费的时间,或者换句话说,tcp三次握手的整个过程必须要在curlopt_connecttimeout内完成,否则就超时。tcp三次握手无法在指定时间内完成表示服务器正处在繁忙/奔溃的状态或网络异常,这正符合本文所提到的场景。
基于这一猜想下,我把curlopt_connecttimeout设成3秒:
curl_setopt($curl_handle, curlopt_connecttimeout, 3);
如此,就不需要在网络抖动的时候等待2分钟(sdk设定的curlopt_connecttimeout是120秒)才报错了。
ps:如果想要设置超时时间少于1秒,需要用到curlopt_timeout_ms,但此配置据鸟哥说有bug,未测试,留个心眼:《curl的毫秒超时的一个”bug”》
以上就介绍了 应对恶劣网络环境,为php-curl设置超时限制,防止服务器卡死,包括了crontab,保存图片方面的内容,希望对php教程有兴趣的朋友有所帮助。