moved重定向

当redis-client向redis-cluster集群中的任意节点发送命令时,该节点会根据key的值来计算出正确的node节点。如果正确节点恰巧是该节点时,返回处理结果,如果不是则返回moved异常。




Redis cluster选举方式 redis-cluster_Powered by 金山文档


  • 演示
  • 正常使用redis-cli客户端
  • 发现虚拟槽不再该节点处理范围内时,仅返回moved异常,不进行跳转。
xiaosa@XIAOSAdeMacBook-Pro bin % ./redis-cli -h 127.0.0.1 -p 7100 
127.0.0.1:7100> cluster keyslot hello
(integer) 866
127.0.0.1:7100> get hello
"world"
127.0.0.1:7100> cluster keyslot php
(integer) 9244
127.0.0.1:7100> set php good
(error) MOVED 9244 127.0.0.1:7101
  • redis-cli客户端加-c参数
  • redis-cli客户端增加-c参数后,在接收到moved异常时会帮助跳转到对应的节点,并执行命令。
xiaosa@XIAOSAdeMacBook-Pro bin % ./redis-cli -c  -h 127.0.0.1 -p 7100
127.0.0.1:7100> set php good
-> Redirected to slot [9244] located at 127.0.0.1:7101
OK
127.0.0.1:7101>

asked重定向

在虚拟槽数据发生迁移时,会触发该异常。


Redis cluster选举方式 redis-cluster_redis_02


moved vd asked

  • 两者都需要客户端去处理重定向问题。
  • moved:槽已确定。
  • asked:迁移过程中,数据不确定在源节点,还是目标节点。

智能客户端Jedis Cluster

如果客户端随机的去访问集群里的任意节点,来通过moved或者asked异常来确定正确的节点,将会带来巨大的额外开销。所以因此引入了智能客户端的概念。

  • Jedis Cluster
  • 从redis cluster集群中选择一个可运行节点,使用cluster slots命令来获取节点与虚拟槽的映射。
  • Jedis Cluster客户端本地存储节点与虚拟槽的映射关系,并根据节点创建对应的链接池。
  • 执行命令时先在Jedis Cluster客户端做一次计算来确定需要访问的节点,来以此来减少与redis cluster server的重定向请求。
  • 同时Jedis Cluster客户端仍需要兼容moved重定向、asked重定向。原因是Jedis Cluster客户端本地存储节点与虚拟槽的映射关系可能不是最新的数据。
  • 执行命令过程如下图。


Redis cluster选举方式 redis-cluster_Powered by 金山文档_03


  • 基本使用
package com.test;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

import java.util.HashSet;
import java.util.Set;

public class JedisClusterTest {
    public static void main(String[] args) {
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        Set<HostAndPort> nodes = new HashSet<>(){{
            add(new HostAndPort("127.0.0.1",7100));
            add(new HostAndPort("127.0.0.1",7101));
            add(new HostAndPort("127.0.0.1",7102));
            add(new HostAndPort("127.0.0.1",7103));
            add(new HostAndPort("127.0.0.1",7104));
            add(new HostAndPort("127.0.0.1",7105));
        }};
        // 单例;无需手动归还链接
        JedisCluster jedisCluster = new JedisCluster(nodes,config);
        jedisCluster.set("hello","world");
        String value = jedisCluster.get("hello");
        System.out.println(value);
    }
}
// 控制台输出
world

Process finished with exit code 0
  • 每个节点都执行命令的操作,例如:在每个节点上执行keys *操作。
package com.test;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.*;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class JedisClusterTest {
    public static void main(String[] args) {
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        Set<HostAndPort> nodes = new HashSet<>(){{
            add(new HostAndPort("127.0.0.1",7100));
            add(new HostAndPort("127.0.0.1",7101));
            add(new HostAndPort("127.0.0.1",7102));
            add(new HostAndPort("127.0.0.1",7103));
            add(new HostAndPort("127.0.0.1",7104));
            add(new HostAndPort("127.0.0.1",7105));
        }};
        // 单例;无需手动归还链接
        JedisCluster jedisCluster = new JedisCluster(nodes,config);
        Map<String, ConnectionPool> poolMap = jedisCluster.getClusterNodes();
        for(Map.Entry<String, ConnectionPool> entry : poolMap.entrySet()){
            ConnectionPool pool = entry.getValue();
            // TODO(判断该节点是否是主节点)
            Connection connection = pool.getResource();
            Object re = connection.executeCommand(new CommandArguments(Protocol.Command.KEYS).add("*"));
            System.out.println(re);
        }
    }
}
// 控制台输出
[]
[[B@78b729e6]
[[B@27c86f2d]
[[B@402e37bc]
[]
[[B@22635ba0]
  • 批量操作的几种实现方案
  • 串行mget
  • 循环的调用。


Redis cluster选举方式 redis-cluster_Redis cluster选举方式_04


  • 串行IO
  • 合并同一个节点的key,串行的请求每一个节点,将n次请求转换为node个数的请求。


Redis cluster选举方式 redis-cluster_缓存_05


  • 并行IO
  • 合并同一个节点的key,与串行IO的最大区别就是分多个线程去请求不同的node节点,响应时间为最慢的节点请求。


Redis cluster选举方式 redis-cluster_redis_06


  • hash tag
  • 通过在key上拼接{tag}强制的将所有的key分配到一个虚拟槽上。性能最高,可能会造成部分节点的数据倾斜。


Redis cluster选举方式 redis-cluster_Powered by 金山文档_07


  • 优缺点对比


Redis cluster选举方式 redis-cluster_redis_08