在 php 循环中将数据写入 redis 时发生了有趣的事情

Interesting thing happened while writing data into redis within a php loop

我写了一个 php 脚本来将数据从一台服务器(我们称之为服务器 A)拉到另一台服务器(服务器 B)。服务器A中的数据是一个redis列表,存储了所有需要写入服务器B的操作命令,如:

["setex",["session:xxxx",604800,"xxxx"]]
["set",["uid:xxx","xxxxx"]]
["pipeline",[]]
["set",["uid:xxx","xxxxx"]]
["hIncrBy",["Signin:xxxx","totalTimes",1]]
["pipeline",[]]
....

我的 php 代码是:

while($i < 1000){
    $line = $redis['server_a']->rpop('sync:op');
    list($op,$params) = json_decode($line,1);
    $r = call_user_func_array(array($redis['server_b'], $op), $params);

    $i++;
}

有线的是,当call_user_func_array方法错误执行redis命令时,队列中的所有rest命令都无法正确写入服务器B。

为了寻求答案,我在这个问题上卡了将近一个星期。经过数千次测试,我发现如果删除无法正确执行的 "bad commands",例如 ["pipeline",[]] 行。可以正确插入所有其他命令。所以它让我想起了一些redis交易问题。 也许有一些机制,当一个命令在 redis 中执行不当时,之后的所有其他命令都将被视为一个事务。所以我在 while 循环中添加了一个 exec() 命令:

 while($i < 1000){
    $line = $redis['server_a']->rpop('sync:op');
    list($op,$params) = json_decode($line,1);
    $r = call_user_func_array(array($redis['server_b'], $op), $params);
    $redis['server_b']->exec(); //this is the significant update
    $i++;
}

那么,我的问题就解决了!!!

我的问题是,谁能帮我解释一下redis的机制?我的假设正确吗?

您的图书馆可能出于某种原因正在使用事务处理流水线。 pipeline 不是实际的 Redis 命令,参见 http://redis.io/commands

只需删除所有带有空参数的 pipeline 命令,或者在您之前发出 pipeline 时只使用 ->exec