Redis
一、Redis概述
1.1 Redis简介
Redis之所以被称为字典服务,这是因为Redis是一个key-value存储系统。支持存储的value类型很多。包括==String(字符串)、List(链表)、Set(集合)、Zsort(sorted set–有序集合)和Hash(哈希类型)==等。
Redis的国际知名用户有:Twiiter、GitHub、Facebook等。国内有:阿里巴巴、腾讯、百度、搜狐、优酷、美团、小米等。熟练的使用和运维Redis已经成为开发运维人员的一个必备技能。
1.1.1 NoSQL
NoSQL:一种非关系型数据库,为了解决大规模数据集合多重数据种类带来的挑战,特别是大数据难题,即高并发问题。
NoSQL分类:
- 键值存储数据库:哈希表,key-value,典型代表就是Redis。
- 列存储数据库:对比关系型数据库,关系型数据库是典型的行存储数据库,其存在的问题是,按行存储的数据在物理层面占用的是连续的存储空间,所有它不适合海量的数据。而按列存储则可实现分布式存储,适合海量存储,典型代表是HBase。
- 文档性数据库:其是NoSQL和关系型数据库的结合,是最像关系型数据库的NoSQL,典型代表是MangoDB。
- 图形(Graph)数据库:用于存放一个节点关系的数据库,例如描述不同人之间的关系,它不是存储在表中,而是网络中各个节点中,类似于图数据结构。典型的代表是Neo4J。
1.2 Redis的用途
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IEFy8OGn-1684386150214)(D:\笔记图片\java笔记图片\redis缓存机制.png)]
1.3 Redis特性
-
性能极高:Redis读的速度可以达到11w次/s,写的速度可以达到8w次/s。之所以具有怎么高的性能,因为以下几点原因:
- Redis所有的操作都是在内存中发生的。
- Redis是用C语言开发的。
- Redis源码非常精细(集性能与优雅于一身)。
-
简单稳定:Redis源码很少。早起版本只有2w行左右。从3.0增加了集群功能,代码变为了5w行。
-
持久化:Redis内存中的数据可以进行持久化,其有两种方式:RDB与AOF。
-
高可用集群:Redis提供了高可用的主从集群功能,可以确保系统的安全性。
-
丰富的数据类型:Redis是一个key-value存储系统。支持存储的value类型很多。包括String(字符串)、List(链表)、Set(集合)、Zsort(sorted set–有序集合)和Hash(哈希类型)等,还有BitMap、HyperLogLog、Geospatial类型。
BitMap:一般用于大数据量的二值统计。
HyperLogLog:其是Hyperlog Log 超级日志记录,用于对数据量超级庞大的日志做去重统计。
Geospatial:地理空间,其主要用于地理位置相关的计算。(如某软件附近的人)
-
强大的功能:Redis提供了数据过期功能、发布/订阅、简单事务功能,还支持Lua脚本扩展功能。
-
客户端语言广泛:Redis提供了简单的TCP通信协议,编程语言可以方便的接入Redis。所以有很多的开源社区、大公司等开发出了很多语言的Redis客户端。
-
支持ACL权限控制:从Redis6开始引入了ACL模块,可以为不同用户定制不同的用户权限。之前的权限控制非常笨拙。
ACL,Access Control List 访问控制链表,是一种细粒度的权限管理策略,可以针对任意用户与组进行权限控制。目前大多数Unix系统与Linux 2.6 版本已经支持ACL了。Zookeeper早已支持ACL了。
Unix和Linux系统默认使用的是UGO(User Group Other)权限控制策略,其是一种粗粒度的权限管理策略。
-
支持多线程IO模型:Redis之前版本采用的是单线程模型,Redis 6.0 后已经可以支持多线程模型了,
1.4 Redis的 IO 模型
Redis 客户端提交的各种请求是如何最终被 Redis 处理的?Redis 处理客户端请求所采用的处理架构,称为Redis 的 IO 模型。不同版本的 Redis 采用的 IO 模型是不同的。
1.4.1 单线程模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8prB4yaM-1684386150215)(D:\笔记图片\java笔记图片\redis单线程.png)]
Redis 的单线程模型采用了多路复用技术。
对于多路复用器的多路选择算法常见的有三种:select 模型(数组)、poll 模型(链表)、epoll 模型。
- poll 模型的选择算法:采用的是轮询算法。该模型对客户端的就绪处理是有延迟的。
- epoll 模型的选择算法:采用的是回调方式。根据就绪事件发生后的处理方式的不同,
又可分为 LT 模型与 ET 模型。
1.4.2 混合线程模型
从 Redis 4.0 版本开始,Redis 中就开始加入了多线程元素。处理客户端请求的仍是单线程模型,但对于一些比较耗时但又不影响对客户端的响应的操作,就由后台其它线程来处理。例如,持久化、对 AOF 的 rewrite、对失效连接的清理等。
1.4.3 多线程模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v4Qs31gj-1684386150215)(D:\笔记图片\java笔记图片\redis多线程.png)]
==结合了单线程和多线程的优点,多线程 IO 模型中的“多线程”仅用于接受、解析客户端的请求,然后将解析出的请求写入到任务队列。而对具体任务(命令)的处理,仍是由主线程处理。==这样做使得用户无需考虑线程安全问题,无需考虑事务控制,无需考虑像 LPUSH/LPOP 等命令的执行顺序问题。
总结:redis的多线程在接受和解析请求的时候是多线程的,而在处理请求的时候是单线程的(一个主线程)。
1.4.4 优缺点总结
(1 ) 单线程模型
- 优点:可维护性高,性能高。不存在并发读写情况,所以也就不存在执行顺序的不确定
性,不存在线程切换开销,不存在死锁问题,不存在为了数据安全而进行的加锁/解锁
开销。 - 缺点:性能会受到影响,且由于单线程只能使用一个处理器,所以会形成处理器浪费。
(2 ) 多线程模型
- 优点:其结合了多线程与单线程的优点,避开了它们的所有不足
- 缺点:该模型没有显示不足。如果非要找其不足的话就是,其并非是一个真正意义上的
“多线程”,因为真正处理“任务”的线程仍是单线程。所以,其对性能也是有些影响的。
总结:一方面可以并发的接受和解析请求,相当于单线程,性能有了提升(多线程的优点)。
另一方面:最终处理请求只有一个主线程来处理,这样也保证了系统的安全性(单线程的优点)。
二、Redis安装
三、五大数据类型及命令
Redis键(key)相关命令
命令名称 | 作用 |
---|---|
keys * | 查看当前库所有key (匹配:keys *1) |
exists key | 判断某个key是否存在 |
type key | 查看你的key是什么类型 |
del key | 删除指定的key数据 |
unlink key | 根据value选择非阻塞删除仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。 |
expire key 10 | 10秒钟:为给定的key设置过期时间 |
ttl key | 查看还有多少秒过期,-1表示永不过期,-2表示已过期 |
select [0~15] | 命令切换数据库,一共16个数据库 |
dbsize | 查看当前数据库的key的数量 |
flushdb | 清空当前库 |
flushall | 通杀全部库 |
1、String
数据结构为简单动态字符串。内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。
命令名称 | 作用 |
---|---|
set | 添加键值对 |
get | 查询对应键值 |
append | 将给定的 追加到原值的末尾 |
strlen | 获得值的长度 |
setnx | 只有在 key 不存在时 设置 key 的值 |
incr | 将 key 中储存的数字值增1,空的话新增值为1 |
decr | 将 key 中储存的数字减1,空的话值为-1 |
incrby / decrby <步长> | 将 key 中储存的数字值增减。自定义步长 |
mset … | 同时设置一个或多个 key-value对 |
mget … | 同时获取一个或多个 value |
msetnx … | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在 |
getrange <起始位置><结束位置> | 获得值的范围,类似java中的substring |
setrange <起始位置> | 用 覆写所储存的字符串值,从<起始位置>开始 |
setex <过期时间> | 设置键值的同时,设置过期时间,单位秒。 |
getset | 以新换旧,设置了新值同时获得旧值。 |
2、List
数据结构为快速链表quickList。首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
命令名称 | 作用 |
---|---|
lpush/rpush … | 从左边/右边插入一个或多个值 |
lpop/rpop | 从左边/右边吐出一个值。值在键在,值光键亡 |
rpoplpush | 从列表右边吐出一个值,插到列表左边。 |
lrange
| 按照索引下标获得元素(从左到右) |
lrange mylist 0 -1 | 0左边第一个,-1右边第一个,(0-1表示获取所有) |
lindex | 按照索引下标获得元素(从左到右) |
llen | 获得列表长度 |
linsert before | 在的后面插入插入值,value带" " |
lrem | 从左边删除n个value(从左到右) |
lset | 将列表key下标为index的值替换成value |
3、Set
数据结构是dict字典,字典是用哈希表实现的。Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。
命令名称 | 作用 |
---|---|
sadd … | 将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略 |
srem … | 删除集合中的某个元素 |
smembers | 取出该集合的所有值 |
sismember | 判断集合是否为含有该值,有1,没有0 |
scard | 返回该集合的元素个数 |
spop | 随机从该集合中吐出一个值 |
srandmember | 随机从该集合中取出n个值,不会从集合中删除 |
smove value | 把集合中一个值从一个集合移动到另一个集合 |
sinter | 返回两个集合的交集元素 |
sunion | 返回两个集合的并集元素 |
sdiff | 返回两个集合的****差集****元素(key1中的,不包含key2中的) |
4、Hash
Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。
命令名称 | 作用 |
---|---|
hset | 给集合中的 键赋值 |
hget | 从集合取出 value |
hmset … | 批量设置hash的值 |
hexists | 查看哈希表 key 中,给定域 field 是否存在。 |
hkeys | 列出该hash集合的所有field |
hvals | 列出该hash集合的所有value |
hincrby | 为哈希表 key 中的域 field 的值加上增量 1 -1 |
hsetnx | 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在 |
5、Zset
zset底层使用了两个数据结构:
(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。
(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。
命令名称 | 作用 |
---|---|
zadd … | 将一个或多个 member 元素及其 score 值加入到有序集 key 当中。 |
zrange
| 返回有序集 key 中,下标在
|
zrangebyscore key minmax [withscores] [limit offset count] | 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。 |
zrevrangebyscore key maxmin [withscores] [limit offset count] | 同上,改为从大到小排列。 |
zincrby | 为元素的score加上增量 |
zrem | 删除该集合下,指定值的元素 |
zcount | 统计该集合,分数区间内的元素个数 |
zrank | 返回该值在集合中的排名,从0开始。 |
四、Redis配置文件介绍
路径:/etc/redis.conf
bind
默认情况bind=127.0.0.1只能接受本机的访问请求
不写的情况下,无限制接受任何ip地址的访问
protected-mode
如果开启了protected-mode,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的响应
五、Redis的发布和订阅
1、 打开一个客户端订阅channel1
SUBSCRIBE channel1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B7Cv6VQg-1684386150216)(file:///C:\Users\MrWang\AppData\Local\Temp\ksohtml14148\wps1.jpg)]
2、打开另一个客户端,给channel1发布消息hello
publish channel1 hello
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kj0aZEoQ-1684386150217)(file:///C:\Users\MrWang\AppData\Local\Temp\ksohtml14148\wps2.jpg)]
返回的1是订阅者数量
3、打开第一个客户端可以看到发送的消息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-26KW0dEh-1684386150217)(file:///C:\Users\MrWang\AppData\Local\Temp\ksohtml14148\wps3.jpg)]
注:发布的消息没有持久化,如果在订阅的客户端收不到hello,只能收到订阅后发布的消息
六、Redis新数据类型
1、bitmap
打卡、钉钉、京东签到等,可以节省内存空间。
命令名称 | 作用 |
---|---|
setbit key offset val | 给指定key的值的第offset赋值val |
getbit key offset | 获取指定key的第offset位 |
bitcount key start end | 返回指定key中[start,end]中为1的数量 |
bitop operation destkey key | 对不同的二进制存储数据进行位运算(AND、OR、NOT、XOR) |
2、HyperLogLog
UV(unique visitor)独立访客,基数去重。属于string数据类型。
命令名称 | 作用 |
---|---|
pfadd < element> [element …] | 添加指定元素到 HyperLogLog 中 |
pfcount [key …] | 计算HLL的近似基数,可以计算多个HLL,比如用HLL存储每天的UV,计算一周的UV可以使用7天的UV合并计算即可 |
pfmerge [sourcekey …] | 将一个或多个HLL合并后的结果存储在另一个HLL中,比如每月活跃用户可以使用每天的活跃用户来合并计算可得 |
3、GEO
type:zset的子类
命令名称 | 作用 |
---|---|
geoadd< longitude> [longitude latitude member…] | 添加地理位置(经度,纬度,名称) |
geopos [member…] | 获得指定地区的坐标值 |
geodist [m/km/ft/mi] | 获取两个位置之间的直线距离 |
georadius< longitude>radius m/km/ft/mi | 以给定的经纬度为中心,找出某一半径内的元素 |
georadiusbymember | |
geohash |
4、Stream
5、bitfield
七、Redis_Jedis_测试
八、Redis_Jedis_实例
redis启动:redis-server /myredis/redis.conf
redis关闭:进入redis-cli 然后输入shutdown即可
redis相关bug
idea连接不上redis的原因:
1.防火墙未关闭
systemctl status firewalld 查看防火墙状态
systemctl stop firewalld 关闭防火墙
2.配置文件中bind 127.0.0.1没有注释掉。(不注释掉只能本机访问,不能远程访问)
3.配置文件protected-mode需要改成no(默认是yes,只能本机访问,不能远程访问)
redis的shutdown命令失效的原因:
https://blog.csdn.net/qq_45950109/article/details/114822126
redis数据库错误:MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persis的解决方法:
1.命令行方式
命令行修改方式示例:
127.0.0.1:6379> config set stop-writes-on-bgsave-error no
2.修改配置文件
修改redis.conf文件:vi打开redis-server配置的redis.conf文件,然后使用快捷匹配模式:/stop-writes-on-bgsave-error定位到stop-writes-on-bgsave-error字符串所在位置,接着把后面的yes设置为no即可。
1. 完成一个手机验证码功能
要求:
1、输入手机号,点击发送后随机生成6位数字码,2分钟有效
2、输入验证码,点击验证,返回成功或失败
3、每个手机号每天只能输入3次
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o1Ui62Qv-1684386150218)(file:///C:\Users\MrWang\AppData\Local\Temp\ksohtml17120\wps1.png)]
代码如下:
package com.atguigu.jedis;
import redis.clients.jedis.Jedis;
import java.util.Random;
public class Phone {
public static void main(String[] args) {
String phone = "15324806527";
//verify("15324806527");
getRedisCode("15324806527", "626054");
}
//3 验证码校验
public static void getRedisCode(String phone,String code){
//从redis中获取验证码
Jedis jedis = new Jedis("10.20.34.70",6379);
String redisCode = jedis.get("VerifyCode"+phone+":code");
if (redisCode==null) System.out.println("验证码已过期!!请重新发送!");
if(code.equals(redisCode)){
System.out.println("成功");
}else {
System.out.println("失败");
}
jedis.close();
}
//2 每个手机每天只能发送3次验证码到redis中,分别设置次数和验证码过期时间。
public static void verify(String phone){
Jedis jedis = new Jedis("10.20.34.70",6379);
//拼接key
//手机发送次数key
String countKey = "VerifyCode"+phone+":count";
//验证码key
String codeKey = "VerifyCode"+phone+":code";
//每个手机每天只能发送三次
String count = jedis.get(countKey);
if (count==null){
//没有发送次数,第一次发送
jedis.setex(countKey, 24*60*60, "1");
}
else if(Integer.parseInt(count)<3){
jedis.incr(countKey);
}else {
System.out.println("发送验证次数已到3次,请明天再发送!!!");
jedis.close();
}
//发送验证码放到redis里面
String code = getCode();
System.out.println(code);
jedis.setex(codeKey, 120, code);//验证码是2分钟过期
jedis.close();
}
//1 随机生成6位的数字验证
public static String getCode(){
Random random = new Random();
String s="";
for(int i=0;i<6;i++){
int rand = random.nextInt(10);
s+=rand;
}
return s;
}
}
九、Redis-事务
Redis的本质:一组命令的集合!一个事物的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
一次性、顺序性、排他性!执行一些列命令!
---------队列 set set set 执行------------
R e d i s 事务没有隔离级别的概念! \textcolor{red}{Redis事务没有隔离级别的概念!} Redis事务没有隔离级别的概念!
所有的命令在事务中,并没有直接被执行!只是发起执行命令的时候才会执行!Exec
R e d i s 单条命令是保持原子性的,但是事务不保证原子性 \textcolor{red}{Redis单条命令是保持原子性的,但是事务不保证原子性} Redis单条命令是保持原子性的,但是事务不保证原子性
redis的事务:
- 开启事务(multi)
- 命令入队(…)
- 执行事务(exec)
Redis事务执行与错误
正常执行事务
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> set k3 3
QUEUED
127.0.0.1:6379(TX)> exec #执行事务
1) OK
2) OK
3) "v2"
4) OK
取消事务(discurd
)
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> discard #取消事务
OK
127.0.0.1:6379> get k4 #事务队列中的命令都不会执行!
(nil)
事务错误
编译型异常(代码有问题!命令有错!),事务中所有命令都不会执行!
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> getset k4 #错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k5 v5
QUEUED
127.0.0.1:6379(TX)> exec #执行事务报错!
(error) EXECABORT Transaction discarded because of previous errors.
运行时异常(1/0),如果事务中存在语法性,name执行的时候,其他的命令是可以注册执行的,错误命令抛出异常!
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incr k1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"
# 虽然中间有一条命令报错了,但是后面的指令依旧正常执行成功了。
# 所以说Redis单条指令保证原子性,但是Redis事务不能保证原子性。
监控(Watch面试常问)
悲观锁:
- 很悲观,认为什么时候都会出现问题,无论做什么都会加锁
乐观锁:
- 很乐观,认为什么时候都不会出现问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据
- 获取version
- 更新的时候比较version
使用watch key
监控指定数据,相当于乐观锁加锁。
redis监视测试
正常执行成功!
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money #监视 money 对象
OK
127.0.0.1:6379> multi #事务正常结束,数据期间没有发生变动,这个时候正常执行成功!
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 80
2) (integer) 20
测试多线程修改值,使用watch 可以当做redis的乐观锁操作!
在未exec前,另一个线程修改了money的值,再exec就会监视失败。
127.0.0.1:6379> watch money #监视 money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 10
QUEUED
127.0.0.1:6379(TX)> incrby out 10
QUEUED
127.0.0.1:6379(TX)> exec #执行之前,另外一个线程,修改了我们的值,这个时候,就会导致事务执行失败!
(nil)
如果修改失败,获取最新的值就好。
unwatch-- 然后 --watch
127.0.0.1:6379> unwatch #1.如果发现事务执行失败,就先解锁。
OK
127.0.0.1:6379> watch money #2.获取最新的值,再次监视。
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 1
QUEUED
127.0.0.1:6379(TX)> incrby money 1
QUEUED
127.0.0.1:6379(TX)> exec #3.比对监视的值是否发生了变化,如果发生了变化,那么可以执行成功,如果变化就执行失败。
1) (integer) 999
2) (integer) 1000
十、Redis-事务_秒杀案例
十一、SpringBoot集成Redis
SpringBoot操作数据:Spring-data jpa jdbc mongodb redis !
SpringData也是和SpringBoot齐名的项目!
说明:springboot 2.x后 ,原来使用的 Jedis 被 lettuce 替换?
jedis:采用的直连,多个线程操作的话,是不安全的。如果要避免不安全,使用jedis pool连接池!更像BIO模式
lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况!可以减少线程数据了,更像NIO模式
十二、Redis持久化之RDB
RDB是什么?
在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
备份是如何执行的?
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
Fork作用?
Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“*写时复制技术*”
RDB持久化流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HoDyXdah-1684386150218)(C:\Users\MrWang\AppData\Roaming\Typora\typora-user-images\image-20230306142519603.png)]
save & bgsave
save :save时只管保存,其它不管,全部阻塞。手动保存。不建议。
bgsave:Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求。
可以通过lastsave 命令获取最后一次成功执行快照的时间
fushall命令
执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义
Save
格式:save 秒钟 写操作次数
RDB是整个内存的压缩过的Snapshot,RDB的数据结构,可以配置复合的快照触发条件,
默认是1分钟内改了1万次,或5分钟内改了10次,或15分钟内改了1次。
禁用:不设置save指令,或者给save传入空字符串
动态停止RDB:redis-cli config set save “” #save后给空值,表示禁用保存策略
RBD优缺点?
*优势*
-
适合大规模的数据恢复
-
对数据完整性和一致性要求不高更适合使用
-
节省磁盘空间
-
恢复速度快
*劣势*
-
Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
-
虽然Redis在fork时使用了****写时拷贝技术****,但是如果数据庞大时还是比较消耗性能。
-
在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KwPtSwOd-1684386150219)(C:\Users\MrWang\AppData\Roaming\Typora\typora-user-images\image-20230306143656241.png)]