Redis
一、Nosql概述
1.1、为啥要用NoSQL
1、单机MySql的年代
APP —- DAL —- Mysql
当时的瓶颈:
- 数据量太大,一个机器放不下
- 数据的索引(B+ Tree),一个机器的内存放不下
- 访问量(读写混合),一个服务器受不了
2、Memcached(缓存)+MySQL+垂直拆分(读写分离)
网站80%都是读,服务器压力太大。于是有了缓存保证效率
发展过程:优化数据结构和索引 —-> 文件缓存(io) —-> Memcached(当时最热门的技术)
3、分库分表+水平拆分+MySQL集群
本质:数据库 读写
MyISAM:表锁,高并发会出现严重的锁问题
Innodb:行锁
慢慢开始用分库分表来解决压力,在那个年代推出了表分区
MySQL集群
4、如今最近的年代
技术爆炸
MySQL等关系型数据库就不够用了!数据量很大,变化很快
存取博客、图片、文件数据库表很大,效率变低
大数据的io压力下,数据库表几乎无法更改。
为什么要用NoSQL
用户的个人信息,社交网络,地理位置。用户自己产生的数据,用户日志等的爆发式增长
这时候NoSQL就能很好的解决问题。
1.2、什么是NoSQL
NoSQL= not only SQL(不仅仅是SQL)
泛指非关系型数据库。
很多的数据类型用户的个人信息,社交网络,地理位置。这些数据的存储不需要固定的格式。不需多余的操作就可以横向扩展
Map
NoSQL的特点
解耦!
方便扩展(数据之间没有关系)
大数据量高性能(Redis 一秒写八万,读取11万,NoSQL是缓存记录级,是一种细粒度的缓存,性能会比较高
数据类型是多样性的(不需要事先设计数据库,随取随用)
传统的RDBMS 和NoSQL ``` 传统的RDBMS
- 结构化组织
- SQL
- 数据和关系都存在单独的表中
- 数据操作,数据定义语言
- 严格的一致性
- 事务ACID ```
NOSQL
- 不仅仅是数据
- 没有固定的查询语言
- 键值对存储,列存储,文档存储,图形数据库(社交关系)
- 最终一致性
- CAP理论和BASE (异地多活)
- 高性能 、 高可用 、 高可扩
了解: 3V 和 3高
3V:
- 海量Velume
- 多样Variety
- 实时Velocity
3高:
- 高并发(集群)
- 高可用(节点故障,还能正常提高服务,降级提供服务)
- 高性能(查询快,c语言实现,内存数据库,单线程)
真正在公司的实践:NoSQL + RDBMS 一起使用
1.3、NoSQL四大分类
1.KV存储数据库
典型代表
BerkeleyDB、MemcacheDB、Redis
特征
可以通过key快速查询到value。一般来说,存储不需要考虑value的格式。
2.文档存储数据库
典型代表
MongoDB、CouchDB
特征
文档数据库一般用类似json的格式存储,存储的内容是文档型的。这样也就有机会对某些字段建立索引,实现关系数据库的某些功能。
3.列存储数据库
典型代表
Hbase、Cassandra、Hypertable
特征
按列存储数据,最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有着极大的IO优势。
4.图关系数据库
典型代表
Neo4J、FlockDB
特征
图形关系的最佳存储,使用传统关系数据库来解决的话性能低下,而且设计及其不方便。
区别
1.4、CAP原理
传统关系型数据库ACID原理
1.原子性(Atomicity)
一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有被执行过一样。
2.一致性(Consistency)
在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作
3.独立性(Isolation)
数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交、读已提交、可重复读和串行化。
4.持久性(Durability)
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
CAP原理
1.强一致性(Consistency)
在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
2.可用性(Availability)
每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据。在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。
3.分区容错性(Partition tolerance)
分区容错性其实是约束了分布式系统需要具有如下的特性:分布式在遇到任何网络分区故障的时候,仍然需要保证对外提供满足一致性和可用性的服务,除非整个网络均已瘫痪。也就是说,它容忍错误的出现,在发生错误的情况下可以继续进行操作。
CAP的三进二原则
1.CAP理论的核心
一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三大类。
- CA:单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
- CP:满足一致性,分区容忍性的系统,通常性能不是特别高。
- AP:满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
如何选择
CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。一致性和可用性的抉择可以参考思路
数据库事务一致性需求
很多web实时系统并不要求严格的数据库事务,对读一致性的要求很低,有些场合对写一致性要求并不高 。允许实现最终一致性。数据库的写实时性和读实时性的需求
对系统数据库来说,插入一条数据之后立刻查询,是肯定可以独处这条数据。但是对于大多数web应用来说,并不要求这么高的实时性,当我们发布一条消息后,过上几秒或是几十秒后被接受看到都是被允许的(如发微博/直播等,都是具有延迟的)对复杂的SQL查询,特别是多表关联查询的需求
任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的报表查询。我们把这些数据进行整合以k-v键值对的形式放到缓存里面,避免了数据库查询,这样子记得到我们所要的内容,又不给数据库增加负担,这样增强了数据的高可用。
1.5、BASE原理
BASE就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。他的思想就是通过让系统在某一时刻牺牲数据一致性的要求来换取系统整体的伸缩性和性能上的改观。(也就是说牺牲C 来实现AP,以BASE的理论来达成最终一致性)。
1.基本可用(Basically Available)
这里是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心功能或者当前最重要功能可用。对于用户来说,他们当前最关注的功能或者最常用的功能的可用性将会获得保证,但是其他功能会被削弱。
2.软状态(Soft state)
允许系统数据存在中间状态,但不会影响到系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步时存在延时。
3.最终一致(Eventually consistent)
要求系统数据副本最终能够一致,而不需要实时保证数据副本一致。最终一致性是弱一致性的一种特殊情况。最终一致性有5个变种:因果一致性,读己之所写(例如发微博的时候,自己可以马上看到,但是粉丝要过几秒钟),会话一致性,单调读一致性,单调写一致性。
二、Redis入门
2.1、概述
Redis是什么?
Redis (Remote Dictionary Server ) ,远程服务字典
是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库
Redis能干嘛
- 内存存储、持久化,内存是断电即失,所以持久化很重要(RDB、AOF)
- 效率高,可用于高速缓存
- 发布订阅系统
- 地图信息分析
- 计时器、计数器
- 。。。
特性
- 多样的数据类型
- 持久化
- 集群
- 事务
- 。。
需要用的东西
- 广告:狂神说公众号
- 官网 https://redis.io/
- 中文网 http://www.redis.cn/
下载地址
- Windows在github上下载(停更很久了)
- Redis都是在Linux上搭建的
2.2 、Redis安装
Window安装
- 下载安装包
- 。。。。
linux安装
1、下载安装包 redis-6.2.4.tar.gz
2、解压Redis的安装包 程序放在/opt文件夹下
3、进入解压后的文件,可以看到我们Redis的配置文件
4、基本的环境安装
yum gcc -c++(需要补充)
5、redis默认的安装路径 /user/local/bin
6、将Redis配置文件。复制到我们的目录下 usr/local/bin
7、Redis默认不是后台启动的,我们需要修改配置文件 vim redis.conf no —- 改为yes
8、启动Redis服务 usr/local/bin redis-server myconfig/redis.conf
Redis是单线程的
Redis是基于内存操作,CPU不是Redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽
既然可以使用单线程来实现,就使用单线程
Redis是C语言写的 官方提供的数据是10000+ 的QPS,完全不比同样使用key-value 的Memecahe差
Redis为什么单线程还这么快?
- 误区1:高性能的服务器一定是多线程的?
- 误区二:多线程(CPU上下文切换)一定会比单线程效率高 先去CPU>内存>硬盘
核心:Redis试讲所有的数据放入内存当中,所以说使用单线程去操作就是效率最高的,多线程(CPU切换:耗时的操作)对于内存系统来说,如果没有上下文切换,效率就是最高的
三、五大数据类型
Redis-key
在redis中无论什么数据类型,在数据库中都是以key-value形式保存,通过进行对Redis-key的操作,来完成对数据库中数据的操作。
exists key
:判断键是否存在del key
:删除键值对move key db
:将键值对移动到指定数据库expire key second
:设置键值对的过期时间type key
:查看value的数据类型
关于TTL命令
Redis的key,通过TTL命令返回key的过期时间,一般来说有3种:
当前key没有设置过期时间,所以会返回-1.
当前key有设置过期时间,而且key已经过期,所以会返回-2.
当前key有设置过期时间,且key还没有过期,故会返回key的正常剩余时间.
关于重命名RENAME和RENAMENX
RENAME key newkey修改 key 的名称
RENAMENX key newkey仅当 newkey 不存在时,将 key 改名为 newkey 。
String
String类似的使用场景:value除了是字符串还可以是数字,用途举例:
- 计数器
- 统计多单位的数量:uid:123666:follow 0
- 粉丝数
- 对象存储缓存
List(列表)
Redis列表是简单的字符串列表,按照插入顺序排序。
你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
小结
- list实际上是一个链表,before Node after , left, right 都可以插入值
- 如果key不存在,则创建新的链表
- 如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在
- 在两边插入或者改动值,效率最高!修改中间元素,效率相对较低
应用:
**消息排队!消息队列(Lpush Rpop),栈(Lpush Lpop)**
Set
Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
Hash
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。Set就是一种简化的Hash,只变动key,而value使用默认值填充。可以将一个Hash表作为一个对象进行存储,表中存放对象的信息。
Zset
不同的是每个元素都会关联一个double类型的分数(score)。redis正是通过分数来为集合中的成员进行从小到大的排序。
score相同:按字典顺序排序
有序集合的成员是唯一的,但分数(score)却可以重复。
四、三种特殊数据类型
4.1、Geospatial
4.2、Hyperloglog
4.3、BitMaps
五、事务
Redis单条命令是保证原子性的,但是事务不保证原子性
Redis事务本质:一组命令的集合!
————————- 队列 set set set 执行 —————————-
一个事务中每条命令都会被序列化,执行过程中按顺序执行,不允许其他命令进行干扰。
- 一次性
- 顺序性
- 排他性
Redis事务没有隔离级别的概念
- 所有的命令在事务中,并没有直接被执行,只有发起执行命令的时候才会被执行! Exec
Redis单条命令是保证原子性的,但是事务不保证原子性!
5.1、Redis事务操作过程
- 开启事务(
multi
) - 命令入队
- 执行事务(
exec
)
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)> get k2
QUEUED
127.0.0.1:6379(TX)> EXEC #执行事务
1) OK
2) OK
3) OK
4) "v2"
127.0.0.1:6379>
取消事务!
127.0.0.1:6379> MULTI #开启事务
OK
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>
5.2、事务错误
编译型异常(代码有错误,命令有错),事务中的所有的命令都不会被执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> error k1 # 这是一条语法错误命令
(error) ERR unknown command `error`, with args beginning with: `k1`, # 会报错但是不影响后续命令入队
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors. # 执行报错
127.0.0.1:6379> get k1
(nil) # 其他命令并没有被执行
运行时异常(1/0 ),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常
所以不保证事务原子性
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> INCR k1 # 这条命令逻辑错误(对字符串进行增量)
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) (error) ERR value is not an integer or out of range # 运行时报错
4) "v2" # 其他命令正常执行
# 虽然中间有一条命令报错了,但是后面的指令依旧正常执行成功了。
# 所以说Redis单条指令保证原子性,但是Redis事务不能保证原子性。
5.3、监控
六、Jedis
七、Springboot整合
八、自定义Redis工具类
九、Redis.conf
十、持久化—RDB
10.1、什么是RDB
在指定时间间隔后,将内存中的数据集快照写入数据库 ;在恢复时候,直接读取快照文件,进行数据的恢复 ;
默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。文件名可以在配置文件中进行自定义。
RDB保存的是dump.rdb
10.2、工作原理
在进行 RDB
的时候,redis
的主线程是不会做 io
操作的,主线程会 fork
一个子线程来完成该操作;
- Redis 调用forks。同时拥有父进程和子进程。
- 子进程将数据集写入到一个临时 RDB 文件中。
- 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益(因为是使用子进程进行写操作,而父进程依然可以接收来自客户端的请求。)
10.3、触发机制
- save的规则满足的情况下,会自动触发rdb原则
- 执行flushall命令,也会触发我们的rdb原则
- 退出redis,也会自动产生rdb文件
save
使用 save
命令,会立刻对当前内存中的数据进行持久化 ,但是会阻塞,也就是不接受其他操作了;
由于
save
命令是同步命令,会占用Redis的主进程。若Redis数据非常多时,save
命令执行速度会非常慢,阻塞所有客户端的请求。
flushall命令
flushall
命令也会触发持久化 ;
触发持久化规则
满足配置条件中的触发条件 ;
可以通过配置文件对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动进行数据集保存操作。
bgsave
bgsave
是异步进行,进行持久化的时候,redis
还可以将继续响应客户端请求
10.4、优缺点
优点:
- 适合大规模的数据恢复
- 对数据的完整性要求不高
缺点:
- 需要一定的时间间隔进行操作,如果redis意外宕机了,这个最后一次修改的数据就没有了。
- fork进程的时候,会占用一定的内容空间。
十一、持久化AOF
11.1、什么是AOF
Append Only File
以日志的形式来记录每个写的操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
快照功能(RDB)并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、以及未保存到快照中的那些数据。 从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化。
如果要使用AOF,需要修改配置文件:
appendonly no yes则表示启用AOF
默认是不开启的,我们需要手动配置,然后重启redis,就可以生效了!
如果这个aof文件有错位,这时候redis是启动不起来的,我需要修改这个aof文件
redis给我们提供了一个工具redis-check-aof —fix
优点
- 每一次修改都会同步,文件的完整性会更加好
- 每秒同步一次,可能会丢失一秒的数据
- 从不同步,效率最高
缺点
- 相对于数据文件来说,aof远远大于rdb,修复速度比rdb慢!
- aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化
十二、RDB和AOF的选择
12.1、对比
12.2、如何选择哪种持久化方式
一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。
十三、Redis发布与订阅
命令
示例
原理
缺点
应用
十四、Redis主从复制
概念
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower), 数据的复制是单向的!只能由主节点复制到从节点(主节点以写为主、从节点以读为主)。
默认情况下,每台Redis服务器都是主节点,一个主节点可以有0个或者多个从节点,但每个从节点只能由一个主节点。
作用
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余的方式。
- 故障恢复:当主节点故障时,从节点可以暂时替代主节点提供服务,是一种服务冗余的方式
- 负载均衡:在主从复制的基础上,配合读写分离,由主节点进行写操作,从节点进行读操作,分担服务器的负载;尤其是在多读少写的场景下,通过多个从节点分担负载,提高并发量。
- 高可用基石:主从复制还是哨兵和集群能够实施的基础。
为什么使用集群
- 单台服务器难以负载大量的请求
- 单台服务器故障率高,系统崩坏概率大
- 单台服务器内存容量有限。
环境配置
我们在讲解配置文件的时候,注意到有一个replication
模块 (见Redis.conf中第8条)
查看当前库的信息:info replication
127.0.0.1:6379> info replication
# Replication
role:master # 角色
connected_slaves:0 # 从机数量
master_replid:3b54deef5b7b7b7f7dd8acefa23be48879b4fcff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
既然需要启动多个服务,就需要多个配置文件。每个配置文件对应修改以下信息:
- 端口号
- pid文件名
- 日志文件名
- rdb文件名
启动单机多服务集群:
一主二从配置
==默认情况下,每台Redis服务器都是主节点;==我们一般情况下只用配置从机就好了!
认老大!一主(79)二从(80,81)
使用SLAVEOF host port
就可以为从机配置主机了。
然后主机上也能看到从机的状态:
我们这里是使用命令搭建,是暂时的,==真实开发中应该在从机的配置文件中进行配置,==这样的话是永久的。
使用规则
- 从机只能读,不能写,主机可读可写但是多用于写。 ```bash 127.0.0.1:6381> set name sakura # 从机6381写入失败 (error) READONLY You can’t write against a read only replica.
127.0.0.1:6380> set name sakura # 从机6380写入失败 (error) READONLY You can’t write against a read only replica.
127.0.0.1:6379> set name sakura OK 127.0.0.1:6379> get name “sakura”
2.
当主机断电宕机后,默认情况下从机的角色不会发生变化 ,集群中只是失去了写操作,当主机恢复以后,又会连接上从机恢复原状。
3.
当从机断电宕机后,若不是使用配置文件配置的从机,再次启动后作为主机是无法获取之前主机的数据的,若此时重新配置称为从机,又可以获取到主机的所有数据。这里就要提到一个同步原理。
4.
第二条中提到,默认情况下,主机故障后,不会出现新的主机,有两种方式可以产生新的主机:
- 从机手动执行命令slaveof no one,这样执行以后从机会独立出来成为一个主机
- 使用哨兵模式(自动选举)
> 如果没有老大了,这个时候能不能选择出来一个老大呢?手动!
如果主机断开了连接,我们可以使用`SLAVEOF no one`让自己变成主机!其他的节点就可以手动连接到最新的主节点(手动)!如果这个时候老大修复了,那么久重新连接!
<a name="94816f45"></a>
# 十五、哨兵模式
**主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。**这不是一种推荐的方式,更多时候,我们优先考虑**哨兵模式**。
哨兵的作用:
-
通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
-
当哨兵监测到master宕机,会自动将slave切换成master,然后通过**发布订阅模式**通知其他的从服务器,修改配置文件,让它们切换主机。
<br />哨兵模式优缺点
优点:
1. 哨兵集群,基于主从复制模式,所有主从复制的优点,它都有
2. 主从可以切换,故障可以转移,系统的可用性更好哨兵模式是主从模式的升级,手动到自动,更加健壮
缺点:
1. Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦
2. 实现哨兵模式的配置其实是很麻烦的,里面有很多配置项
<a name="1b8920bd"></a>
# 十六、缓存穿透与雪崩
<a name="d9526f37"></a>
## 缓存穿透(查不到)
> 概念
在默认情况下,用户请求数据时,会先在缓存(Redis)中查找,若没找到即缓存未命中,再在数据库中进行查找,数量少可能问题不大,可是一旦大量的请求数据(例如秒杀场景)缓存都没有命中的话,就会全部转移到数据库上,造成数据库极大的压力,就有可能导致数据库崩溃。网络安全中也有人恶意使用这种手段进行攻击被称为洪水攻击。
> 解决方案
**布隆过滤器**
对所有可能查询的参数以Hash的形式存储,以便快速确定是否存在这个值,在控制层先进行拦截校验,校验不通过直接打回,减轻了存储系统的压力
**缓存空对象**
一次请求若在缓存和数据库中都没找到,就在缓存中放一个空对象用于处理后续这个请求。
这样做有一个缺陷:存储空对象也需要空间,大量的空对象会耗费一定的空间,存储效率并不高。解决这个缺陷的方式就是设置较短过期时间
即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
<a name="1f3d8099"></a>
## 缓存击穿(量太大,缓存过期)
> 概念
相较于缓存穿透,缓存击穿的目的性更强,一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。这就是缓存被击穿,只是针对其中某个key的缓存不可用而导致击穿,但是其他的key依然可以使用缓存响应。
比如热搜排行上,一个热点新闻被同时大量访问就可能导致缓存击穿。
> 解决方案
-
**设置热点数据永不过期**
这样就不会出现热点数据过期的情况,但是当Redis内存空间满的时候也会清理部分数据,而且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间。 ```
- 加互斥锁(分布式锁) Redis的分布式锁 java3Y公众号文章 2021.6.17
在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。这样对锁的要求就十分高。
缓存雪崩
概念
大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
解决方案
redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群限流降级(SpringCloud中讲过)=-
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。