文档章节

Curl的毫秒超时的一个”Bug”

BearCatYN
 BearCatYN
发布于 2015/04/29 12:20
字数 666
阅读 135
收藏 5

最近我们的服务在升级php使用的libcurl, 期望新版本的libcurl支持毫秒级的超时, 从而可以更加精细的控制后端的接口超时, 从而提高整体响应时间.

但是, 我们却发现, 在我们的CentOS服务器上, 当你设置了小于1000ms的超时以后, curl不会发起任何请求, 而直接返回超时错误(Timeout reached 28).

原来, 这里面有一个坑, CURL默认的, 在Linux系统上, 如果使用了系统标准的DNS解析, 则会使用SIGALARM来提供控制域名解析超时的功能, 但是SIGALARM不支持小于1s的超时, 于是在libcurl 7.28.1的代码中(注意中文注释行):

int Curl_resolv_timeout(struct connectdata *conn,
                        const char *hostname,
                        int port,
                        struct Curl_dns_entry **entry,
                        long timeoutms)
{
.......
.......
#ifdef USE_ALARM_TIMEOUT
  if(data->set.no_signal)
    /* Ignore the timeout when signals are disabled */
    timeout = 0;
  else
    timeout = timeoutms;
 
  if(!timeout)
    /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
    return Curl_resolv(conn, hostname, port, entry);
 
  if(timeout < 1000) //如果小于1000, 直接超时返回
    /* The alarm() function only provides integer second resolution, so if
       we want to wait less than one second we must bail out already now. */
    return CURLRESOLV_TIMEDOUT;
 
  ....
  ....

可见, 当你的超时时间小于1000ms的时候, name解析会直接返回CURLRESOLV_TIMEOUT, 最后会导致CURLE_OPERATION_TIMEDOUT, 然后就Error, Timeout reached了…

这….太坑爹了吧? 难道说, 我们就不能使用毫秒超时么? 那你提供这功能干啥?

还是看代码, 还是刚才那段代码, 注意这个(中文注释行):

#ifdef USE_ALARM_TIMEOUT
  if(data->set.no_signal)  //注意这行
    /* Ignore the timeout when signals are disabled */
    timeout = 0;
  else
    timeout = timeoutms;
 
  if(!timeout)
    /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
    return Curl_resolv(conn, hostname, port, entry);
 
  if(timeout < 1000)
    /* The alarm() function only provides integer second resolution, so if
       we want to wait less than one second we must bail out already now. */
    return CURLRESOLV_TIMEDOUT;

看起来, 只要set.no_signal 这个东西为1, 就可以绕过了… 那这个玩意是啥呢?

这就简单了, grep一下代码, 发现:

 
  case CURLOPT_NOSIGNAL:
    /*
     * The application asks not to set any signal() or alarm() handlers,
     * even when using a timeout.
     */
    data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE;
    break;

哈哈, 原来是这货:

<?php
   curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
?>

加上这个OPT以后, 一切终于正常了!

后记:

这样一来, 就会有一个隐患, 那就是DNS解析将不受超时限制了, 这在于公司内部来说, 一般没什么问题, 但是万一DNS服务器hang住了, 那就可能会造成应用超时.

那么还有其他办法么?

有, 那就是Mike提醒的, 我们可以让libcurl使用c-ares(C library for asynchronous DNS requests)来做名字解析. 具体的可以在config curl的时候:


本文转载自:http://www.laruence.com/2014/01/21/2939.html

共有 人打赏支持
BearCatYN
粉丝 26
博文 158
码字总数 11947
作品 0
朝阳
程序员
私信 提问
阅读鸟哥的风雪之隅PHP博客的笔记(1)

在PHP中使用协程实现多任务调度 http://www.laruence.com/2015/05/28/3038.html 2. Curl的毫秒超时的一个”Bug” CentOS服务器上, 当你设置了小于1000ms的超时以后, curl不会发起任何请求, 而...

laiconglin
2016/06/12
45
0
curl连接时间设置

CURL访问HTTP: CURL 是常用的访问HTTP协议接口的lib库,性能高,还有一些并发支持的功能等。 curl_setopt($ch, opt) 可以设置一些超时的设置,主要包括: (重要) CURLOPT_TIMEOUT 设置cURL允...

colin_86
2015/10/23
3
0
为什么你必须得学些 TCP/IP 的知识?

题外话:通信通讯三次握手?你还在停留在这个级别么,对于专业网络者和开发者而言,同步和异步的通信变得更加重要和迫切。 这不是指要明白 TCP 的所有东西,也不是说要通读 《TCP/IP 详解》。...

English0523
2016/01/12
0
0
curl的设置超时时间小于1000ms时无效

curl版本>7.16.2,支持CURLOPTTIMEOUTMS,请求响应时间很小,小于5ms,设置CURLOPTTIMEOUTMS为120ms,不能正确得到响应。要做一个实时竞价的东西,往外发几个百请求,目前用的是curlmultiex...

Zone
2011/04/08
1K
0
世界最著名的四大bug

世界最著名的四大bug 程序师2018-01-030 阅读 bug业界观察 “电子邮件无法发送到 500 英里以外” Bug界最经典的传奇之一 我在做校园的邮件系统管理员的时候,有用户向我抱怨说:他们不能发送...

程序师
01/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Nginx+Keepalived实现站点高可用

Nginx+Keepalived实现站点高可用

吴伟祥
5分钟前
0
0
git常用命令速查表

任梁荣
8分钟前
1
0
一文带你学会使用YOLO及Opencv完成图像及视频流目标检测(上)

摘要: 本文介绍使用opencv和yolo完成图像目标检测,代码解释详细,附源码,上手快。 计算机视觉领域中,目标检测一直是工业应用上比较热门且成熟的应用领域,比如人脸识别、行人检测等,国内...

阿里云官方博客
10分钟前
0
0
SpringBoot整合RabbitMQ之典型应用场景实战二

实战前言 RabbitMQ 作为目前应用相当广泛的消息中间件,在企业级应用、微服务应用中充当着重要的角色。特别是在一些典型的应用场景以及业务模块中具有重要的作用,比如业务服务模块解耦、异步...

liwei2000
12分钟前
0
0
ES6这些就够了

刚开始用vue或者react,很多时候我们都会把ES6这位大兄dei加入我们的技术栈中。但是ES6那么多那么多特性,我们真的需要全部都掌握吗?秉着二八原则,掌握好常用的、有用的这个可以让我们的开...

文文1
21分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部