在ECS上有个论坛,首页以及各分区页正常,但是打开版块页,也就是帖子列表页时,间隔性的出现速度缓慢的现象,最长的有15s。最开始以为是ECS的环境配置错了,就换到万网主机上测试,结果一样。后来多弄了几个空DZ,一个个排查设置项,最后发现是云端IP库检测惹的祸。

在之前也有粗略搜索过这个问题,但没找到有用的信息。而发现问题所在后,才看到以下的文章,要不然就不用折腾这么久了。

充斥着TX元素的DZ,说实在的不怎么喜欢,可以的话,我还是会选择PW。

==================================================================

前一阵子,就感觉到基于Discuz搭建的会员互动社区打开贴子异常缓慢(响应时间1到10几秒不等),别的页面却是正常的(响应时间200ms左右)。浏览一个贴子需要等待好几秒,我自己使用起来都挺上火的,更何况其他活跃的会员?今天就抽出时间,分析导致Discuz贴子打开缓慢的原因。

除了PHP守护进程,正常情况下PHP程序的运行时间不会太慢,基本都是以ms为单位的。如果出现秒级的响应,很多时候都是sql语句不合理导致的。

然而我在MariaDB的慢日志中并没有找到相关的记录,看来只能老老实实的分析Xdebug日志,看看Discuz究竟慢在哪了。

Xdebug日志中显示,/source/module/forum/forum_viewthread.php文件中第284行代码运行了长达10,900ms!

list($seccodecheck, $secqaacheck) = seccheck('post', 'reply');

再往下分析,就找到了/source/class/helper/helper_seccheck.php文件第300行代码$return[0] = captcha::isneed();运行耗时10,571ms,代码如下:

public static function seccheck($rule, $param = array()) {
    global $_G;
    if($_G['uid'] && !checkperm('seccode')) {
        return array();
    }
    if(method_exists('helper_seccheck', 'rule_'.$rule)) {
        $return = call_user_func(array('helper_seccheck', 'rule_'.$rule), $param);
        if(!isset($_G['cookie']['seccloud'])) {
            if($_G['setting']['seccodedata']['cloudip'] && !$return[0]) {
                $return[0] = captcha::isneed();
                if($return[0]) {
                    dsetcookie('seccloud', 1);
                }
            }
        } else {
            $return[0] = true;
        }
        return $return;
    } else {
        return array();
    }
}

很明显,这条语句是根据条件来判断是否运行的,当看到$_G[‘setting’][‘seccodedata’][‘cloudip’]的时候,我突然想起了,好像以前在后台开启了某些“云”功能。

果然,找到Discuz后台的 防水墙->验证码->云端IP库检测,然后选择否,提交保存。现在重新打开贴子,响应时间就恢复到了200ms左右。

云端IP库检测:启用后当用户的登录 IP 在云端可疑 IP 库中时,用户的注册、登录、发表等操作会自动启用验证码。Discuz官方是这么描述这个功能的。

有兴趣的朋友,可以继续往下看,我的跟踪记录。

其实captcha::isneed();就是调用了/source/function/function_filesock.php文件中定义的_dfsockopen()函数,从某个API获取数据。

因为68行代码运行了10,559ms,所以我为了获取导致响应缓慢的API地址,就在68行后添加了一些判断代码:

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
$data = curl_exec($ch);
$time = time();
if( $time - $_SERVER['REQUEST']  > 5) {
    echo $scheme.'://'.($ip ? $ip : $host).($port ? ':'.$port : '').$path;
}

运行后,输出类似如下:

http://api.discuz.qq.com:80/captcha/isNeed?appId=321122415&clientIp=10.0.0.87&dzVersion=X3.2&openId=44A2245222FE28B91D0D0B969312686E&sId=34707439&uid=2279&ver=1.0&ts=1416967960&sig=eb6a3333d37cc7f556873841732d8d18

所以贴子响应慢,就是因为这个提供IP检测的API接口性能太差导致的。

原文