Quantcast
Channel: Dumbee
Viewing all articles
Browse latest Browse all 8

Redis Java客户端 Jedis设计及工作流程

$
0
0

1、Jedis 简介

Jedis是Redis官方推荐的首选Java客户端实现。目前支持redis各种数据结构的操作包括string,hash, list, set, sorted set;支持事务/管道/发布订阅等;支持客户端sharding和Redis 集群。 项目地址:https://github.com/xetorthio/jedis

2、Jedis class diagram

Jedis实例本身是线程不安全的,所以jedis项目使用了Apache commons-pool作为对象池来管理jedis实例。

jedis_class

Jedis class diagram

3、Jedis sequence diagram (set command)

jedis_sequence_diagram

Jedis sequence diagram

 

4、ShardedJedis class diagram

jedis_c_shard

ShardedJedis class diagram

5、ShardedJedis sequence diagram(set command)

jedis_s_shard

ShardedJedis sequence diagram

关于sharding

Sharded Jedis的一致性hash实现是将redis服务器节点按照一定规则进行hash算法切分并把(虚拟)节点信息保存在TreeMap中,通过算法实现如下图的闭环。

hash

Sharded Jedis 一致性hash算法实现核心代码如下:

private void initialize(List<S> shards) {
        nodes = new TreeMap<Long, S>();

        for (int i = 0; i != shards.size(); ++i) {
            final S shardInfo = shards.get(i);
            if (shardInfo.getName() == null)
            	for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
            		nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" + n), shardInfo);
            	}
            else
            	for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
            		nodes.put(this.algo.hash(shardInfo.getName() + "*" + shardInfo.getWeight() + n), shardInfo);
            	}
            resources.put(shardInfo, shardInfo.createResource());
        }
    }

以上是TreeMap初始化的过程,主要根据是否定义了节点name产生了两条分支进行hash计算,通过代码可以了解到,如果在没有定义节点name的情况下,如果有节点挂掉要启动备份节点时,新节点在List<S> shards中的位置(index)不能变,这样才能保证整个集群一致性hash的结果与原来相同,当然最好的方式还是为每个节点定义一个name,这样就与节点在配置中的顺序无关了。

public R getShard(String key) {
        return resources.get(getShardInfo(key));
    }

    public S getShardInfo(byte[] key) {
        SortedMap<Long, S> tail = nodes.tailMap(algo.hash(key));
        if (tail.size() == 0) {
            return nodes.get(nodes.firstKey());
        }
        return tail.get(tail.firstKey());
    }

    public S getShardInfo(String key) {
        return getShardInfo(SafeEncoder.encode(getKeyTag(key)));
    }

另外注意:在使用sharded jedis时,如果在JedisPoolConfig中配置testOnBorrow为true,那么在borrowObject时会调用validateObject方法来验证所有对象实例的有效性,此时redis cluster中只要有一个节点出问题,客户端将无法获取shardedJedis实例。如果配置testOnBorrow为false(默认值),在获取sharedJedis实例时将不会进行集群节点有效性的验证,只有散列到出问题节点的请求才会抛异常,其他节点的访问正常。下面是ShardedJedisPool.ShardedJedisFactory.validateObject方法的具体实现:

public boolean validateObject(final Object obj) {
        try {
                ShardedJedis jedis = (ShardedJedis) obj;
                for (Jedis shard : jedis.getAllShards()) {
                    if (!shard.ping().equals("PONG")) {
                        return false;
                    }
                }
                return true;
            } catch (Exception ex) {
                return false;
            }
      }

ps:以上源码分析都依据版本2.1.0,目前Jedis又开始频繁更新来适配redis cluster版本。


Viewing all articles
Browse latest Browse all 8

Trending Articles