6

我正在将我网站的某些部分从关系数据库移动到 Redis,并且需要在可能很短的时间内插入数百万个键。

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

那么问题来了 -在 phpredis 中使用管道是否等同于http://redis.io/topics/mass-insert中描述的大量插入?


这是一个例子:

  • phpredis方式:

    <?php
    
    // All necessary requires etc.
    $client = Redis::getClient();    
    
    $client->multi(Redis::PIPELINE); // OR $client->pipeline();
    $client->zAdd('key', 1, 2);
    ...
    $client->zAdd('key', 1000, 2000);
    $client->exec();
    
  • 来自 redis.io 的vs协议:

    cat data.txt | redis-cli --pipe
    
4

1 回答 1

10

我是phpredis的贡献者之一,所以我可以回答你的问题。简短的回答是它不一样,但我会提供更多细节。

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

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


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

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

我实际上在这里创建了一个项目: https ://github.com/michael-grunder/redismi

这个扩展背后的想法是你用你的命令调用它,然后将缓冲区保存到磁盘,这将在原始 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');
?>

然后你可以做这样的事情:

➜  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

干杯!

于 2013-10-09T20:31:47.807 回答