redis下的shareJedis使用

redis分区:

分区就是将数据分散到多个redis实例中,每个redis实例只保存一部分数据

分区/分片的意义:

单机的机器存储容量会限制redis的服务能力,为了存储的横向扩展,可以将数据分散到多台机器上

ShardedJedis是通过一致性哈希来实现将不同的key分散到不同的redis server中

shareJedis使用:

@Test
    public void test3() {
        //设置连接池的相关配置
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(2);
        poolConfig.setMaxIdle(1);
        poolConfig.setMaxWaitMillis(2000);
        poolConfig.setTestOnBorrow(false);
        poolConfig.setTestOnReturn(false);
        //定义redis的多个节点机器
        List<JedisShardInfo> list = new ArrayList<JedisShardInfo>() {{
            add(new JedisShardInfo("127.0.0.1", 6379));
            add(new JedisShardInfo("127.0.0.1", 6380));
            add(new JedisShardInfo("127.0.0.1", 6381));
        }};
        //定义redis分片连接池
        ShardedJedisPool jedisPool = new ShardedJedisPool(poolConfig, list);
        
        //获取连接操作redis 进行查询等其他操作 
        //使用后一定关闭,还给连接池
        try (ShardedJedis jedis = jedisPool.getResource()) {
            //向redis中添加20个记录查看分片结果
            for (int i = 0; i < 10; i++) {
                //增加的记录格式为   key=NUM_i   value=i
                jedis.set("NUM_" + i, "" + i);
                jedis.get("NUM_" + i);
            }
        }
       
    }

测试数据分布情况

分布情况是根据shareJedis中对key进行一致性哈希来确定记录的存放区域

shareJedis讲解

1.继承体系

shareJedis存储数的核心代码:

    private final Map<ShardInfo<R>, R> resources = new LinkedHashMap<ShardInfo<R>, R>();


    public String set(final String key, final String value) {
        Jedis j = getShard(key);
        return j.set(key, value);
    }


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


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


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

主要的操作是:Jedis j = getShard(key);获取对应的jedis实例,方法(getShardInfo(byte[] key))nodes是个treeMap,algo是Hashing类型,key分片所使用的hash算法,主要步骤:

1.从treeMap中取出大于等于key之后的部分视图SortMap

2.从sortMap取出第一个键值对的值,对象S

3.从resource中取出R(Map<ShardInfo<R>, R> resources = new LinkedHashMap<ShardInfo<R>, R>();)

根据下面的代码发现 S是JesdisShareInfo,R就是redis实例

public class BinaryShardedJedis extends Sharded<Jedis, JedisShardInfo> implements
    BinaryJedisCommands {}

public class Sharded<R, S extends ShardInfo<R>>{}

 

JedisShardInfo具体信息如下:里面包含了jedis服务器的一些信息,最重要的是它的父类中有一个weight字段,作为本jedis服务器的权值,实际是根据存储的jedis信息去获取jedis的实例

整体的存储流程:

1.将key值进行hash算法,然后根据这个hash出来的key从treeMap中获取jedisShareInfo

2.根据jedisShareInfo中的信息获取jedis实例,最终返回,执行操作

 

    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() + "*" + n), shardInfo);
            }
            resources.put(shardInfo, shardInfo.createResource());
        }
    }

Shared中的初始化方法, 将每台服务器节点采用hash算法划分为160个虚拟节点(可以配置划分权重),保存在TreeMap中,

然后把每台服务器节点的信息和物理连接以键值对保存LinkedHashMap中。

shardInfo.createResource()根据shareInfo中存储的redis创建redis实例信息

其中初始化方法调用实在 ShardedJedis jedis = jedisPool.getResource() 这里进行初始化的,实际是通过连接池来实现的,具体感兴趣的可以自己调试一下

ShardedJedis分布式具体的的实现思路:

  • redis服务器节点划分:将每台服务器节点采用hash算法划分为160个虚拟节点(可以配置划分权重)

  • 将划分虚拟节点采用TreeMap存储

  • 对每个redis服务器的物理连接采用LinkedHashMap存储

  • 对Key or KeyTag 采用同样的hash算法,然后从TreeMap获取大于等于键hash值得节点,取最邻近节点存储;当key的hash值大于虚拟节点hash值得最大值时,存入第一个虚拟节点

  • sharded采用的hash算法:MD5 和 MurmurHash两种;默认采用64位的MurmurHash算法;

分区的不足:

  1. 分区是多台redis共同作用的,如果其中一台出现了宕机现象,则整个分片都将不能使用,虽然是在一定程度上缓减了内存的压力,但是没有实现高可用。
  2. 涉及多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。
  3. 涉及多个key的redis事务不能使用。
  4. 当使用分区时,数据处理较为复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件。

  高可用的解决方案:可以采用哨兵机制实现主从复制从而实现高可用。

博主初次涉猎,如果有什么问题以及说的不明白的,请留言告知 一起交流提升

欢迎关注作者公众号交流以及投稿

回复  8888可以领取面试资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术王老五

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值