一、什么是Redis
Redis是一种开源的内存数据库,它支持键值存储,常被用作数据缓存、消息代理和队列等。它以高性能和支持多种数据结构而闻名,如字符串、哈希、列表、集合和有序集合。Redis也支持持久化,可以将数据存储在磁盘上,以确保数据不会因服务器重启而丢失。
二、Redis的优点
读取速度快,因为数据存在内存中,所以数据获取快;
支持多种数据结构,包括字符串、列表、集合、有序集合、哈希等;
支持事务,且操作遵守原子性,即对数据的操作要么都执行,要么都不支持;
还拥有其他丰富的功能,队列、主从复制、集群、数据持久化等功能。
三、为什么Redis的速度比较快
1.Redis是由C语言实现的,效率比较高
2.Redis存储在内容中,针对内存操作,使用效率高
3.Redis是基于非阻塞的IO复用模型
4.采用单线程的模型,避免频繁的上下文切换
5.提供了丰富的数据结构,提高使用效率
四、Redis的持久化方式?有何区别?
Redis的持久化方式为RDB和AOF两种:
RDB 持久化方式
使用数据集快照的方式记录Redis数据库的所有键值对,将数据写入临时文件,持久化完成后,用临时文件替换原文件,达到数据恢复的效果。
优点:
只有一个文件 dump.rdb ,方便持久化。
容灾性好,一个文件可以保存到安全的磁盘。
性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 Redis 的高性能)
相对于数据集大时,比 AOF 的启动效率更高。
缺点:
数据安全性低。 RDB 是间隔一段时间进行持久化,如果持久化之间 Redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
AOF 持久化方式
是指所有的命令行记录以 Redis 命令请求协议的格式完全持久化存储,保存为 AOF 文件
优点
数据安全, AOF 持久化可以配置 appendfsync 属性,有 always,每进行一次命令操作就记录到 AOF 文件中一次。
通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。
AOF 机制的 rewrite 模式。 AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall )
缺点
AOF 文件比 RDB 文件大,且恢复速度慢。
数据集大的时候,比 RDB 启动效率低
五、Redis支持的数据类型
Redis的五种基本数据类型
String(字符串):SDS
底层的数据结构为简单动态字符串(SDS) ,可以保存文本和二进制数据
List(列表):LinkedList/ZipList/QuickList
底层实现为一个双向链表 ,支持反向查找和遍历
Hash(散列):Dict、ZipList
底层实现为数组 + 链表
Set 类型是一种无序集合,集合中的元素没有先后顺序但都唯一
底层实现为数组 + 链表
Zset(有序集合):ZipList、SkipList
在Set基础上增加了一个权重参数score,使得元素能够按照score进行有序排列。"底层使用跳表实现"
Redis的三种特殊类型
Bitmap(位图)
Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身
HyperLogLog(基数统计)
HyperLogLog 是一种有名的基数计数概率算法 ,基于 LogLog Counting(LLC)优化改进得来,并不是 Redis 特有的,Redis 只是实现了这个算法并提供了一些开箱即用的 API。
Geospatial (地理位置)
Geospatial index(地理空间索引,简称 GEO) 主要用于存储地理位置信息,基于 Sorted Set 实现。
六、Redis的过期key删除策略
惰性删除 :只会在取出/查询 key 的时候才对数据进行过期检查。这种方式对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。
定期删除 :周期性地随机从设置了过期时间的 key 中抽查一批,然后逐个检查这些 key 是否过期,过期就删除 key。相比于惰性删除,定期删除对内存更友好,对 CPU 不太友好。
延迟队列 :把设置过期时间的 key 放到一个延迟队列里,到期之后就删除 key。这种方式可以保证每个过期 key 都能被删除,但维护延迟队列太麻烦,队列本身也要占用资源。
定时删除:每个设置了过期时间的 key 都会在设置的时间到达时立即被删除。这种方法可以确保内存中不会有过期的键,但是它对 CPU 的压力最大,因为它需要为每个键都设置一个定时器。
七、Redis的内存淘汰策略Redis 的内存淘汰策略
只有在运行内存达到了配置的最大内存阈值时才会触发,这个阈值是通过redis.conf的maxmemory参数来定义的。
Redis 提供了 6 种内存淘汰策略:
volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰。
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。
allkeys-lru(least recently used):从数据集(server.db[i].dict)中移除最近最少使用的数据淘汰。
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。
no-eviction(默认内存淘汰策略):禁止驱逐数据,当内存不足以容纳新写入数据时,新写入操作会报错。
八、Redis bigkey问题
bigKey:一个 key 对应的 value 所占用的内存比较大,那这个 key 就可以看作是 bigkey。
处理方式
分割 bigkey :将一个 bigkey 分割为多个小 key。例如,将一个含有上万字段数量的 Hash 按照一定策略(比如二次哈希)拆分为多个 Hash。
手动清理 :Redis 4.0+ 可以使用 UNLINK 命令来异步删除一个或多个指定的 key。Redis 4.0 以下可以考虑使用 SCAN 命令结合 DEL 命令来分批次删除。
采用合适的数据结构 :例如,文件二进制数据不使用 String 保存、使用 HyperLogLog 统计页面 UV、Bitmap 保存状态信息(0/1)。
开启 lazy-free(惰性删除/延迟释放) :lazy-free 特性是 Redis 4.0 开始引入的,指的是让 Redis 采用异步方式延迟释放 key 使用的内存,将该操作交给单独的子线程处理,避免阻塞主线程。
九、Redis生产问题
缓存穿透
缓存穿透说简单点就是大量请求的 key 是不合理的,根本不存在于缓存中,也不存在于数据库中 。
解决办法:
做好参数校验
(1)缓存无效key
(2)布隆过滤器
(3)接口限流
缓存击穿
缓存击穿中,请求的 key 对应的是 热点数据 ,该数据 存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期) 。
解决办法:
(1)永不过期
(2)提前预热
(3)加锁
缓存雪崩
缓存在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力。
针对 Redis 服务不可用的情况:
(1)Redis 集群:采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。Redis Cluster 和 Redis Sentinel 是两种最常用的 Redis 集群实现方案。
(2)多级缓存:设置多级缓存,例如本地缓存+Redis 缓存的二级缓存组合,当 Redis 缓存出现问题时,还可以从本地缓存中获取到部分数据。
针对大量缓存同时失效的情况:
(1)设置随机失效时间(可选):为缓存设置随机的失效时间,例如在固定过期时间的基础上加上一个随机值,这样可以避免大量缓存同时到期,从而减少缓存雪崩的风险。
(2)提前预热(推荐):针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。(3)持久缓存策略(看情况):虽然一般不推荐设置缓存永不过期,但对于某些关键性和变化不频繁的数据,可以考虑这种策略。