2021-10-08----redis的java客户端--jedis

掌握jedis客户端的使用

介绍

Redis作为一个流行的缓存技术,支持非常多的客户端语言,其中java就具备多种不同的客户端api操作redis服务端执行命令,其中jedis,lettuce和redission是比较广发使用的三种,目前springboot2.2.5封装了前2种

测试学习api

保证运行的redis可以被外界访问

启动redis的服务端,外界在默认的配置中不允许访问redis-server的,可以使用redis.conf加载启动9000端口的服务端

选择测试工程添加客户端jedis依赖

<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

理解数据分片的概念(首次接触到数据分布式)

redis集群

Redis集群至少需要3个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以2个节点无法构成集群。

redis的分布式数据分片计算–hash取余

redis的分布式
为什么要用分布式
jedis对象可以实现的功能:用户登录状态的存储和读取
2021-10-08----redis的java客户端--jedis_第1张图片
虽然系统功能能够通过jedis操作9000这个端口的客户端实现读写,但是单个节点redis使用存在物理瓶颈。

  • 内存容器有限
  • 读写效率
    所以需要引入分布式集群
  • 分布式:一个任务,拆分给多个人同时完成,redis中需要拆分的不是业务而是数据
    2021-10-08----redis的java客户端--jedis_第2张图片
  • 数据的分配–数据分片计算
    单个节点时,无需考虑数据的分配问题,是因为所有数据都必须在这个节点实现读写,但是一旦引入分布式集群,必须考虑数据整体怎么样分配不同的节点,而且保证—单调性,整体一批数据被切分成了若干份,称之为数据分片
    == 单调性:哪存的在哪取==
    2021-10-08----redis的java客户端--jedis_第3张图片
  • 启动3个节点的分布式集群
  • start-redis.sh的命令,会启动6379 6380 6381的三个端口redis进程,不能使用redis-server启动默认6379在执行start-redis.sh
    2021-10-08----redis的java客户端--jedis_第4张图片

理解一致性hash和hash取余算法

  • hash取余算法
    一旦涉及到单调性,最先考虑到的计算逻辑就是hash散列,hash取余是一种分布式结构中最常见的经典计算方法
    hash取余对数据key-value的key值做hash取余计算,得到结果只要key值不变(字符串相等)取余结果在[0,1,2,3,4,5,n-1]n=分片个数(节点个数),计算公式
    (key.hashcode()&Integer.MAX.VALUE)%N其中N为分片(节点)个数
    key.hashCode():对key做hash散列计算,只要key值不变,得到一个不变可正可负的整数,只要散列计算能够做到key不变,整数结果不变,不一定非得是得hashCode最终任意一个key值都会对应[-21亿,21亿]区间的一个整数
    key.hashCode()&Integer.MAX_VALUE:31位二进制保真运算,目的是将前面的整数保真后31位二进制,保证他是一个正整数&位的与运算,目的是取得一个正整数
    2021-10-08----redis的java客户端--jedis_第5张图片

hash取余就可以应用在redis分布式数据分片计算逻辑后,当有key-alue出现时,先对key做hash取余,n是节点个数(现在是3)所有节点jedis排序(list)1 2 3…n-1使用到取余结果对应到一个固定jedis对象,最终连接固定的redis节点

2021-10-08----redis的java客户端--jedis_第6张图片

  • hash取余算法不能适用于分片个数N变化的场景
    • 只要是hash必定数据倾斜,可以通过key值来设计数据倾斜,key越规律,数倾斜的越小
    • 由于redis集群有动态线性扩展的特点,3哥变5哥,5哥变12哥,很频繁发生,hash取余无法保证扩容,缩容时的单调性(单调性造成严重破坏)
      2021-10-08----redis的java客户端--jedis_第7张图片

一致性hash

jedis封装了一种对应分布式的分片计算逻辑----一致性hash,在redis集群做分布式扩容和缩容时,虽然也会影响数据的单调性,但是节点越多,影响的数据量越小

