Redis

一、前言

​ Windows 和 Linux 的压缩包都放在 这里了,都是 5.0.14 版本,应该就够用。

二、NOSQL 简介

(一)关系型数据库

​ 在一个给定的应用领域中,所有实体及实体之间联系的集合构成一个关系数据库。关系数据库的型称为关系数据库模式,是对关系数据库的描述,若干域的定义,在这些域上定义的若干关系模式;关系数据库的值是这些关系模式在某一时刻对应的关系的集合,通常简称为关系数据库。

(二)什么是 nosql

​ NoSQL 是 Not Only SQL 的缩写,意即 "不仅仅是SQL" 的意思,泛指非关系型的数据库。强调 Key-Value Stores 和文档数据库的优点,而不是单纯的反对RDBMS。

(三)什么是 Redis

​ Redis 是一个开源(BSD 许可)、基于内存、支持多种数据结构的存储系统,可以作为数据库、缓存和消息中间件。它支持的数据结构有字符串(strings)、哈希(hashes)、列表(lists)、集合 (sets)、有序集合(sorted sets)等,除此之外还支持 bitmaps、hyperloglogs 和地理空间( geospatial )索引半径查询等功能。

​ 它内置了复制(Replication)、LUA 脚本(Lua scripting)、LRU 驱动事件(LRU eviction)、事 务(Transactions)和不同级别的磁盘持久化(persistence)功能,并通过 Redis 哨兵(哨兵)和集群(Cluster)保证缓存的高可用性(High availability)。

(四)为何使用缓存

​ 使用缓存的目的就是提升读写性能。而实际业务场景下,更多的是为了提升读性能,带来更好的性能,带来更高的并发量。 Redis 的读写性能比 Mysql 好的多,我们就可以把 Mysql 中的热点数据缓存到 Redis 中,提升读取性能,同时也减轻了 Mysql 的读取压力。

三、Windows 中使用 Redis

​ 下载完压缩文件,解压就可以了。

​ 下面这行是 redis 配置文件中的密码,设不设置看个人喜好。

# requirepass foobared
配置了配置文件可以
 redis-server.exe redis

​ 下面的 redis-server.exe 是服务端,关了这个窗口 redis 服务就会关闭,下面的 redis-cli.exe 是客户端。

image-20230603205942582

image-20230603210026489

推荐使用 图形化工具代替 cli

image-20230604183257251

四、Linux 使用 Redis

​ 我参考是别人的博客CentOS7 安装 redis设置开机自启动

​ Redis 都启动了,在这里留个 标记记录一下 mysql 的远程连接。

​ 安装 mysql 参考的是 这篇文章,最后如果报错 [ERROR] The server quit without updating PID file 的话我是直接把 MariaDB 卸载了,好像说是会冲突。

​ 安装 JDK 教程很多,太久远了我也找不到自己安装的教程了。

​ 最后也是都跑起来了。

image-20230604100307816

五、Redis 的基本操作

(一)Redis 的数据结构

​ Redis 是键值对类型的数据库,KEY 的类型一般是 String ,VALUE 的类型多样,包括 String、Hash、List、Set、SortedSet 五种基本数据类型,以及 GEO、BitMap、HyperLog 等特殊类型。

image-20230608094204201

image-20230608101724511

(二)Redis 的通用命令

​ redis是一个单线程的,且与网络的带宽有关,底层是c语言写的,原子性的操作,不区分大小写命令。

​ Redis命令十分丰富,包括的命令组有Cluster、Connection、Geo、Hashes、HyperLogLog、Keys、Lists、Pub/Sub、Scripting、Server、Sets、Sorted Sets、Strings、Transactions一共14个redis命令组两百多个redis命令。只需要记个差不多就可以了,无论是在 cli 的客户端还是 RESP 的控制台,都可以找到相关命令的提示。

image-20230608092716990

命令 参数 说明
KEYS [pattern] 查看所有符合 pattern 的 key,返回一组 key
DEL key 删除指定的 key,返回受影响的个数
EXISTS key 是否存在
EXPIRE key second 设置 key 有效期,参数为 key 和 second
TTL key 查看 key 剩余有效期,长期为 -1 ,失效为 -2

String 类型的常见命令

命令 说明
SET 添加或者修改已经存在的一个String 类型的键值对
GET 根据 key 获取 String 类型的value
MSSET 批量添加多个String 类型的键值对
MSGET 根据多个 key 获取多个String 类型的 value
INCR 让一个整型的 key 自增1
INCRBY 让一个整型的 key 自增并指定步长,例如:incrby num2 让num值自增2
INCRBYFLOAT 让一个浮点类型的数字自增并指定步长
SETNX 添加一个 String 类型的键值对,前提是这个 key 不存在,否则不执行
SETEX 添加一个 String 类型的键值对,并且指定有效期

Hash 的常用命令

命令 说明
HSET key field value 将哈希表 key 中的字段 field 的值设为 value
HGET key field 获取存储在哈希表中指定字段的值
HDEL key field 删除存储在哈希表中的指定字段
HKEYS key 获取哈希表中所有字段
HVALS key 获取哈希表中所有值
HGETALL key 获取在哈希表中指定 key 的所有字段和值

