• ShardedJedis的分片原理


    ShardedJedisPool xml配置:

    <bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool">
        <constructor-arg index="0">
            <bean class="redis.clients.jedis.JedisPoolConfig"></bean>
        </constructor-arg>
        <constructor-arg index="1">
            <list>
                <bean class="redis.clients.jedis.JedisShardInfo">
                    <constructor-arg name="host" value="192.168.233.8"/>
                    <constructor-arg name="port" value="6379"/>
                </bean>
                <bean class="redis.clients.jedis.JedisShardInfo">
                    <constructor-arg name="host" value="192.168.233.8"/>
                    <constructor-arg name="port" value="6381"/>
                </bean>
                <bean class="redis.clients.jedis.JedisShardInfo">
                    <constructor-arg name="host" value="192.168.233.8"/>
                    <constructor-arg name="port" value="6382"/>
                </bean>
            </list>
        </constructor-arg>
    </bean>

    xml配置对应的构造方法:

    public class ShardedJedisPool extends Pool<ShardedJedis> {
      public ShardedJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards) {
        this(poolConfig, shards, Hashing.MURMUR_HASH);
      }
    }

    ShardedJedisPool使用示例:

    ShardedJedisPool pool = ctx.getBean(ShardedJedisPool.class);
    ShardedJedis jedis = pool.getResource();
    String zhang = jedis.get("zhang");
    jedis.close(); 

    ShardedJedisPool.getResource 的调用栈:

    代码分析:

    //类 redis.clients.util.Sharded<R, S extends ShardInfo<R>>
    private final Map<ShardInfo<R>, R> resources = new LinkedHashMap<ShardInfo<R>, R>();
    
    private void initialize(List<S> shards) {
        nodes = new TreeMap<Long, S>();
      //shards是xml中配置的redis.clients.jedis.JedisShardInfo的list
        for (int i = 0; i != shards.size(); ++i) {
            final S shardInfo = shards.get(i);
         //没有为JedisShardInfo设置name,所以执行if分支,weight默认为1
         //取 SHARD-0-NODE-0 ~ SHARD-0-NODE-159 哈希值
         //取 SHARD-1-NODE-0 ~ SHARD-1-NODE-159 哈希值
         //取 SHARD-2-NODE-0 ~ SHARD-2-NODE-159 哈希值
         //把(哈希值->JedisShardInfo)键值对放入nodes中
            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);
            }
            //添加到map中,键为JedisShardInfo,值为Jedis
            resources.put(shardInfo, shardInfo.createResource());
        }
    }

    JedisShardInfo.createResource:

    //省略其他代码
    public class JedisShardInfo extends ShardInfo<Jedis> {
      @Override
      public Jedis createResource() {
        return new Jedis(this);
      }
    }

    存取一个键时,根据键获取一个JedisShardInfo,以get为例:

    public S getShardInfo(byte[] key) {
       //nodes是TreeMap,由红黑树实现,是按键值排好序的map,默认为升序
       //假定 algo.hash(key) 的值为10086,该行代码是取出键大于10086的所有键值对  
        SortedMap<Long, S> tail = nodes.tailMap(algo.hash(key));
        //如果不存在,则取第一个键值对的JedisShardInfo    
        if (tail.isEmpty()) {
            return nodes.get(nodes.firstKey());
        }
        //如果存在这样的键值对,则返回第一个键值对中的JedisShardInfo
        return tail.get(tail.firstKey()); 
    }

    Sharded类中有2个map,TreeMap<Long, S> nodes和Map<ShardInfo<R>, R> resources,

    运行时具体是:TreeMap<Long, JedisShardInfo>和Map<JedisShardInfo, Jedis>。

    分析以上代码可知,首先计算出 "SHARD-i-NODE-n" 的哈希值,预先生成一颗红黑树,即填充nodes。

    当存取键值对时,计算键的哈希值,然后从红黑树上摘下比该值大的第一个节点上的JedisShardInfo,随后从resources取出Jedis。

    假定有红黑树如下:

  • 相关阅读:
    JZ36 两个链表的第一个公共结点
    程序员的表达能力
    Git学习(2)-使用Git 代码将本地文件提交到 GitHub
    初识模块
    三元表达式、递归、匿名函数
    CSRF
    XSS前置课程--同源策略
    XSS
    SQL注入基础入门
    Linux下ettercap的安装,make安装软件步骤
  • 原文地址:https://www.cnblogs.com/allenwas3/p/7852274.html
Copyright © 2020-2023  润新知