当然,要解决这个问题有很多办法;比如把purge接口的请求丢给消息队列,后台计划任务不停地消费消息队列发起purge请求;如果这么做确实可以解决问题,但是把整体架构复杂化了。 不用消息队列,很多人就会想到用异步;但是项目使用的是PHP,它是顺序执行,不支持异步的,怎么办? 拜读Laruence早期的文章: 根据文章中的介绍,果断采用fsockopen的方法: <?php function asyncGet($url) { $parts = parse_url($url); $fp = fsockopen( $parts['host'], isset($parts['port']) ? $parts['port'] : 80, $errno, $errstr, 3 ); $out = "GET " . $parts['path'] . " HTTP/1.1\r\n"; $out .= "Host: " . $parts['host'] . "\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); fclose($fp); } $start = microtime(true); asyncGet( 'http://cdn.ljf.me/purge.php' ); $end = microtime(true); $cost = $end - $start; echo "purge cdn cost: $cost s\n";问题来了,无论如何发送请求,服务器都没有正常地清洗缓存(直接输入url访问是可以正常清洗的,排除purge接口本身的问题)。
127.0.0.1 - - [18/Dec/2013:11:57:57 +0800] "GET /purge.php HTTP/1.1" 499 0 "-" "-" "-"在HTTP协议中没有直接定义499的状态码,这个状态码是nginx指定的。 /* from ngx_http_request.h */ /* * HTTP does not define the code for the case when a client closed * the connection while we are processing its request so we introduce * own code to log such situation when a client has closed the connection * before we even try to send the HTTP header to it */ #define NGX_HTTP_CLIENT_CLOSED_REQUEST 499 nginx对499的定义是”client has closed connection”,并且在这些情况下会返回这个状态码:
现在的问题是:我们要等nginx的upstream处理完并且把请求交给fastcgi之后,才能主动关闭连接,否则就不能正常的清洗CDN的缓存了。 function asyncGet($url) { $parts = parse_url($url); $fp = fsockopen( $parts['host'], isset($parts['port']) ? $parts['port'] : 80, $errno, $errstr, 3 ); $out = "GET " . $parts['path'] . " HTTP/1.1\r\n"; $out .= "Host: " . $parts['host'] . "\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); usleep(10000); fclose($fp); }一个不安全的做法是在fclose之前,让当前的进程先睡眠一段时间;我这里设置为10毫秒,这10毫秒的延迟对我完成整个请求的影响不大,同时我也认为nginx一定能在10毫米内把请求转到fastcgi去执行。这个时间间隔很难把握,不能保证php一定有执行到。 这种方式并不是真正的异步,只是很取巧的强制关闭连接而不等待服务器端响应。所以在Laruence的那2篇文章中,有2个问题:
Laruence这2篇博文都是08年写的,不知道当时是不是用apache做的测试。因为没有使用apache的场景,所以也就不打算用apache再验证一次。 转载请保留固定链接: https://linuxeye.com/program/1989.html |