1、Redis简介

Redis是什么?(实质上是一个分布式缓存中间件,Nosql)

Redis(Remote Dictionary Server)----远程字典服务器,因为Redis是一个key-value存储系统。支持value的数据结构类型很多,包括字符串(String)、链表(List)、集合(Set)和哈希类型(Hash),还有BitMap、HyperLogLog、Geospatial。支持数据备份---master-slave支持事务、持久化、缓存淘汰,提供了主从模式、Redis Sentinel和Redis Cluster集群架构方案

注:红字语句后的黑字是其三个特点

BitMap :一般用于大数据量的二值性统计

HyperLogLog:其实HyperLog对于数据量庞大的日志去重统计

Geospatial:地理空间,其主要为地理位置相关的计算

Redis可以干什么?(功能)

  • 分布式缓存,挡在mysql数据库之前的一道屏障
  • 内存存储和持久化(RDB+AOF),redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
  • 高可用架构搭配
    单机 主从 哨兵 集群
  • 缓存穿透、击穿、雪崩
  • 分布式锁
  • 队列
  • Reids提供list和set操作,这使得Redis能作为一个很好的消息队列平台来使用。 我们常通过Reids的队列功能做购买限制。比如到节假日或者推广期间,进行一些活动,对用户购买

Redis为什么这么主流?这么快?优势?

性能极高 -Redis读写速度非常快---10w次/秒的计量单位

轻量级中间件---占用内存资源很小

Redis数据类型丰富,K-V存储结构

Redis支持数据的持久化,可以将内存中的数据保存在磁盘中吗,重启的时候可以再次加载使用---基于内存,对磁盘IO使用少,速度更快

Redis支持数据的备份,即M-S(主从模式)模式主从复制

Redis7的特性

RDB+AOF均可持久化,支持自动加载,主从切换不丢失数据

1.1、数据库应用发展历程

  1. 单机数据库时代:一个应用、一个数据库实例
  2. 缓存、水平切分时代
  3. 读写分离时代
  4. 分表分库束时代(集群)
  5. 关系型数据库:Oracle、 Mysql、 DB2、SQLServer
    关系型数据库无法满足当前高速发展的网路,所以出现非关系型数据库
  6. 非关系型数据库(Nosql):底层改变存储机制,不再采用关系数据模型,聚合数据结构存储(数据一旦没有关系,使得扩展性、读写性大大提高)
    redis/ mongoDb/ HBase

redistemplate set 更新key redis更新机制_数据库

2、Redis持化双雄RDB+AOF

Redis 有两种持久化方案,RDB (Redis DataBase)和 AOF (Append Only File)

2.1、RDB

RDB是Redis默认的持久化方案。在指定时间间隔内,执行指定次数的写操作,则会将内存中的数据写入磁盘中,即在指定目录下生成一个dump.rdb文件Redis重启就是加载dump.rdb文件恢复数据

RDB文件的核心配置--save<><>方案进行快照写入磁盘

save <seconds> <changes>

# save ""

save 900 1

save 300 10

save 60 10000

save <指定时间间隔> <执行指定次数更新操作>,满足条件就将内存中的数据同步到硬盘中。官方出厂配置默认是 900秒内有1个更改,300秒内有10个更改以及60秒内有10000个更改,则将内存中的数据快照写入磁盘

若不想使用RDB,可以把# save ""变成save ""

触发RDB快照
1 在指定的时间间隔内,执行指定次数的写操作
2 执行save(阻塞, 只管保存快照,其他的等待) 或者是bgsave (异步)命令
3 执行flushall 命令,清空数据库所有数据,意义不大。
4 执行shutdown 命令,保证服务器正常关闭且不丢失任何数据,意义...也不大

通过RDB文件恢复数据
将dump.rdb 文件拷贝到redis的安装目录的bin目录下,重启redis服务即可。在实际开发中,一般会考虑到物理机硬盘损坏情况,选择备份dump.rdb 。可以从下面的操作演示中可以体会到

RDB 的优缺点
优点:
1 适合大规模的数据恢复。
2 如果业务对数据完整性和一致性要求不高,RDB是很好的选择。

缺点:
1 数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。
2 备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件。
 

[root@itdragon bin]# vim redis.conf

save 900 1

save 120 5

save 60 10000

[root@itdragon bin]# ./redis-server redis.conf

[root@itdragon bin]# ./redis-cli -h 127.0.0.1 -p 6379

127.0.0.1:6379> keys *

(empty list or set)

127.0.0.1:6379> set key1 value1

OK

127.0.0.1:6379> set key2 value2

OK

127.0.0.1:6379> set key3 value3

OK

127.0.0.1:6379> set key4 value4

OK

127.0.0.1:6379> set key5 value5

OK

127.0.0.1:6379> set key6 value6

OK

127.0.0.1:6379> SHUTDOWN

not connected> QUIT

[root@itdragon bin]# cp dump.rdb dump_bk.rdb

[root@itdragon bin]# ./redis-server redis.conf

[root@itdragon bin]# ./redis-cli -h 127.0.0.1 -p 6379

127.0.0.1:6379> FLUSHALL

OK

