19-获取与插槽对应的节点
8.3.4 获取与插槽对应的节点
8.3.3节介绍了插槽的分配方式,对于指定的键,可以根据前文所述的算法来计算其属于哪个插槽,但是如何获取某一个键由哪个节点负责呢?
实际上,当客户端向集群中的任意一个节点发送命令后,该节点会判断相应的键是否在当前节点中,如果键在该节点中,则会像单机实例一样正常处理该命令;如果键不在该节点中,就会返回一个 MOVE 重定向请求,告诉客户端这个键目前由哪个节点负责,然后客户端再将同样的请求向目标节点重新发送一次以获得结果。
一些语言的Redis库支持代理 MOVE 请求,所以对于开发者而言命令重定向的过程是透明的,使用集群与使用单机实例并没有什么不同。然而也有些语言的Redis库并不支持集群,这时就需要在客户端编码处理了。
还是以上面的集群配置为例,键 foo 实际应该由6382节点负责,如果尝试在6380节点执行与键 foo 相关的命令,就会有如下输出:
redis 6380> SET foo bar
(error) MOVED 12182 127.0.0.1:6382
返回的是一个 MOVE 重定向请求, 12182 表示 foo 所属的插槽号, 127.0.0.1:6382 则是负责该插槽的节点地址和端口,客户端收到重定向请求后,应该将命令重新向6382节点发送一次:
redis 6382> SET foo bar
OK
Redis命令行客户端提供了集群模式来支持自动重定向,使用 -c 参数来启用:
$ redis-cli -c -p 6380
reds 6380> SET foo bar
-> Redirected to slot [12182] located at 127.0.0.1:6382
OK
可见加入了 -c 参数后,如果当前节点并不负责要处理的键,Redis命令行客户端会进行自动命令重定向。而这一过程正是每个支持集群的客户端应该实现的。
然而相比单机实例,集群的命令重定向也增加了命令的请求次数,原先只需要执行一次的命令现在有可能需要依次发向两个节点,算上往返时延,可以说请求重定向对性能的还是有些影响的。
为了解决这一问题,当发现新的重定向请求时,客户端应该在重新向正确节点发送命令的同时,缓存插槽的路由信息,即记录下当前插槽是由哪个节点负责的。这样每次发起命令时,客户端首先计算相关键是属于哪个插槽的,然后根据缓存的路由判断插槽由哪个节点负责。考虑到插槽总数相对较少(16384个),缓存所有插槽的路由信息后,每次命令将均只发向正确的节点,从而达到和单机实例同样的性能。