phpredis管道是否与使用协议进行大规模插入相同?

phpredis管道是否与使用协议进行大规模插入相同?,php,insert,redis,phpredis,Php,Insert,Redis,Phpredis,我正在将我的站点的一部分从关系数据库移动到Redis,需要在可能短的时间内插入数以百万计的密钥 在我的例子中,数据必须首先从MySQL获取,由PHP准备,然后添加到相应的排序集(时间作为分数+ID作为值)。目前我正在使用phpredis multi-method的Redis::PIPELINE参数。尽管速度有了明显的提高,但在执行导入时,它还是阻止了读取并减慢了加载时间 所以问题来了——在phpredis中使用管道是否等同于中描述的质量插入 下面是一个例子: phpredis方式: 我是p

我正在将我的站点的一部分从关系数据库移动到Redis,需要在可能短的时间内插入数以百万计的密钥

在我的例子中,数据必须首先从MySQL获取,由PHP准备,然后添加到相应的排序集(时间作为分数+ID作为值)。目前我正在使用phpredis multi-method的
Redis::PIPELINE
参数。尽管速度有了明显的提高,但在执行导入时,它还是阻止了读取并减慢了加载时间

所以问题来了——在phpredis中使用管道是否等同于中描述的质量插入


下面是一个例子:

  • phpredis方式:


我是phpredis的撰稿人之一,所以我可以回答你的问题。简短的回答是,这是不一样的,但我会提供更多的细节

当您将phpredis放入
Redis::PIPELINE
模式时,会发生的情况是,它不会在调用命令时发送命令,而是将其放入“待发送”命令列表中。然后,一旦调用
exec()
,就会用所有命令创建一个大的命令缓冲区并发送到Redis

命令全部发送后,phpredis读取每个回复并根据每个命令规范打包结果(例如,
HMGET
调用作为关联数组返回等)


phpredis中的流水线性能实际上相当好,应该足以满足几乎所有用例。也就是说,您仍然在通过PHP处理每个命令,这意味着您将通过为每个命令调用phpredis扩展本身来支付函数调用开销。此外,phpredis将花费时间处理和格式化每个回复

如果您的用例需要将大量数据导入Redis,特别是如果您不需要处理每个回复(而是只想知道所有命令都已处理),那么批量导入方法就是最好的选择

实际上,我在这里创建了一个项目:

此扩展背后的思想是,您可以使用命令调用它,然后将缓冲区保存到磁盘,磁盘将采用原始Redis协议,并与
cat buffer.txt | Redis cli--pipe
样式插入兼容

需要注意的一点是,目前不能简单地将任何给定的phpredis调用替换为对RedisMI对象的调用,因为命令被处理为变量参数调用(如hiredis),这适用于大多数但不是所有phpredis命令

下面是一个简单的示例,说明如何使用它:

<?php
$obj_mi = new RedisMI();

// Some context we can pass around in RedisMI for whatever we want
$obj_context = new StdClass();
$obj_context->session_id = "some-session-id";

// Attach this context to the RedisMI object
$obj_mi->SetInfo($obj_context);

// Set a callback when a buffer is saved
$obj_mi->SaveCallback(
    function($obj_mi, $str_filename, $i_cmd_count) {
        // Output our context info we attached
        $obj_context = $obj_mi->GetInfo();
        echo "session id: " . $obj_context->session_id . "\n";

        // Output the filename and how many commands were sent
        echo "buffer file: " . $str_filename . "\n";
        echo "commands   : " . $i_cmd_count . "\n";
    }
);

// A thousand SADD commands, adding three members each time
for($i=0;$i<1000;$i++) {
    $obj_mi->sadd('some-set', "$i-one", "$i-two", "$i-three");
}

// A thousand ZADD commands
for($i=0;$i<1000;$i++) {
    $obj_mi->zadd('some-zset', $i, "member-$i");
}

// Save the buffer
$obj_mi->SaveBuffer('test.buf');
?>

干杯

谢谢你的回答!我设法处理了数据库中的2000万行,并使用事务在redis中存储了大约250万个密钥。然而,由于redis非常出色,并且在我们的堆栈中发挥了巨大的作用,因此在未来我一定会尝试您的解决方案。
cat data.txt | redis-cli --pipe
<?php
$obj_mi = new RedisMI();

// Some context we can pass around in RedisMI for whatever we want
$obj_context = new StdClass();
$obj_context->session_id = "some-session-id";

// Attach this context to the RedisMI object
$obj_mi->SetInfo($obj_context);

// Set a callback when a buffer is saved
$obj_mi->SaveCallback(
    function($obj_mi, $str_filename, $i_cmd_count) {
        // Output our context info we attached
        $obj_context = $obj_mi->GetInfo();
        echo "session id: " . $obj_context->session_id . "\n";

        // Output the filename and how many commands were sent
        echo "buffer file: " . $str_filename . "\n";
        echo "commands   : " . $i_cmd_count . "\n";
    }
);

// A thousand SADD commands, adding three members each time
for($i=0;$i<1000;$i++) {
    $obj_mi->sadd('some-set', "$i-one", "$i-two", "$i-three");
}

// A thousand ZADD commands
for($i=0;$i<1000;$i++) {
    $obj_mi->zadd('some-zset', $i, "member-$i");
}

// Save the buffer
$obj_mi->SaveBuffer('test.buf');
?>
➜  tredismi  php mi.php
session id: some-session-id
buffer file: test.buf
commands   : 2000
➜  tredismi  cat test.buf|redis-cli --pipe
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 2000