连接redis集群报错:(error) MOVED的解决方法

1. 现象描述

在使用redis集群的时候,当我们连接一个节点的时候,如果这个节点不是主节点,而是从节点,那么我们的连接命令会报错,提示错误信息为(error) MOVED。表示所连接的节点已经不是该数据的归属节点了,需要我们重新去找该数据所在的节点。

2. 错误原因

redis集群中,有6个节点,在节点1加入一个数据后(假设是字符串类型),redis会对该数据执行CRC16运算,得到一个整型数,然后对整型数取模,得到一个数字n,在redis集群中n对应的节点就是数据的归属节点,存储了该数据。但是这里的问题在于,每个节点都有可能是主节点也有可能是从节点,也就是说通过连接某一个节点,我们不能确定该节点是否是我们想要的归属节点,所以在连接从节点并执行命令的时候,如果该从节点的数据发生了迁移,就会报错。

3. 解决方法

3.1 迁移前确认节点状态

在使用redis集群的时候,我们可以通过命令 redis-cli cluster nodes 查看所有节点的状态,找到主节点,然后连接主节点。如果我们要执行一些读操作,连接的从节点就可以了。如果我们要执行一些写操作,在连接之前先使用 redis-cli cluster keyslot key 命令获取数据所在的槽信息,然后在连接节点之前先检查该节点是否为相应槽的主节点,如果是,连接该节点执行操作,否则使用新的节点重新连接。

# 查看所有节点的状态

$ redis-cli cluster nodes

# 获取槽信息,并检查所连接的节点是否为主节点

$ redis-cli -c cluster keyslot mykey

$ redis-cli -c cluster nodes | grep 1234

3.2 使用redis的客户端

除了手动连接节点进行操作之外,我们也可以使用redis的客户端来连接redis集群。例如php语言,我们可以使用 Predis 客户端来连接redis,具体操作可以参考 这篇文章

3.3 使用哨兵模式

除了使用redis集群之外,我们还可以使用redis的哨兵模式。哨兵模式是由一个或多个sentinel实例组成的集合。当某个redis主节点不可用时,哨兵会选举出新的主节点,同时还会通知客户端新的主节点的已变更的地址和端口号。如下图所示:

在哨兵模式下,客户端只需要连接哨兵,然后哨兵会返回最新的主节点的地址信息,客户端再连接最新的主节点进行操作就行了。

3.4 封装连接方式

在实际的开发中,如果我们需要频繁地通过手动方式连接节点进行操作,这无疑会增加我们的开发难度,并且代码重复程度高。建议大家将连接redis集群的代码进行封装,精简操作,增强代码的可重用性。

示例代码:

class RedisCluster {

private $nodes;

public function __construct($nodes) {

$this->nodes = $nodes;

}

public function getConnection($key) {

$slot = $this->keyToSlot($key);

$node = $this->getNode($slot);

$conn = new Redis;

$conn->pconnect($node['host'], $node['port']);

return $conn;

}

private function keyToSlot($key) {

$CRC16_TABLE = array(

// CRC16数组

);

$hash = crc16($key);

return $hash % 16384;

}

private function getNode($slot) {

foreach ($this->nodes as $node) {

if ($node['slots'][0] <= $slot && $node['slots'][1] >= $slot) {

return $node;

}

}

}

}

$nodes = array(

array('host' => '127.0.0.1', 'port' => 7000, 'slots' => array(0, 1000)),

array('host' => '127.0.0.1', 'port' => 7001, 'slots' => array(1001, 2000)),

// ...

);

$rc = new RedisCluster($nodes);

$conn = $rc->getConnection('mykey');

4. 总结

以上是关于redis连接集群时遇到的错误,以及解决方法的总结。遇到这种问题,一定不要慌张,总结查看相信一定会给你带来帮助,增长你的技能。

数据库标签