List 的常用命令

命令 说明
LPUSH key value1 [value2] 将一个或多个值插入到列表头部
LRANGE key start stop 获取列表指定范围内的元素
RPOP key 移除并获取列表最后一个元素
LLEN key 获取列表长度
BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超 时或发现可弹出元素为止

Set 的常用命令

命令 说明
SADD key member1 [member2] 向集合添加一个或多个成员
SMEMBERS key 返回集合中的所有成员
SCARD key 获取集合的成员数
SINTER key1 [key2] 返回给定所有集合的交集
SUNION key1 [key2] 返回所有给定集合的并集
SDIFF key1 [key2] 返回给定所有集合的差集
SREM key member1 [member2] 移除集合中一个或多个成员

Sorted Set (有序集合)命令

KEYS pattern 查找所有符合给定模式( pattern)的 key
EXISTS key 检查给定 key 是否存在
TYPE key 返回 key 所储存的值的类型
TTL key 返回给定 key 的剩余生存时间(TTL, time to live),以秒为单位
DEL key 该命令用于在 key 存在是删除 key

六、Redis 的数据结构

​ 我所参考的博客,感觉比较全面了,结合实际的应用场景;这个 对于数据结构的描述有图片,更直观了解。

​ Redis最为常用的数据类型主要有String、Hash、List、Set、 Sorted set、 pub/sub、 Transactions。

image-20230617113933137

(一)内存管理对不同数据类型的描述

image-20230617103412587

​ 首先Redis内部使用一个 redisObject 对象来表示所有的 key 和 value,redisObject 最主要的信息如上图所示:type 代表一个 value 对象具体是何种数据类型,encoding 是不同数据类型在redis内部的存储方式,比如:type=string 代表 value 存储的是一个普通字符串,那么对应的 encoding 可以是 raw 或者是 int,如果是 int 则代表实际 redis 内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:"123" "456"这样的字符串。

(二)Redis 的 -key 的层级结构

​ 相比较于 Mysql ,Redis 中没有 Table 的概念。假如在传统的关系数据库中有 user 和 product 两个表,我们就都可以把他们的主键定义为字段 id,有一个用户的 id 是1,一个商品的 id 也是1,这恒河里吧。

​ Redis 的 key 允许有多个单词形成层级结构,多个单词之间用 ':' 隔开,格式如下:

#User 相关的 Key
Springboot_heima:user:1
#Product 相关的 Key
Springboot_heima:product:1

image-20230617105458579

​ 如果 Value 是一个 java 对象,例如一个 User 对象,侧可以将对象序列化为SON字符串后存储:

image-20230617105216050

(三)String

string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。value其实不仅是String,也可以是数字(上面有说到关于 String 的自增自减)。string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

​ ⏬应用场景

​ String 是最常用的一种数据类型,普通的 key / value 存储都可以归为此类,即可以完全实现目前 Memcached 的功能,并且效率更高。还可以享受Redis的定时持久化,操作日志及 Replication等功能。

(四)Hash

Redis hash 是一个键值(key => value)对集合。Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

image-20230617114309841

​ ⏬应用场景

​ 我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:

​ 用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式:

image-20230617111204963

​ 第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,就像在 “Redis 的 -key 的层级结构” 这一部分所说的,但是增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。

​ 第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,就是纯纯的浪费内存了。

​ 那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口,如下图:

image-20230617111408671

