bzzear 2017-06-21 10:08:37 9722次浏览 4条回复 2 1 0

yii2.0中redis使用过程中踩过的坑(读取redis巨慢)

$startTime = microtime(true);
$rsp = Yii::$app->redis->get($key);
$endTime = microtime(true);
$elapsed = number_format($endTime - $startTime, 4);
echo $elapsed;

在执行读取redis数据的过程中,这个巨慢 执行的结果是2.2772s,平均都要2.2s以上

然后发现在yii里面并没有用到php-redis的扩展 自己写了一个用php-redis的方法来看,

$startTime = microtime(true);
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$rsp = $redis->get($key);
$endTime = microtime(true);
$elapsed = number_format($endTime - $startTime, 4);
echo $elapsed;

这个的执行的结果是0.0004s,差别n级别

最后在vendor/yiisoft/yii2-redis/Connection.php 692行中直接return $data

private function parseResponse($command)
{
    $startTime = microtime(true);
    if (($line = fgets($this->_socket)) === false) {
        throw new Exception("Failed to read from socket.\nRedis command was: " . $command);
    }
    $type = $line[0];
    $line = mb_substr($line, 1, -2, '8bit');
    switch ($type) {
        case '+': // Status reply
            if ($line === 'OK' || $line === 'PONG') {
                return true;
            } else {
                return $line;
            }
        case '-': // Error reply
            throw new Exception("Redis error: " . $line . "\nRedis command was: " . $command);
        case ':': // Integer reply
            // no cast to int as it is in the range of a signed 64 bit integer
            return $line;
        case '$': // Bulk replies
            if ($line == '-1') {
                return null;
            }
            $length = (int)$line + 2;
            $data = '';
            while ($length > 0) {
                if (($block = fread($this->_socket, $length)) === false) {
                    throw new Exception("Failed to read from socket.\nRedis command was: " . $command);
                }
                $data .= $block;
                $length -= mb_strlen($block, '8bit');
            }

            $endTime = microtime(true);
            $elapsed = number_format($endTime - $startTime, 4);
            echo $elapsed;
            return $data;
            return mb_substr($data, 0, -2, '8bit');
        case '*': // Multi-bulk replies
            $count = (int) $line;
            $data = [];
            for ($i = 0; $i < $count; $i++) {
                $data[] = $this->parseResponse($command);
            }

            return $data;
        default:
            throw new Exception('Received illegal data from redis: ' . $line . "\nRedis command was: " . $command);
    }
}

这里的耗时是0.0017s,所以定位的问题是在下面这行代码中

return mb_substr($data, 0, -2, '8bit');

最后,发现是php的mb_string的扩展没有装(好奇怪,没装这个还能用这个mb_substr函数,还能获得正确的结果); 安装这个扩展sudo apt-get install php7.0-mbstring。 再访问,耗时0.0012s,问题解决

觉得很赞
  • 回复于 2017-06-22 08:59 举报

    多谢分享,谢谢呀

    1 条回复
    回复于 2017-06-22 11:17 回复

    一起踩坑,一起学习

  • 回复于 2017-07-27 19:26 举报

    我在本地win7 64bit 上也遇到了同样的问题,mb_string php-redis 都安装了,怎么直接用yii2-redis还是非常慢呢?求教求教

    1 条回复
    回复于 2017-07-28 20:19 回复

    你也得一点点去找出问题来

  • 回复于 2017-07-30 13:38 举报

    找到了,问题出在了设置上,在win7上host一定不要用localhost,用127.0.0.1,两者差距大约一秒。在网上查到一个英文帖子说的大体是因为win7上IPv6的因素,具体也不是很明白,反正是改了host后就没有事了。另外yii2-redis好像不是用的php-redis扩展,而是用的socket。

    1 条回复
    回复于 2017-07-31 09:51 回复

    对的, yii2-redis用的不是php-redis

  • 回复于 2019-10-17 10:23 举报

    我也遇到过,不过吧redis 配置中的hostname 的 localhost 改为 'hostname' => '127.0.0.1' 就好了……

您需要登录后才可以回复。登录 | 立即注册