/**
    * 上述实现了自定义分片对象,但是由于hash取余不适用于redis
    * 所以jedis单独封装了一个算法--一致性hash
    * ShardedJedis 构造过程提供所有分片信息
    */
    @Test
    public void consistentHash(){
    String key=UUID.randomUUID().toString();
    String value="haha";
    //帮助分片对象收集所有节点信息
    List<JedisShardInfo> nodes=new ArrayList<>();
    nodes.add(new JedisShardInfo("192.168.73.130",8888));
    nodes.add(new JedisShardInfo("192.168.73.130",8889));
    nodes.add(new JedisShardInfo("192.168.73.130",8890));
    //创建出jedis的分片对象
    ShardedJedis sJedis=new ShardedJedis(nodes);
    //见证分布式 分片计算和单调性保证
    sJedis.set(key,value);
    //使用集群读取key值
    System.out.println(sJedis.get(key));
    }
一致性原理

基础:麻省理工大学97年创建一个数学模型,后背应用到分布式领域,实现了一个hash映射计算,可以将任意的内存数据对象,通过hash散列映射到【0,2……32-1】
由于结果是32的二进制,0减去1变成2……32-1最大数加一变成0,这个取值区间称之为hash环

2021-10-08----redis的java客户端--jedis_第8张图片
数学映射计算:

  • 节点手机信息时,每个节点信息作为一个对象映射到这个换上一个整数

  • key值作为字符串数据也会映射到这个环上一个整数
    2021-10-08----redis的java客户端--jedis_第9张图片

  • key与节点对应原则
    key的整数顺时针寻找最近节点整数做对应关系
    2021-10-08----redis的java客户端--jedis_第10张图片
    在这里插入图片描述

  • 扩容缩容时,单调性保证
    如果集群节点越多,hash环弧线被分配的越短,对应的数据量越小,根据上述的计算逻辑,新节点加入时,影响的数据单调性范围越小,所以在一个频繁发生扩容缩容的集群中,分布式计算为了保证单调性一致hash比hash取余更适合
    2021-10-08----redis的java客户端--jedis_第11张图片

  • 数据平衡性
    2021-10-08----redis的java客户端--jedis_第12张图片
    当节点相互映射的整数比较近,必定会有某些节点对应key值远远大于其他节点,造成严重的数据倾斜,所以需要解决这个问题,一致性hash计算逻辑引入虚拟节点。
    2021-10-08----redis的java客户端--jedis_第13张图片
    通过对虚拟节点的个数控制,还可以做到按照比例的分片数据,在jedis中实现的虚拟节点个数160*weight,weight默认是1
    2021-10-08----redis的java客户端--jedis_第14张图片

连接池

在目前阶段,不管是单个jedis对象,还是分片对象ShardedJedis都是一个对象(关联的都是一个单个的链接),应用效率不高,在实际应用中,总要从代码中new出来然后用完了要关闭(close),应该引用连接池。

JedisPool

一次性创建多个jedis对象,都是链接一个节点的,用的时候从链接池中获取临街,用完归还链接,提升对象的使用效率,不必频繁的创建销毁对象。

/*
    JedisPool
     */
    @Test
    public void test05(){
        JedisPool pool=new JedisPool("10.9.118.11",6380);
        //获取连接资源
        Jedis jedis1 = pool.getResource();
        jedis1.set("name","王翠花");
        pool.returnResource(jedis1);
        Jedis jedis2 = pool.getResource();
        System.out.println(jedis2.get("name"));
        pool.returnResource(jedis2);
    }

2021-10-08----redis的java客户端--jedis_第15张图片

分片连接池

ShardedJedisPool
如果说jedisPool管理了一批Jedis对象,ShardedJedisPool管理了一批ShardedJedis
2021-10-08----redis的java客户端--jedis_第16张图片

/*
    分片连接池
     */
    @Test
    public void test06(){
        //提供分片节点信息
        List<JedisShardInfo> infos=new ArrayList<>();
        infos.add(new JedisShardInfo("10.9.118.11",6379));
        infos.add(new JedisShardInfo("10.9.118.11",6380));
        infos.add(new JedisShardInfo("10.9.118.11",6381));
        //连接池配置属性
        JedisPoolConfig config=new JedisPoolConfig();
        //定义连接池的连接上限,最大空闲,最小空闲,不同的使用环境这些数值配置不一样的
        config.setMaxIdle(8);
        config.setMinIdle(2);
        config.setMaxTotal(200);
        //创建连接池
        ShardedJedisPool pool=new ShardedJedisPool(config,infos);
        ShardedJedis resource = pool.getResource();
        //可以实现api操作,分布式计算
        pool.returnResource(resource);
    }

你可能感兴趣的:(redis,redis,java,数据库)