redis基础和分片计算算法原理

1.为什么使用redis?

之前我们使用springBoot在做微服务的时候,我们发现了一个session共享问题,因为session是存在于服务端的,而服务器可能是集群的,那就意味着服务每次的调用,不一定在一个服务器上,那么session就无法保证存在于一个服务器上,从而导致session的丢失,为了处理这个问题,就可以使用redist来解决。

2.redis相关知识:

特性: redis存储的是nosql型数据,简单来说就是使用key-value的方式来储存数据。

客户端和服务端: redis的服务端启动后,就等待客户端连接,客户端有很多种类,比如java客户端

存储位置: redis存储数据的位置是在缓存上,这就意味着它的速度非常快,但是也有缺点,就是容量小。

数据格式: redis中的数据是用key-value的方式来储存的,value可以有如下格式:

string: 这个很简单,就不说了

hash: 双层map的结构,第一层存的是key-value,然后第一层的value中再存一个key-value格式的数据

双向list:数据结构中学过,key-value形式存储数据,其中value中存储l双向list,一个key对应一个双向list

set:key-value形式储存数据,一个key对应一个set,set中元素不重复,无序。

zst:和set相似,但是他是有序的,在元素的数据上绑定了一个

评分的数字(实际应用场景中,评分可以不同业务意义,例如点击次数,例如播放量,例如投票数量等)

扫描二维码关注公众号,回复: 11325664 查看本文章

3.使用java客户端连接redis

要使用Java客户端连接redis就需要引入依赖:

      <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
      </dependency>

代码:

   @Test
    public void test(){
    //第一个参数的redis服务器的ip地址,第二个是redis服务的端口号
        Jedis jedis=new Jedis("10.42.130.140",6380);
        //调用set方法,再redis中添加一对key-value
        jedis.set("lxh","23");
        //hset方法,在hash中添加一个key为school,value为name-“河南工业大学”
        jedis.hset("school","name","河南工业大学");
        jedis.lpush("list","100","200");
    }

在这里插入图片描述
问题的提出:java客户端可以连接上redis服务端,但是如果有多个redis服务端,我们只有保证用户每次访问的redis服务端都是同一个,才可以实现session那样的共享数据,那么如何保证用户每次访问的都是同一个redis?

4.分片计算——hash取余

当你的redis服务数量是确定的时候,可以使用此方法:
hash取余根据你的key值(redis中存储数据是以key-value形式),计算出一个值,把这个值映射到一个-21亿到+21亿的区间,接着把这个数取正,然后进行保真运算,最后%redis服务节点个数,得到的就是要使用第几个节点,代码如下:

 @Test
    public void test2(){
        Jedis jedis1=new Jedis("10.42.130.140",6380);
        Jedis jedis2=new Jedis("10.42.130.140",6381);

        List<Jedis> list=new ArrayList<Jedis>();

        list.add(jedis1);
        list.add(jedis2);

        for (int i=0;i<100;i++){
            String key= UUID.randomUUID().toString();
            String value=i+"";
            //hash取余算法,得到一个下标,通过该下标去list中寻找需要的redis
            int index=(key.hashCode()&Integer.MAX_VALUE)%list.size();
            Jedis jedis=list.get(index);
            jedis.set(key,value);
        }
    }

在这里插入图片描述
在这里插入图片描述
可以看到两个redis服务端中储存的数据分别是60条和40条。

5.分片计算—— 一致性hash

上面所说的hash取余算法,只能解决定长的redis服务问题,但是redis服务数量总是在变化的,一但数量发生了变化最后取余的误差就会非常大,导致java客户端通过key去寻找对应的redis服务时发生错误,所以为了解决这个问题,就出现了一致性hash。

算法思路:

首先需要一个hash环,0~43亿。

然后对节点做散列计算,让各个节点分散到这个环上。

再对key值做散列计算,把key也分散到这个环上。

接着就开始寻找,这些key会寻找离他们最近的节点,然后和这些节点对应上。

数据平衡性:
就比如刚刚上面那个案例,我启动了两个redis服务,把他们两个分散到这个hash环上,如果按照散列算法,必然会有一个节点承载的数据多于另外一个,那么如何解决这个问题?
jedis使用了虚拟节点技术,默认每个节点自带160个虚拟节点,这些虚拟节点和真实节点功能一样,为的就是去揽收那些离他们近的key散列。

代码如下:

 @Test
    public void test3(){
        List<JedisShardInfo> list=new ArrayList<JedisShardInfo>();
        
        list.add(new JedisShardInfo("10.42.130.140",6380));
        list.add(new JedisShardInfo("10.42.130.140",6381));
//声明一个ShardedJedis的对象,把redis节点的链表传递进去,
//然后他就会把节点散列给安排好,key再进去的时候,就去找最近的节点即可
        ShardedJedis jedis=new ShardedJedis(list);

        for(int i=0;i<10;i++){
            String key=UUID.randomUUID().toString();
            String value=i+"";
            jedis.set(key,value);
        }
    }

猜你喜欢

转载自blog.csdn.net/weixin_42596778/article/details/106433142
今日推荐