一、Redis简介
一个神奇的网站
- 海量用户
- 高并发
- 性能瓶颈:磁盘IO性能低下
- 扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群
- 降低磁盘IO次数,越低越好 —— 内存存储
- 去除数据间关系,越简单越好 —— 不存储关系,仅存储数据
1.1 NoSQL
1.2 NOSQL和关系型数据库比较
1.3 主流的NOSQL产品
数据库排名 : http://db-engines.com/en/ranking
1.4 什么是Redis
Redis 是一种基于内存的数据库对数据的读写操作都是在内存中完成,因此读写速度非常快,常用于缓存,消息队列、分布式锁等场景。
Redis 提供了多种数据类型来支持不同的业务场景,比如 String(字符串)、Hash(哈希)、 List(列表)Set(集合)、Zset(有序集合)、Bitmaps (位图) 、HyperLogLog (基数统计) 、GEO (地理信息)Stream (流),并且对数据类型的操作都是原子性的,因为执行命令由单线程负责的,不存在并发竞争的问题。
除此之外,Redis 还支持事务 、持久化、Lua 脚本、多种集群方案 (主从复制模式、哨兵模式、切片机群模式)、发布/订阅模式,内存淘汰机制、过期删除机制等等。
Redis官方简介
Redis 是一个开源 (BSD 许可)内存数据结构存储用作数据库、缓存、消息代理和流引警。Redis 提供数据结构,例如 字符串、散列、列表集合、带范围查询的排序集合、位图、超日志、地理空间索引和流。Redis 内置了复制、Lua 脚本、LRU 驱逐、事务和不同级别的磁盘持久性,并通过以下方式提供高可用性Redis Sentinel和Redis Cluster的自动分区。
您可以对这些类型运行原子操作例如附加到字符串; 增加哈希值;将元素推入列表,计算集交、并 、差;或获取排序集中排名最高的成员。
为了达到最佳性能,Redis 使用 内存中的数据集。根据您的用例,Redis 可以通过定期将数据集转储到磁盘 或将每个命令附加到基于磁盘的日志来持久化您的数据。如果您只需要一个功能丰富的网络内存缓存,您也可以禁用持久性。
Redis 支持异步复制,具有快速非阻塞同步和自动重新连接以及网络拆分上的部分重新同步
二、Redis 的下载与安装
2.1 Redis 的下载
- Redis 高级开始使用
- 以4.0 版本作为主版本
- Redis 入门使用
- 以 3.2 版本作为主版本
- 下载地址:https://github.com/MSOpenTech/redis/tags
2.2 安装 Redis
- redis-server.exe 服务器启动命令
- redis-cli.exe 命令行客户端
- redis.windows.conf redis核心配置文件
- redis-benchmark.exe 性能测试工具
- redis-check-aof.exe AOF文件修复工具
- redis-check-dump.exe RDB文件检查工具(快照持久化文件)
2.3 启动 Redis
三、Redis基本操作
- 功能性命令
- 清除屏幕信息
- 帮助信息查阅
- 退出指令
- 功能:设置 key,value 数据
- 命令: set key value
- 功能:根据 key 查询对应的 value,如果不存在,返回空(nil)
- 命令: get key
- 功能:清除屏幕中的信息
- 命令:clear
- 功能:退出客户端
- 命令:quit exit 按钮
- 功能:获取命令帮助文档,获取组中所有命令信息名称
- 命令: help 命令名称 help @组名
四.Redis 数据类型(5种常用)
- redis 自身是一个 Map,其中所有的数据都是采用 key : value 的形式存储
- 数据类型指的是存储的数据的类型,也就是 value 部分的类型,key 部分永远都是字符串
- 在一个项目中,key最好使用统一的命名模式
- key区分大小写
- key不要太长,尽量不要超过1024字节。不仅消耗内存,也会降低查找的效率
- key不要太短,太短可读性会降低
4.1 String
- 存储的数据:单个数据,最简单的数据存储类型,也是最常用的数据存储类型
- 存储数据的格式:一个存储空间保存一个数据
- 存储内容:通常使用字符串,如果字符串以整数的形式展示,可以作为数字操作使用
4.1.1 String类型的内部实现
String 类型的底层的数据结构实现主要是 SDS(简单动态字符串)。 SDS 和我们认识的 C 字符串不太一样,之所以没有使用 C 语言的字符串表示,因为 SDS 相比于 C的原生字符串:
1、SDS 不仅可以保存文本数据,还可以保存二进制数据。因为 SDS 使用len 属性的值而不是空字符来判断字符串是否结束,并且SDS的所有API都会以处理二进制的方式来处理SDS存放在buf 数组的数据。所以SDS不光能存放文本数据,而且能保存图片、音频、视频、压缩文件这样的二进制数据;
2、SDS 获取字符串长度的时间复杂度是 O(1)。因为 C语言的字符串并不记录自身长度,所以获取长度的复杂度为 O(n);而SDS结构里用len 属性记录了字符串长度,所以复杂度为 O(1);
3、Redis 的 SDS API 是安全的,拼接字符串不会造成缓冲区溢出。因为 SDS 在拼接字符串之前会检查SDS空间是否满足要求,如果空间不够会自动扩容,所以不会导致缓冲区溢出的问题。
==========================字符串类型 string==========================
##添加/修改数据
set key value
##获取数据
get key
##删除数据
del key
##添加/修改多个数据
mset key1 value1 key2 value2 …(m代表Multiple)
##获取多个数据
mget key1 key2 …
##获取数据字符个数(字符串长度)
strlen key
##追加信息到原始信息后部(如果原始信息存在就追加,否则新建)
append key value
##按照范围获取
GETRANGE key 开始下标 结束下标
##替换
SETRANGE key 位置
##先get然后在set
getset key value
4.2 Hash
- 新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
- 需要的存储结构:一个存储空间保存多个键值对数据
- hash类型:底层使用哈希表结构实现数据存储
- 如果fifield数量较少,存储结构优化为类数组结构
- 如果fifield数量较多,存储结构使用HashMap结构
4.2.1 Hash类型内部实现
Hash 类型的底层数据结构是由压缩列表或哈希表实现的:
1、如果哈希类型元素个数小于512个(默认值,可由 hash-max-ziplist-entries 配置),所有值小于64字节(默认值,可由hash-max-ziplist-value 配置)的话,Redis 会使用压缩列表作为 Hash 类型的底层数据结构;
2、如果哈希类型元素不满足上面条件,Redis 会使用哈希表作为 Hash 类型的底层数据结构。
在 Redis 7.0 中,压缩列表数据结构已经废弃了,交由 listpack 数据结构来实现了。
==========================hash哈希类型==========================
添加/修改数据
hset key field value
添加,但是有则不添加,无则添加
hsetnx key field value
获取数据
hget key field
hgetall key
删除数据
hdel key field1 [field2]
添加/修改多个数据
hmset key field1 value1 field2 value2 …
获取多个数据
hmget key field1 field2 …
获取哈希表中字段的数量
hlen key
获取哈希表中是否存在指定的字段
hexists key field
获取哈希表中所有的字段名或字段值
hkeys key
hvals key
设置指定字段的数值数据增加指定范围的值
hincrby key field increment
hincrbyfloat key field increment
hash 类型数据操作的注意事项
1.hash类型下的value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取
到,对应的值为(nil)
2.每个 hash 可以存储 2^32^-1个键值对
3.hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了
存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用
4.hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数
据访问瓶颈
4.3 List
- 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
- 需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
- list类型:保存多个数据,底层使用双向链表存储结构实现
4.3.1 List类型内部实现
List 类型的底层数据结构是由双向链表或压缩列表实现的:
1、如果列表的元素个数小于 512个(默认值,可由 list-max-ziplist-entries 配置),列表每个素的值都小于 64 字节(默认值,可由 list-max-ziplist-value 配置),Redis 会使用压缩列表作为 List 类型的底层数据结构;
2、如果列表的元素不满足上面的条件,Redis 会使用双向链表作为 List 类型的底层数据结构;
但是在 Redis 3.2 版本之后,List 数据类型底层数据结构就只由 quicklist 实现了,替代了双向链表和压缩列表。
==========================list==========================
添加/修改数据
lpush key value1 [value2] ……
rpush key value1 [value2] ……
获取数据
lrange key start stop
lindex key index
llen key
获取并移除数据
lpop key
rpop key
通过下标截取指定的长度,这个list已经被改变了,只剩下截取的元素
ltrim key start end
lset将列表中指定下标的值替换为另外一个值,更新操作
lset key 下标 新数据 # 如果不存在列表我们去更新就会报错
将某个具体的value插入到列中的某个元素的前面或者后面!
LINSERT mylist before "world" "other"
LINSERT mylist after "world" "other"
规定时间内获取并移除数据 b代表block阻塞
blpop key1 [key2] timeout
brpop key1 [key2] timeout
eg:lpush list1 a b
lpop list1 ===a
lpop list1 ===b
lpop list1 ===nil 立刻响应为空,但如果是blpop会阻塞,也就是会等,现在没数据不意味着未来
没有
blpop list1 30 获取数据,有则返回,没有则等待30秒
可以打开2个客户端演示
4.3.2 list 类型数据操作注意事项
1 .list 中保存的数据都是 string 类型的,数据总容量是有限的,最多 2^32^-1 个元素 (4294967295);2 .list 具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作;3 . 获取全部数据操作结束索引设置为 -1;4 .list 可以对数据进行分页操作,通常第一页的信息来自于 list ,第 2 页及更多的信息通过数据库的形式加载。
4.4 Set
- 新的存储需求:存储大量的数据,在查询方面提供更高的效率
- 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
- set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
4.4.1 Set内部实现
Set 类型的底层数据结构是由哈希表或整数集合实现的:
1、如果集合中的元素都是整数且元素个数小于 512 (默认值,set-maxintset-entries配置)个,Redis会使用整数集合作为 Set 类型的底层数据结构;
2、如果集合中的元素不满足上面条件,则 Redis 使用哈希表作为 Set 类型的底层数据结构。
==========================Set==========================
添加数据
sadd key member1 [member2]
获取全部数据
smembers key
删除数据
srem key member1 [member2]
获取集合数据总量
scard key
判断集合中是否包含指定数据
sismember key member
求两个集合的交、并、差集
sinter key1 [key2]
sunion key1 [key2]
sdiff key1 [key2]
求两个集合的交、并、差集并存储到指定集合中
sinterstore destination key1 [key2]
sunionstore destination key1 [key2]
sdiffstore destination key1 [key2]
将指定数据从原始集合中移动到目标集合中
smove source destination member
set 类型数据操作的注意事项
1.set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份
2.set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
4.5 sorted_set
- 新的存储需求:数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式
- 需要的存储结构:新的存储模型,可以保存可排序的数据
- sorted_set类型:在set的存储结构基础上添加可排序字段
4.5.1 sorted_set类型内部实现
Zset 类型的底层数据结构是由压缩列表或跳表实现的:
1、如果有序集合的元素个数小于 128 个,并且每个元素的值小于 64 字节时,Redis 会使用压缩列表作为 Zset 类型的底层数据结构;
2、如果有序集合的元素不满足上面的条件,Redis 会使用跳表作为 Zset 类型的底层数据结构。
添加数据
zadd key score1 member1 [score2 member2]
获取全部数据
zrange key start(开始索引) stop(结束索引) [WITHSCORES] #[WITHSCORES]可以除了数据还
显示分值
zrevrange key start stop [WITHSCORES] 反转
删除数据
zrem key member [member ...]
获取集合数据总量
zcard key
五.Jedis
<!--导入jedis的包-->
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
2、编码测试
import redis.clients.jedis.Jedis;
public class TestPing {
public static void main(String[] args) {
// 1、 new Jedis 对象即可
Jedis jedis = new Jedis("127.0.0.1",6379);
// jedis 所有的命令就是我们之前学习的所有指令!所以之前的指令学习很重要!
System.out.println(jedis.ping());
}
}
六、事务
6.1 概念
6.2 特点
命令 | 描述 |
---|---|
multi | 标记一个事务的开始 |
exec | 执行所有事务块内的命令 |
discard | 取消事务,放弃执行事务块内的所有命令 |
watch key [key] | 监视一个或多个类,如果在事务执行之前这个或这些key 被其他命令所改动,那么事务将被打断。类似乐观锁 |
unwatch | 取消watch命令对所有 key 的监视。 |
6.3 为什么要添加事务
银行存款 10000 元 , 三个人同时使用一个账户购买商品,发现存款变负数一个请求想给金额减 8000一个请求想给金额减 5000一个请求想给金额减 1000
七、Spring-data-redis
1.加入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.application.properties中加入redis相关配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.0.24
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=1000
3.具体代码了解
spring data redis中封装了两个模板类,帮助我们实现redis的crud
RedisTemplate key value泛型都是object
StringRedisTemplate key value泛型都是string
注意:
1.两者数据各自存,各自取,数据不互通。
RedisTemplate不能取StringRedisTemplate存入的数据
序列化策略
9.redis的配置
StringRedisTemplate不能取RedisTemplate存入的数据
2.序列化策略不同:
RedisTemplate采用JDK的序列化策略(JdkSerializationRedisSerializer)保存的key
和value 都是采用此策略序列化保存的
存储时,先将数据序列化为字节数组,再存入Redis数据库。查看Redis会发现,是字节数组的形
式类似乱 码读取时,会将数据当做字节数组转化为我们需要的数据,以用来存储对象,但是要实现
Serializable接 口
StringRedisTemplate采用String的序列化策略(StringRedisSerializer)保存的key和
value都 是采用此策略序列化保存的当存入对象时,会报错:can not cast into String
存储和读取,都为可读的数据
3.两者的关系是StringRedisTemplate继承RedisTemplate
4.使用场景:
当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那
么你就使 用StringRedisTemplate即可。
但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取
出一个对 象,那么使用RedisTemplate是更好的选择。
五大数据类型
* redisTemplate.opsForValue();//操作字符串
* redisTemplate.opsForList();//操作List
* redisTemplate.opsForSet();//操作Set
* redisTemplate.opsForZSet();//操作ZSet
* redisTemplate.opsForHash();//操作Hash
序列化策略
改变序列化策略默认序列化方式存储到 redis 的数据人工不可读不同策略序列化的过程有性能高低的spring-data-redis 提供如下几种序列化策略GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化Jackson2JsonRedisSerializer: 跟 JacksonJsonRedisSerializer 实际上是一样的JacksonJsonRedisSerializer: 序列化 object 对象为 json 字符串JdkSerializationRedisSerializer: 序列化 java 对象StringRedisSerializer: 简单的字符串序列化
八、Redis持久化
8.1 RDB方式
概念 :
8.1.1 RDB手动
说明 | 经验 | |
dbfifilename dump.rdb
|
设置本地数据库文件名,默认值为
dump.rdb
|
通常设置为
dump-
端口号
.rdb
|
dir
|
设置存储
.rdb
文件的路径
|
通常设置成存储空间较大的目录中,目录名称
data
|
rdbcompression yes
|
设置存储至本地数据库时是否压缩数据,默认为
yes
,采用
LZF
算法 压缩
|
通常默认为开启状态,如果设置为
no
,可以节省
CPU
运行时间,但会使存储的文件变大(巨
大)
|
rdbchecksum yes
|
设置是否进行
CRC64
算法
RDB
文件格式校验, 该校验过程在写文件和读文件过程均进行
|
通常默认为开启状态,如果设置为
no
,可以节约读写性过程约
10%
时间消耗,但是存储一定的数
据损坏风险
|
8.1.2 RDB自动
配置 :save second changes
作用 : 满足限定时间范围内key的变化数量达到指定数量即进行持久化
参数 :
second:监控时间范围
changes:监控key的变化量
位置 : 在conf文件中进行配置
注意:
1、save配置要根据实际业务情况进行设置,频度过高或过低都会出现性能问题,结果可能是灾难性的
2、save配置中对于second与changes设置通常具有互补对应关系,尽量不要设置成包含性关系
3、save配置启动后执行的是bgsave操作。
RDB优点
RDB是一个紧凑压缩的二进制文件,存储效率较高
RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
RDB恢复数据的速度要比AOF快很多
RDB节省磁盘空间
RDB缺点
Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能
RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象
8.2 AOF方式
AOF(append only fifile)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的;与RDB相比可以简单描述为改记录数据为记录数据产生的过程AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式。
8.2.1 AOF执行过程
客户端的请求写命令会被append追加到AOF缓冲区内;
AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
8.2.2 AOF写数据三种策略(appendfsync)
always(每次):每次写入操作均同步到AOF文件中,数据零误差,性能较低
everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高 在系统突然宕机的情况下丢失1秒内的数据
no(系统控制):由操作系统控制每次同步到AOF文件的周期,整体过程不可控。
8.2.3 AOF相关配置
配置 | 作用 |
appendonly yes|no
|
是否开启
AOF
持久化功能,默认为不开启状态
|
appendfsync always|everysec|no
|
AOF
写数据策略
|
appendfifilename fifilename
|
AOF
持久化文件名,默认文件名未
appendonly.aof
,建议配置为
appendonly-
端口号
.aof
|
dir
|
AOF
持久化文件保存路径,与
RDB
持久化文件保持一致即可
|
8.2.4 AOF重写
8.2.5 AOF重写作用
- 降低磁盘占用量,提高磁盘利用率
- 提高持久化效率,降低持久化写时间,提高IO性能
- 降低数据恢复用时,提高数据恢复效率
8.2.6 AOF 重写规则
- 进程内已超时的数据不再写入文件
- 忽略无效指令,重写时使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令
- 如del key1、 hdel key2、srem key3、set key4 111、set key4 222等对同一数据的多条写命令合并为一条命令如lpush list1 a、lpush list1 b、 lpush list1 c 可以转化为:lpush list1 a b c。
- 为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素 AOF和RDB同时开启,系统默认取AOF的数据(数据不会存在丢失)
8.2.7 AOF 重写方式
九、Redis删除策略
9.1 过期数据
- XX :具有时效性的数据
- -1 :永久有效的数据
- -2 :已经过期的数据或被删除的数据或未定义的数据
9.2 数据删除策略
9.2.1 定时删除
- 创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
- 优点:节约内存,到时就删除,快速释放掉不必要的内存占用
- 缺点:CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指 令吞吐量
- 总结:用处理器性能换取存储空间(拿时间换空间)
9.2.2 惰性删除
- 数据到达过期时间,不做处理。等下次访问该数据时
- 如果未过期,返回数据
- 发现已过期,删除,返回不存在
- 优点:节约CPU性能,发现必须删除的时候才删除
- 缺点:内存压力很大,出现长期占用内存的数据
- 总结:用存储空间换取处理器性能(拿空间换时间)
9.2.3 定期删除
- Redis启动服务器初始化时,读取配置server.hz的值,默认为10
- 每秒钟执行server.hz次serverCron()中的方法---databasesCron()---activeExpireCycle()
- activeExpireCycle()对每个expires[*]逐一进行检测,每次执行250ms/server.hz
- 对某个expires[*]检测时,随机挑选W个key检测
- 如果key超时,删除key
- 如果一轮中删除的key的数量>W * 25%,循环该过程
- 如果一轮中删除的key的数量≤W * 25%,检查下一个expires[*],0-15循环
- W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值
-
参数 current_db 用于记录 activeExpireCycle() 进入哪个 expires[*] 执行
-
如果 activeExpireCycle() 执行时间到期,下次从 current_db 继续向下执行
- 优点1:CPU性能占用设置有峰值,检测频度可自定义设置
- 优点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
- 总结:周期性抽查存储空间 (随机抽查,重点抽查)
9.2.4 删除策略对比
9.3 逐出算法
- Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法。
- 注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。
抛出异常:(error) OOM command not allowed when used memory >'maxmemory'
影响数据逐出的相关配置
- maxmemory最大可使用内存
- maxmemory-samples每次选取待删除数据的个数
- maxmemory-policy删除策略
策略名称 | 作用 |
volatile-lru
|
挑选最近最少使用的数据淘汰
|
volatile-lfu
|
挑选最近使用次数最少的数据淘汰
|
volatile-ttl
|
挑选将要过期的数据淘汰
|
volatile-random
|
任意选择数据淘汰
|
策略名称 | 作用 |
allkeys-lru
|
挑选最近最少使用的数据淘汰
|
allkeys-lfu
|
挑选最近使用次数最少的数据淘汰
|
allkeys-random
|
任意选择数据淘汰
|
策略名称 | 作用 |
no-enviction
(驱逐)
|
禁止驱逐数据(redis4.0中默认策略),会引发错误
OOM
(
Out Of Memory)达到最大内存后的,对被挑选出来的数据进行删除的策略
|
十、企业级解决方案
10.1 缓存预热
- 请求数量较高;
- 主从之间数据吞吐量较大,数据同步操作频度较高,因为刚刚启动时,缓存中没有任何数据;
解决方案:
准备工作:
- 日常例行统计数据访问记录,统计访问频度较高的热点数据;
- 将统计结果中的数据分类,根据级别,redis优先加载级别较高的热点数据;
实施:
- 使用脚本程序固定触发数据预热过程;
- 如果条件允许,使用了CDN(内容分发网络),效果会更好;
CDN 的全称是 Content Delivery Network ,即内容分发网络。其基本思路是尽可能避开 互联网 上有可能影响数据传输速度和稳定性的 瓶颈 和环节,使内容传输得更快、更稳定。通过在网络各处放置 节点服务器 所构成的在现有的互联网基础之上的一层智能 虚拟网络 , CDN 系统能够实时地根据 网络流量 和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet 网络拥挤 的状况,提高用户访问网站的响应速度
总结
10.2 缓存雪崩
- 给不同的Key的TTL添加随机值
- 利用Redis集群提高服务的可用性
- 给缓存业务添加降级限流策略
- 给业务添加多级缓存
10.3 缓存击穿
- 互斥锁
- 逻辑过期

解决方案一、使用锁来解决

解决方案二、逻辑过期方案
这种方案巧妙在于,异步的构建缓存,缺点在于在构建完缓存之前,返回的都是脏数据。
10.4 缓存穿透
- 缓存空对象
- 优点:实现简单,维护方便
- 缺点:有额外的内存消耗,可能造成短期的不一致
- 布隆过滤
- 优点:内存占用较少,没有多余的key
- 缺点:实现复杂,存在误判的可能

实战举例