127.0.0.1:6379> keys *

(empty list or set)

127.0.0.1:6379> SHUTDOWN

not connected> QUIT

[root@itdragon bin]# cp dump_bk.rdb dump.rdb

cp: overwrite `dump.rdb'? y

[root@itdragon bin]# ./redis-server redis.conf

[root@itdragon bin]# ./redis-cli -h 127.0.0.1 -p 6379

127.0.0.1:6379> keys *

1) "key5"

2) "key1"

3) "key3"

4) "key4"

5) "key6"

6) "key2"

第一步:vim 修改持久化配置时间,120秒内修改5次则持久化一次。
第二步:重启服务使配置生效。
第三步:分别set 5个key,过两分钟后,在bin的当前目录下会自动生产一个dump.rdb文件。(set key6 是为了验证shutdown有触发RDB快照的作用)
第四步:将当前的dump.rdb 备份一份(模拟线上工作)。
第五步:执行FLUSHALL命令清空数据库数据(模拟数据丢失)。
第六步:重启Redis服务,恢复数据。数据是空的????这是因为FLUSHALL也有触发RDB快照的功能。
第七步:将备份的 dump_bk.rdb 替换 dump.rdb 然后重新Redis。

注意点:SHUTDOWN 和 FLUSHALL 命令都会触发RDB快照,这是一个坑,请大家注意。

其他命令:

keys * 匹配数据库中所有 key
save 阻塞触发RDB快照,使其备份数据
FLUSHALL 清空整个 Redis 服务器的数据(几乎不用)
SHUTDOWN 关机走人(很少用)

2.2、AOF

AOF:Redis默认不开启,它是为了弥补RDB的不足(数据的不一致性),它采用日志的形式来记录每个写操作,并追加到文件中。Redis的重启会根据额日志文件的内容将写指令从前到后执行一次完后数据的恢复工作

redistemplate set 更新key redis更新机制_redis_02

always:同步持久化,每次发生数据变化会立刻写入到磁盘中。性能较差当数据完整性比较好(慢,安全)
everysec:出厂默认推荐,每秒异步记录一次(默认值)
no:不同步

重写触发机制

redistemplate set 更新key redis更新机制_redis_03

当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。一般都设置为3G,64M太小了

触发AOF快照
根据配置文件触发,可以是每次执行触发,可以是每秒触发,可以不同步。

根据AOF文件恢复数据
正常情况下,将appendonly.aof 文件拷贝到redis的安装目录的bin目录下,重启redis服务即可。但在实际开发中,可能因为某些原因导致appendonly.aof 文件格式异常,从而导致数据还原失败,可以通过命令redis-check-aof --fix appendonly.aof 进行修复 。从下面的操作演示中体会。

[root@itdragon bin]# vim appendonly.aof

appendonly yes

[root@itdragon bin]# ./redis-server redis.conf

[root@itdragon bin]# ./redis-cli -h 127.0.0.1 -p 6379

127.0.0.1:6379> keys *

(empty list or set)

127.0.0.1:6379> set keyAOf valueAof

OK

127.0.0.1:6379> FLUSHALL

OK

127.0.0.1:6379> SHUTDOWN

not connected> QUIT

[root@itdragon bin]# ./redis-server redis.conf

[root@itdragon bin]# ./redis-cli -h 127.0.0.1 -p 6379

127.0.0.1:6379> keys *

1) "keyAOf"

127.0.0.1:6379> SHUTDOWN

not connected> QUIT

[root@itdragon bin]# vim appendonly.aof

fjewofjwojfoewifjowejfwf

[root@itdragon bin]# ./redis-server redis.conf

[root@itdragon bin]# ./redis-cli -h 127.0.0.1 -p 6379

Could not connect to Redis at 127.0.0.1:6379: Connection refused

not connected> QUIT

[root@itdragon bin]# redis-check-aof --fix appendonly.aof

'x 3e: Expected prefix '*', got: '

AOF analyzed: size=92, ok_up_to=62, diff=30

This will shrink the AOF from 92 bytes, with 30 bytes, to 62 bytes

Continue? [y/N]: y

Successfully truncated AOF

[root@itdragon bin]# ./redis-server redis.conf

[root@itdragon bin]# ./redis-cli -h 127.0.0.1 -p 6379

127.0.0.1:6379> keys *

1) "keyAOf"

AOF的重写机制
前面也说到了,AOF的工作原理是将写操作追加到文件中,文件的冗余内容会越来越多。所以聪明的 Redis 新增了重写机制。当AOF文件的大小超过所设定的阈值时,Redis就会对AOF文件的内容压缩。

重写的原理:Redis 会fork出一条新进程,读取内存中的数据,并重新写到一个临时文件中。并没有读取旧文件。最后替换旧的aof文件。

触发机制:当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。这里的“一倍”和“64M” 可以通过配置文件修改。

AOF 的优缺点
优点:数据的完整性和一致性更高
缺点:因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢

总结
Redis 默认开启RDB持久化方式,在指定的时间间隔内,执行指定次数的写操作,则将内存中的数据写入到磁盘中。
RDB 持久化适合大规模的数据恢复但它的数据一致性和完整性较差。
Redis 需要手动开启AOF持久化方式,默认是每秒将写操作日志追加到AOF文件中。
AOF 的数据完整性比RDB高,但记录内容多了,会影响数据恢复的效率。
Redis 针对 AOF文件大的问题,提供重写的瘦身机制。
若只打算用Redis 做缓存,可以关闭持久化。
若打算使用Redis 的持久化。建议RDB和AOF都开启。其实RDB更适合做数据的备份,留一后手。AOF出问题了,还有RDB

3、Redis事务特性

3.1、Redis事务特性是什么?

Redis事务只具有一致性和隔离性

Redis 事务的本质是MULTIEXECWATCH等一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。总的来说:

redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

隔离性
Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的


没有隔离级别
Redis事务没有隔离级别的概念,批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。


单条命令原子性,事务整体无原子性
单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行

3.2、Redis事务的三个阶段

  • 事务开始 MULTI
  • 命令入队
  • 事务执行 EXEC

事务执行过程中,如果服务端收到有EXEC、DISCARD、WATCH、MULTI之外的请求,将会把请求放入队列中排队

WATCH
这是一个乐观锁,可以为 Redis 事务提供(CAS)行为。可以监控一个或多个键,如果在事务执行之前,被监视的key被其他命令修改(或删除),则事务被打断(类似乐观锁),之后的事务就不会执行,监控一直持续到EXEC命令


MULTI
用于开启一个事务(标记一个事务块的开始),它总是返回OK。MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。(发送执行的多条命令,但不执行,EXEC调用才真正执行)


EXEC
执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil。(一旦执行exec后,之前加的监控锁watch都会被取消掉)


DISCARD
通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出。


UNWATCH
可以取消watch对所有key的监控

Redis事务其他实现
基于Lua脚本,Redis可以保证脚本内的命令一次性、按顺序地执行,其同时也不提供事务运行错误的回滚,执行过程中如果部分命令运行错误,剩下的命令还是会继续运行完

4、Redis的缓存双写一致性

①. 什么是缓存双写一致
②. 先更新数据库,再更新缓存
③. 先删除缓存,再更新数据库
④. 先更新数据库,再删除缓存

4.1、什么是缓存双写一致性?

如果redis中有数据,需要和数据库中的值相同

如果redis中无数据,数据库中的值要是最新值

什么是同步直写?

小数据,某一条或一小戳数据要求立刻变更,前台询问,后台立刻同步数据

什么是异步缓写?

正常业务,马上更新mysql,可以在业务上允许1h后redis起效

出现异常后,不得不讲失败的动作重新修补,不得不借助Kafka或者RabbitMQ等消息中间件解耦重试后重写


4.2、先更新数据库,再更新缓存

5、内存策略,回收机制和过期Key处理

5.1、Redis内存我怎么知道满没?

引出redis最大默认内存

没有配置之前默认redis内存最大大小为0,在64位操作系统下不限制redis内存使用(推荐redis内存最大设置为物理内存的0.75)

redistemplate set 更新key redis更新机制_java_04

redistemplate set 更新key redis更新机制_java_05

redistemplate set 更新key redis更新机制_数据库_06

 配置最大内存

redistemplate set 更新key redis更新机制_Redis_07

怎么查看redis内存?

info memory

config get maxmemory


模拟打穿redis---内存溢出(直接可以修改文件里的配置最大值,也可以像下面一样命令执行)

redistemplate set 更新key redis更新机制_java_08

 

redistemplate set 更新key redis更新机制_数据_09

redistemplate set 更新key redis更新机制_Redis_10

5.2、过期策略+淘汰机制 

redistemplate set 更新key redis更新机制_redis_11

redistemplate set 更新key redis更新机制_数据_12

redistemplate set 更新key redis更新机制_java_13

redistemplate set 更新key redis更新机制_redis_14

redistemplate set 更新key redis更新机制_java_15

 

redistemplate set 更新key redis更新机制_redis_16

 CPU运行处理最大时间

redistemplate set 更新key redis更新机制_redis_17

redistemplate set 更新key redis更新机制_redis_18

 

redistemplate set 更新key redis更新机制_redis_19

惰性删除存在一个问题:如果一个Key很长时间无人访问,永远存在,那怎么删除? 引入周期删除

redistemplate set 更新key redis更新机制_Redis_20

redistemplate set 更新key redis更新机制_数据_21

 

redistemplate set 更新key redis更新机制_数据库_22

redistemplate set 更新key redis更新机制_redis_23

 Slow模式:低频高时长

 Fast模式:高频低时长

redistemplate set 更新key redis更新机制_数据库_24

redistemplate set 更新key redis更新机制_Redis_25

redistemplate set 更新key redis更新机制_数据库_26

redistemplate set 更新key redis更新机制_Redis_27

 

redistemplate set 更新key redis更新机制_java_28

两个维度:过期键中帅选+所有键中筛选

四个方面:LRU、LFU、random、ttl

redistemplate set 更新key redis更新机制_redis_29

 如何配置?config命令,直接去redis.conf

redistemplate set 更新key redis更新机制_数据_30

redistemplate set 更新key redis更新机制_数据_31