• ShardedJedis实现学习


    ShardedJedis实现学习-我们到底能走多远系列(33)

    我们到底能走多远系列(31)

    扯淡:

      工作是容易的赚钱是困难的
      恋爱是容易的成家是困难的
      相爱是容易的相处是困难的
      决定是容易的可是等待是困难的

    主题:

    1,Sharded的实现

     
     ShardedJedis是基于一致性哈希算法实现的分布式Redis集群客户端。
     
     关于一致性哈希算法 可以参考 转载文章
     

      Memcached 和 redis 都使用了该算法来实现自己的多服务器均匀分派存储值的。

      shardedJedisPool的配置如下:(具体可以参考《spring和redis的整合》

    复制代码
    <bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool"  scope="singleton">
            <constructor-arg index="0" ref="jedisPoolConfig" />
            <constructor-arg index="1">
                <list>
                    <bean class="redis.clients.jedis.JedisShardInfo">
                        <constructor-arg name="host" value="${redis.host}" />
                        <constructor-arg name="port" value="${redis.port}" />
                        <constructor-arg name="timeout" value="${redis.timeout}" />
                        <constructor-arg name="weight" value="1" />
                    </bean>
                </list>
            </constructor-arg>
     </bean>
    复制代码

     注入了两个对象:jedisPoolConfig 和 JedisShardInfo

    然后产生ShardedJedis:

    复制代码
        public ShardedJedis getRedisClient() {
            try {
                ShardedJedis shardJedis = shardedJedisPool.getResource();
                return shardJedis;
            } catch (Exception e) {
                log.error("getRedisClent error", e);
            }
            return null;
        }
    复制代码

    ShardedJedis 继承 BinaryShardedJedis 继承Sharded<Jedis, JedisShardInfo>

    Sharded的实现就是前面一致性哈希算法的实现啦~

    复制代码
    // 使用TreeMap来完成构造出一个很多节点的环形
    private TreeMap<Long, S> nodes;
    
    // 构造方法
    public Sharded(List<S> shards, Hashing algo, Pattern tagPattern) {
            this.algo = algo;
            this.tagPattern = tagPattern;
            // 初始化方法,建立一个个节点
            initialize(shards);
    }
    复制代码

    initialize方法:

    复制代码
        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
                    // 将设置的权重放大160倍,产生更多的节点,因为hash一下就散落到各道各处了,如此就是所谓的虚拟节点,以保证均匀分布
                    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());
            }
        }
    复制代码

    redis放key value的时候,需要判断应该放在那个服务器上,就是判断hash后更靠近哪个节点。

    复制代码
        public R getShard(byte[] key) {
            return resources.get(getShardInfo(key));
        }
    
        public R getShard(String key) {
            return resources.get(getShardInfo(key));
        }
        //最终调用方法
        public S getShardInfo(byte[] key) {
           // 首先判断是不是tree中最大的key,及最后一个,注意我们是环,所以最大的后面就要从头开始。
            SortedMap<Long, S> tail = nodes.tailMap(algo.hash(key));
            // 是最后一个key了,所以取第一个节点对应的服务器
            if (tail.size() == 0) {
                return nodes.get(nodes.firstKey());
            }
            // 不是最后一个就是比自己离自己最近的大的key对应的服务器
            return tail.get(tail.firstKey());
        }
    
        public S getShardInfo(String key) {
            return getShardInfo(SafeEncoder.encode(getKeyTag(key)));
        }
    复制代码

    到这里基本明白了如何抽象实现一个环状的排序的数据结构了。值得借鉴。

    2,实践中的一个例子

     问题:模拟一个抽奖的效果,随机产生一个范围内的数字,看是否在中奖的区域内来判断是否中奖。 中奖区域分多个层次的奖项。
    如图:
     
    |0 -------奖项1--------200|201-------奖项2--------1000|1001-------奖项3-------5000|5001-------没奖---------100000|
     
    使用了TreeMap来实现
    从项目里拉出来的代码:
    复制代码
    TreeMap<Integer, AwardConfigDO> extentTree = new TreeMap<Integer, AwardConfigDO>();
            // 获奖区间划分
            for (AwardConfigDO awardConfig : configList) {
                //Probability是区间节点,如100,500
                extentTree.put(awardConfig.getProbability(), awardConfig);
            }
            // 进入中奖区 random 是随机产生的数字,首先判断是否进入中奖区
            if (random < extentTree.lastKey()) {
                //然后判断 中奖奖项 是哪个
                AwardConfigDO awardConfig =  extentTree.higherEntry(random).getValue();
            }    
    复制代码

    所以TreeMap可以来抽象实现这种区间的结构。关于TreeMap可以看API哦。

    让我们继续前行

    ----------------------------------------------------------------------

    努力不一定成功,但不努力肯定不会成功。
    共勉。

     
     
  • 相关阅读:
    输入输出重定向
    进程管理
    普通变量_环境变量_环境变量配置文件
    高级文件操作命令_文件查找
    软件包管理_rpm命令管理_yum工具管理_文件归档压缩_源码包管理
    用户管理_组管理_设置主机名_UGO_文件高级权限_ACL权限
    字符串是否包含中文
    SQL 优化
    JS数组
    RedisUtil 工具类
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3276403.html
Copyright © 2020-2023  润新知