Redis(REmote DIctionary Server,远程字典服务)

发布于:2023-01-22 ⋅ 阅读:(7) ⋅ 点赞:(0) ⋅ 评论:(0)

Redis(REmote DIctionary Server,远程字典服务)

        Redis(REmote DIctionary Server,远程数据服务)是用C语言开发的一个开源的高性能 键值对key-value)数据库,Redis把所有数据是保存在内存里面的。官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s ,且Redis通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:key一直String类型,redis支持的数据类型 指的就是value可以存储的数据类型

Redis 默认是16个数据库, 编号是从0~15. 【默认是0号库】

  • keys *: 查询所有的key

  • exists key:判断是否有指定的key 若有返回1,否则返回0

  • expire key 秒数:设置这个key在缓存中的存活时间

  • ttl key:展示指定key的剩余时间
    若返回值为 正数:指定key的剩余时间
    若返回值为 -1:永不过期

    若返回值为 -2:不存在或者已过期

  • del key:删除指定key

  • rename key 新key:重命名

  • type key:判断一个key的类型

  • ping :测试连接是否连接

  • select index:切换库

  • move key index: 把key移动到几号库(index是库的编号)

  • flushdb:清空当前数据库

  • flushall:清空当前实例下所有的数据库

为啥 Redis 单线程模型也能效率这么高?

• 纯内存操作

• 核心是基于非阻塞的 IO 多路复用机制

• 单线程反而避免了多线程的频繁上下文切换问题

Redis数据类型

字符串类型

string

Redis中一个字符串类型(String)的值能存储最大容量是512M

列表类型

List

类似LinkedList

散列类型/哈希类型

hash

类似HashMap,适合存储对象(属性,属性值)

集合类型(无序)

set

类似HashSet,无序且唯一

有序集合类型

zset/sorted_set

有序且唯一

StringRedisTemplate的API

Jedis就是使用Java操作Redis的客户端(工具包:Jedis=JDBC+驱动)

1.Jedis的入门

需求: 使用java代码操作Redis 进行增(改)删查  

步骤:

        1. 创建项目,导入jedis 的jar包
        2. 创建jedis对象  new Jedis(String host,int port);
        3. 调用方法
        4. 关闭对象 释放资源

public class Demo01 {
    public static void main(String[] args) {

        //1.创建jedis对象
        Jedis jedis = new Jedis("localhost",6379);
        //2.调用方法
        //2.1:string类型操作
        //获取value
        String akey = jedis.get("akey");
        System.out.println("akey = " + akey);
        //判断key是否存在
        Boolean flag = jedis.exists("akey");
        System.out.println("akey是否存在:"+flag);
        //jedis.del("akey");  删除key
        //存储key-value
        jedis.set("dkey","ddd");

        //2.2:hash类型
        jedis.hset("user1","name","zs");
        String name = jedis.hget("user1", "name");
        System.out.println("name = " + name);

        //2.3:list类型
        jedis.rpush("list1","a","b","c");
        System.out.println(jedis.lindex("list1", 2));

        //2.4:set类型
        jedis.sadd("set1","a","b","c");
        Set<String> set1 = jedis.smembers("set1");
        for (String s : set1) {
            System.out.println(s);
        }

        //3.关闭对象
        jedis.close();
    }
}

2.Jedis连接池的使用-Jedis进阶

需求: 从Jedis的连接池里面获得jedis

步骤:

  1. 创建JedisPoolConfig对象

  2. 创建JedisPool对象

  3. 获取jedis对象

  4. 调用方法

  5. 归还jedis对象到Jedis连接池

public class Demo02 {
    public static void main(String[] args) {
        //1. 创建JedisPoolConfig对象
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(5);
        config.setMaxWaitMillis(5000);
        //2. 创建JedisPool对象
        JedisPool jedisPool = new JedisPool(config, "localhost", 6379);
        //3. 获取jedis对象
        Jedis jedis = jedisPool.getResource();
        //4. 调用方法  需求:如果akey存在 获取akey的值  ; 如果akey不存在 创建一个akey=aaa存入redis中
        if(jedis.exists("akey")){
            System.out.println(jedis.get("akey"));
        }else{
            jedis.set("akey","aaa");
        }
        //5. 归还jedis对象到Jedis连接池
        jedis.close();
    }
}

3.JedisUtils工具类的抽取-Jedis进阶

目的: 1.保证池子只有一个 2.获得jedis对象 3.归还

步骤:

  1. 创建JedisUtils工具类

  2. 获取jedis对象

  3. 归还jedis对象

  4. 保证池子只有一个 使用静态代码块创建连接池对象

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Jedis工具类
 *  1.提供获取jedis对象的方法  getJedis();
 *  2.提供归还jedis对象的方法  close(Jedis jedis);
 *  优化:让jedisPool对象只有一个  采用单例模式  声明一个静态变量JedisPool对象  然后使用静态代码块初始化JedisPool对象
 */