​ 也就是说,Key 仍然是用户 ID, value 是一个Map,这个 Map 的key是成员的属性名,value 是属性值,这样对数据的修改和存取都可以直接通过其内部 Map 的 Key ( Redis 里称内部 Map 的 key 为 field ) , 也就是通过 key (用户ID) + field (属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题,很好的解决了问题。

​ Redis Hash对应Value内部实际就是一个 HashMap ,实际这里会有2种不同实现,这个 Hash 的成员比较少时 Redis 为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的 HashMap 结构,对应的 value redisObject 的encoding为 zipmap,当成员数量增大时会自动转成真正的 HashMap,此时encoding为ht。

​ 同时需要注意,Redis 提供了接口 (hgetall) 可以直接取到全部的属性数据,但是如果内部 Map 的成员很多,那么涉及到遍历整个内部 Map 的操作,由于 Redis 单线程模型的缘故,这个遍历操作可能会比较耗时,而另其它客户端的请求完全不响应,这点需要格外注意。

(五)List

Redis list 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

image-20230617114324072

​ ⏬应用场景

​ Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。

​ List 就是链表,使用List结构,我们可以轻松地实现最新消息排行等功能。List的另一个应用就是消息队列,可以利用 List 的 PUSH 操作,将任务存在 List 中,然后工作线程再用 POP 操作将任务取出进行执行。Redis 还提供了操作 List 中某一段的 api,你可以直接查询,删除 List 中某一段的元素。

GRANT ALL PRIVILEGES ON . TO 'root'@'10.186.196.110' IDENTIFIED BY 'root' WITH GRANT OPTION;

(六)Set

Redis set是string类型的无序集合。集合是通过hashtable实现的,概念和数学中个的集合基本类似,可以交集,并集,差集等等,set中的元素是没有顺序的。所以添加,删除,查找的复杂度都是O(1)。

image-20230617114333688

​ ⏬应用场景

​ Redis set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是list所不能提供的。

​ Set 就是一个集合,集合的概念就是一堆不重复值的组合。利用 Redis 提供的 Set 数据结构,可以存储一些集合性的数据。

(七)SortedSet

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

image-20230617114341555

​ ⏬使用场景

​ Redis sorted set 的使用场景与 set 类似,区别是 set 不是自动有序的,而 sorted set 可以通过用户额外提供一个优先级 (score) 的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择 sorted set 数据结构,比如twitter 的 public timeline 可以以发表时间作为 score 来存储,这样获取时就是自动按时间排好序的。

​ 和 Set 相比,Sorted Set关联了一个double类型权重参数score,使得集合中的元素能够按 score 进行有序排列,redis 正是通过分数来为集合中的成员进行从小到大的排序。zset 的成员是唯一的,但分数 (score) 却可以重复。比如一个存储全班同学成绩的 Sorted Set,其集合 value 可以是同学的学号,而 score 就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。另外还可以用Sorted Set 来做带权重的队列,比如普通消息的 score 为1,重要消息的 score 为2,然后工作线程可以选择按 score 的倒序来获取工作任务。让重要的任务优先执行。

七、在 IDEA 中使用 Redis

​ 在 yml 文件中配置 Redis 的数据源,没有设置 Redis 的密码所以不用写

  redis:
    database: 0
    host: 127.0.0.1
    password:
    port: 6379
    lettuce:
      pool:
        max-active: 8 # 最大连接
        max-idle: 8 # 最大空闲连接
        min-idle: 0 # 最小空闲连接
        max-wait: 100ms # 连接等待时间

​ 引入 SpringBoot 整合的 Redis 依赖,SpringBoot1.0 的时候还需要引入 jedis 的依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

​ Spring 提供了 RedisTemplete 类封装了各种操作 Redis 数据的方法,StringRedisTemplate 继承了RedisTemplate,并对其中的一些方法进行了修改。StringRedisTemplate 和 redis 中的数据类型是一样的。也分为五种,对应着不同的方法:

stringRedisTemplate.opsForValue();   //操作字符串
stringRedisTemplate.opsForHash();   //操作hash
stringRedisTemplate.opsForList();   //操作list
stringRedisTemplate.opsForSet();    //操作set
stringRedisTemplate.opsForZSet();   //操作有序set

​ 把 redisTemplete 注入就可以使用了。

    @Autowired
    private StringRedisTemplate redisTemplate;
    @RequestMapping("/rds")
    public Map getRedisValue() {
        String name =  redisTemplate.opsForValue().get("name");
        System.out.println(redisTemplate.hasKey("name"));
        HashMap hashMap = new HashMap();
        hashMap.put("name", name);
        return hashMap;
    }

​ 返回的 Json 字符结果。

{
    "name": "0号库中的name"
}

​ 不要注入错了😢,RedisTemplete 和 StringRedisTemple 是不一样的,StringRedisTemplete 在继承了 RedisTemplete 的同时在构造器中重写了关于序列化的策略,也就是说这两个类的序列化是不一样的。使用 RedisTemplete 存入数据数据库中存储的是 字节数组,也只能读取这种东西,但是我存入的 name 是在 热水瓶(RESP)中放入的字符串所以读不出来。具体可以看这个 或者 这一篇

八、Redis 持久化

(一)RDB 快照(snapshot)

​ 在默认情况下, Redis 将内存数据库快照保存在名字为 *dump.rdb* 的二进制文件中。你可以对 Redis 进行设置, 让它在 “ N 秒内数据集至少有 M 个改动” 这一条件被满足时, 自动保存一次数据集。比如说, 以下设置会让 Redis 在满足“ 60 秒内有至少有 1000 个键被改动”这一条件时, 自动保存一次。

# save 60 1000

image-20230618103916781

​ ⏬windows 中的配置文件

image-20230618104505178

(二)AOF(append-only file)

​ 快照功能并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化,将修改的每一条指令记录进文件appendonly.aof中

#你可以通过修改配置文件来打开 AOF 功能:
appendonly yes

​ 每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。这样的话, 当 Redis 重新启动时, 程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。

image-20230618104621416

(三)混合模式(dump+aof)

​ 重启 Redis 时,我们很少使用 RDB来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 RDB来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。

​ Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化

​ 假如设置 dump 为 “60秒内变动两次就进行持久化”,当不到 60s Redis 关闭,在该 60s 之前的数据会存储到 dump 中,同时 60s 之前的 “操作” 被删除,这次尚未保存的数据 Redis 会把操作记录到 aof 中,下次在已有的 dump 基础上执行 aof 的操作即可。

#通过如下配置可以开启混合持久化:
aof-use-rdb-preamble yes
posted @ 2023-06-18 10:55  Purearc  阅读(42)  评论(0编辑  收藏  举报