文章目录
前言
最近在复习Redis相关内容,顺便整理一下,相关基础知识
一、 Redis基本数据类型
-
String
-
二进制安全,就是说这个redis的string可以包含任何数据,包括图片或者序列化的对象。
-
一个键最大存储大小为512M
-
应用场景: 常用进行阅读量,访问量等数量统计,使用incr等自加自减操作
-
常用命令
- get:获取值
- set:设置值
- incr:自加
- decr:自减
- incrby:加
- decrby:减
-
Hash
- redis hash是一个键值对(key(string) => value((key,value))),可以看着一个string类型的key和一个可以存放对象结构(键值对)的value。
- 一个key可以放多个value(多个key不同的键值对)
- 每一个Hash可以存储4294967295个键值对。
- 应用场景: 保存/读取/修改对象属性
- 常用命令
- hset:添加hash数据 => hset key key1 value
- hget:获取hash数据 => get key key1
- hmget:获取多个hash数据 => hmget key key1 key2
-
List
- Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
- List中可以包含的最大元素数量是4294967295。
- 列表由多个字符串值组成的有序可重复的序列,是链表结构,所以向列表两端添加元素的时间复杂度为0(1),获取越接近两端的元素速度就越快。
- 应用场景
- 最新消息排行榜
- 消息队列
- 常用命令
- lpush:从左边推入 => lpush listname value1
- lpop:从左边弹出并返回第一个值 => lpop listname
- rpush:从右变推入 => rpush listname value2
- rpop:从右边边弹出并返回第一个值 => rpop listname
- llen:查看某个list数据类型的长度 => llen listname
-
Set
- Redis的set是无序不可重复的
- Set可包含的最大元素数量是4294967295。
- Set是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
- 应用场景: 利用唯一性,可进行IP相关的统计和限制操作
- 常用命令
- sadd:添加数据
- spop:删除数据
- scard:查看set数据中存在的元素个数
- sismember:判断set数据中是否存在某个元素
- srem:删除某个set数据中的元素
-
Sort Set(zset)
- Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
- 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
- zset的成员是唯一的,但分数(score)却可以重复。
- sorted set是插入有序的,即自动排序。
- 应用场景
- 有分数排行需求的排行榜
- 常用命令
- zadd:添加 => zadd key 1.1 value
- zcard:查询 => zcard key
- zrange:数据排序 => orange key 0 2 withscores. (分数0-2之间的键值对)
二、键值(key)的常用操作
- 如何从所有数据中获取固定格式的数据,如某固定格式开始的,如查询所有的“key1”开头的key,就可以使用【KEYS PATTERN】
keys key1*
缺点是: 当数据量非常大的时候,对机器的内存消耗非常大,可能会造成机器卡顿,这是因为,keys指令会一次性返回所欲匹配的key
-
就像后端一次性获取所有数据会导致每次获取都会消耗很大的服务器资源,通常我们都会使用分页。
Redis中的SCAN就类似分页能分批次的获取数据(如果不对请指正0.0)
命令格式为:
【SCAN cursor [MATCH pattern] [COUNT count]】
- cursor - 游标。
- pattern - 匹配的模式。
- count - 指定从数据集里返回多少元素,默认值为 10 。
基本用法
redis 127.0.0.1:6379> scan 0 # 使用 0 作为游标,开始新的迭代
1) "17" # 第一次迭代时返回的游标
2) 1) "key:12"
2) "key:8"
3) "key:4"
4) "key:14"
5) "key:16"
6) "key:17"
7) "key:15"
8) "key:10"
9) "key:3"
10) "key:7"
11) "key:1"
redis 127.0.0.1:6379> scan 17 # 使用的是第一次迭代时返回的游标 17 开始新的迭代
1) "0"
2) 1) "key:5"
2) "key:18"
3) "key:0"
4) "key:2"
5) "key:19"
6) "key:13"
7) "key:6"
8) "key:9"
9) "key:11"
回到上个问题
这是个基于游标的迭代器,从0开始,到0结束完一次遍历,中间使用上一次游标来进行迭代过程的延续。每次返回的格式不可控,只是大概符合count参数,具体看以下模拟过程。
// 假设符合条件数据大于100
// 会返回2个数据 1是下一次开始的游标,2是返回的结果
sacn 0 match key1* count 10
1) "655360"
2) 1) "key1864385"
2) "key1392840"
3) "key1388130"
4) "key1357007"
5) "key1743332"
6) "key1593973"
7) "key1399047"
// 下次获取就需要上次迭代的游标
scan 655360 match key1* count 10
1) "327680"
2) 1) "key1610178"
2) "key1693505"
3) "key1032175"
4) "key1721788"
5) "key1678140"
6) "key1359412"
// 以后就这样循环,直到下次游标为0
scan 327680 match key1* count 10
1) "2031616"
2) 1) "key1798037"
2) "key1805785"
3) "key1837836"
4) "key1138914"
5) "key1689917"
6) "key1033258"
关于这什么时候使用哪种方式,这要根据数据量决定,数据量不大可以使用keys,数据量大用scan
注意⚠️
- scan获取的数据会存在重复,要注意去重
- 要主要获取上一次的游标,就像是分页查询的当前页
- rename(rename key, newkey) 对key重命名
- renamenx(rename key, newkey) 仅当newkey不存在时,对key重命名为newkey
- Type(key) 返回key的类型
- expire(key, second) 以秒为单位设置key失效时间
- expireat(key, timestamp) 以时间戳设置key失效时间
- pexpireat(key, timestamp) 以毫秒为单位设置key失效时间
- persist(key) 一处key的失效时间
- ttl(key) 返回key所剩余时间(返回-2表示key不存在, -1 表示永远不过时)
- pttl(key) 以毫秒为单位返回失效时间
- randomkey 随机返回一个key
- dump(key) 序列化给定key
三、Redis持久化方式
由于Redis是基于内存的,进程关闭后数据就会丢失,所以Redis就有了3种持久化的方式
3.1 持久化方式之RDB
RDB又称为快照模式,在此模式下,Redis会定期将全量数据保存为dump.rdb(二进制)文件。
RDB文件可以通过两个命令来生成,一个是SAVE,一个是BGSAVE,两者的区别主要是SAVE会阻塞服务器进程(众所周知,Redis是使用单线程模型),而BGSAVE是Fork(系统调用的方法,用来创建进程)一个子进程出来创建RDB文件,不阻塞进程。
相比于传统创建进程,Linux的fork()方法实现了Copy-on-Write(写时复制),传统方式创建子进程会将会复制所有资源给子进程一份,效率低下且不一定所有资源子进程都需要。而Linux优化了这个方法,当主进程创建子进程时,内核只为子进程创建一个虚拟空间,主进程和子进程使用同一物理空间,只有发生更改时,才会为子进程分配独立的物理空间。
例如,多个调用者请求相同资源,他们会获取到一个指向相同资源地址的指针,直到某个调用者试图更改资源内容,系统才会真正复制一份副本给该调用者,其他调用者见到的依旧是最开始的版本,直到新数据写入,更新指针,就都能读取到最新的内容了。
可以通过使用命令lastsave来查看最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示。
redis 127.0.0.1:6379> LASTSAVE
(integer) 1410853592
除了手动命令创建外,还可以通过
- 配置redis.conf来配置SAVE m n 来指定触发规则,这个方式使用的命令是BGSAVE
- debug reload - save当前的rdb文件,并清空当前数据库,重新加载rdb
- 如果没有开启AOF,执行Shutdown,会执行以下操作
- 停止所有客户端
- 如果有至少一个保存点在等待,执行 SAVE 命令
- 如果 AOF 选项被打开,更新 AOF 文件
- 关闭 redis 服务器(server)
缺点:
- 内存数据是全量同步而不是根据变化增量同步,数据量大导致的I/O操作会严重影响性能。
- 由于是定期保存,如果服务突然宕机,就会丢失当前到最近一次快照期间的数据。
3.2 持久化方式之AOF
知道了RDB模式的缺点,我们来看看另一种持久化的方式就是AOF(Append-Only-File)持久化,简单点来说就是
- 记录除了查询以外的所有变更数据库状态的命令
- 以append的形式追加保存到AOF文件中(增量形式)
AOF配置默认是关闭的,可以通过修改redis.conf的appendonly 为 yes就可以了,还可以通过配置appendfsync来配置AOF文件的写入方式,总共有3种
- appendfsync always 一但缓冲区内容发生变化,就记录一次
- appendfsync everysec 每秒记录一次
- appendfsync no 将决定权交给系统,系统一般会在缓存区满后进行记录
AOF方式由于是记录操作的(就像日志)方式,可能存在相同的操作命令执行多次(比如某个值递增了100次),记录了多次,这会导致AOF文件会越来越大,但实际上我们只需要知道最后的状态就可以了。基于这种情况,Redis提供了一个重写日志的方法,就是会将上面提到的多余的操作进行重写,生成一个最精简的AOF文件,这种机制可以通过两种方式触发。
- 手动触发,执行bgrewriteaof命令
- 配置redis.conf auto-aof-rewrite-min-size 表示运行AOF重写是文件最小的大小。默认64M,小于64M就会不自动重写了。
3.3 RDB VS AOF 对比以及相关问题
RDB
- 优点: 全量数据快照,文件小,恢复快
- 缺点: 无法保存最近一次快照之后的数据(备份粒度较粗)
AOF
- 优点:可读性高,适合保存增量数据,数据不易丢失
- 缺点:文件体积大,恢复时间长
对于这两种方法,官方的回答是
通常,如果你要想提供很高的数据保障性,那么建议你同时使用两种持久化方式。如果你可以接受灾难带来的几分钟的数据丢失,那么你可以仅使用RDB。很多用户仅使用了AOF,但是我们建议,既然RDB可以时不时的给数据做个完整的快照,并且提供更快的重启,所以最好还是也使用RDB。
-
如何使用RDB或者AOF进行恢复?
- 在redis重启或者退出,都会执行shutdown进行相对应文件(RDB或者AOF)文件的读取和加载
-
当RDB和AOF两种文件总存的情况下,redis的恢复流程?
- 一句话,有AOF加载AOF,忽略RDB;没有AOF,加载RDB。
3.4 RDB-AOF混合持久化方式
在了解的两种方法的优缺点后,Redis在4.0后推出了结合两者优点的混合持久化方式并作为默认的持久化方法。
这种模式实现了以RDB保存全量数据+AOF进行增量补齐的操作,既实现了RDB文件的恢复快,文件小的特点,也保留了AOF文件数据不易丢失的优点。
这种方式是使用BGSAVE做全量持久化,AOF做增量持久化,在Redis实例重启时,会使用BGSAVE持久化文件并重新构建内容,加上AOF的近期命令来完整恢复到最新的状态