public class JedisUtils {

    private static JedisPool jedisPool;

    static{
        //1. 创建JedisPoolConfig对象
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(5);
        config.setMaxWaitMillis(3000);
        //2. 创建JedisPool对象
        jedisPool = new JedisPool(config,"localhost",6379);
    }

    /**
     * 获取jedis对象
     * @return
     */
    public static Jedis getJedis(){
        //3. 获取jedis对象
        return jedisPool.getResource();
    }

    /**
     * 归还jedis对象
     * @param jedis
     */
    public static void close(Jedis jedis){
        if(jedis!=null){
            jedis.close();
        }
    }
}

Redis 的持久化

        Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘(文件)中,这一过程就是持久化

Redis支持两种方式的持久化:RDB持久化 和 AOF持久化

RDB持久化机制:默认开启,不需要配置

RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。快照文件称为RDB文件。

RDB 持久化:该机制可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。

关键字 时间(秒) key修改数量 解释
save 900 1 每900秒(15分钟)至少有1个key发生变化,则dump内存快照
save 300 10 每300秒(5分钟)至少有10个key发生变化,则dump内存快照
save 60 10000 每60秒(1分钟)至少有10000个key发生变化,则dump内存快照

AOF持久化机制:需要手动开启,需要配置

AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。

AOF 持久化:记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。

关键字 持久化时机 解释
appendfsync always 每执行一次更新命令,持久化一次
appendfsync everysec 每秒钟持久化一次
appendfsync no 不持久化

 RDB 持久化和AOF 持久化区别

优点 缺点
RDB

1.RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快(因为其文件要比AOF的小)

2.RDB的性能要比AOF更好

1.RDB的持久化不够及时(一定时间间隔),可能会存在数据丢失

2.RDB持久化时如果文件过大可能会造成服务器的阻塞,停止接收客户端请求

AOF

1.AOF的持久性更加的耐久(可以每秒 或 每次操作保存一次)

2.AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松,AOF是增量操作

1.AOF 文件的体积通常要大于 RDB 文件的体积

2.AOF 的速度可能会慢于 RDB

Redis的模式

  • Standaloan模式(单机模式)单机模式是指在单台服务器中运行的Redis程序,是最原始最基本的模式。所有服务连接一台Redis服务,该模式不适用生产。如果发生宕机,内存爆炸,就可能导致所有连接改redis的服务发生缓存失效引起雪崩

  • Master-slave模式(主从模式) 可以实现读写分离,数据备份。但是并不是「高可用」的

  • Sentinel模式(哨兵模式) 可以看做是主从模式的「高可用」版本,其引入了Sentinel对整个Redis服务集群进行监控。但是由于只有一个主节点,因此仍然有写入瓶颈。
  • Cluster模式 (集群模式)不仅提供了高可用的手段,同时数据是分片保存在各个节点中的,可以支持高并发的写入与读取。当然实现也是其中最复杂的。

1.Master-slave模式(主从模式)

Redis的主从模式指的就是主从复制(数据同步原理):

  1. 从服务器向主服务器发起SYNC 或 PSYNC 命令
  2. 主服务器执行 BGSAVE命令,生成RDB文件,并使用缓存区记录从现在开始的所有写命令
  3. RDB文件生成完成后,主服务器会将其发送给从服务器
  4. 从服务器载入RDB文件,将自己的数据库状态同步更新为主服务器执行 BGSAVE命令时的状态。
  5. 主服务器将缓冲区的所有写命令发送给从服务器,从服务将执行这些写命令,数据库状态同步为主服务器最新状态。

SYNC 与 PSYNC的区别

  • SYNC
    从服务器重新向主服务器发起 SYNC命令,主服务器将所有数据再次重新生成RDB快照发给从服务器开始同步
  • PSYNC
    从服务器重新向主服务器发起 PSYNC命令。主服务器根据双方数据的偏差量判断是否是需要完整重同步还是仅将断线期间执行过的写命令发给从服务器。

PSYNC如何实现部分重同步?

        实现部分重同步主要靠三部分:

                1. 记录复制偏移量

                2. 复制积压缓冲区

                3. 记录服务器ID

2.Sentinel模式(哨兵模式)

哨兵的作用:

  • 监控:Sentinel 会不断检查您的master和slave是否按预期工作

  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主

  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端

3.Cluster模式 (集群模式) 

        Redis的集群模式为了解决系统的横向扩展以及海量数据的存储问题,如果你的数据量很大,那么就可以用redis cluster。

Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上。

数据key不是与节点绑定,而是与插槽绑定。16384=16*1024=16*2^10

Redis如何判断某个key应该在哪个实例?

        1.将16384个插槽分配到不同的实例

        2.根据key的有效部分计算哈希值,对16384取余

        3.余数作为插槽,寻找插槽所在实例即可