# Redis笔记
**Repository Path**: xxacker/redis-notes
## Basic Information
- **Project Name**: Redis笔记
- **Description**: Redis 笔记
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-01-08
- **Last Updated**: 2024-01-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Redis笔记
### 介绍
Redis 笔记用来记录 Redis 的基础知识和用法。
### 0. Redis 在你项目中的应用场景?
### 1. 什么是 Redis ? 它主要用来什么的?
1. Redis 是**高性能的非关系型数据库**,存储格式是 key-value。可以用作**数据库**、**缓存**和**消息代理**。
2. 它支持的数据类型非常多,包括:**string(字符串)、list(列表)、set(集合)、zset(sorted set 有序集合)和 hash(哈希类型)**;
3. 由于 Redis 的数据都基于缓存的,所以速度很快,每秒可以处理超过 10 万次读写操作,是已知性能最快的 Key-Value 数据库;
4. Redis 也可以实现数据写入磁盘中,保证了数据的安全不丢失,而且 Redis 的操作是原子性的。
### 2. Redis 支持哪些数据类型?(请解释一下 Redis 的五种对象类型以及它们的应用场景?)
Redis的五种对象类型包括字符串(string)、列表(list)、集合(set)和有序集合(sorted set)、哈希(hash)。
1. (string)字符串: 常用于存储字符串、整数或浮点数等信息;
2. (list)列表: 是一种有序的字符串列表,可以在头部或尾部添加元素。可以通过List来实现队列和栈等数据结构。
3. (set)集合: 用于存储多个唯一的字符串,并可以进行交集、并集等操作;
4. (sorted set)有序集合: 也用于存储多个唯一的字符串,但每个元素都会关联一个分数,根据分数进行排序。
5. (hash)哈希: 用于存储多个键值对;列表用于存储多个字符串,并按照插入顺序排序;
### 3. Redis 是单线程还是多线程的?
Redis6.0 版本之前的单线程是指 **网络I/O** 和 **键值对读写** 是由一个线程完成的。
Redis6.0 引入的多线程指的是 **网络请求过程** 采用了多线程。但是 **键值对读写** 仍然是单线程处理的,所以 Redis 依然是**并发安全**的。
### 4. Redis 单线程为什么还能这么快?
1. Redis 命令执行基于内存操作,一条命令在内存里操作的时间是几十纳秒
2. 命令执行是单线程操作,没有**线程切换**开销
3. Redis 底层是基于 **I/O 多路复用机制**提升整体的的 I/O 利用率
4. 高效的数据存储结构:全局 hash 表以及多种高效数据结构,比如:跳表、压缩队列、链表等等。
### 5. Redis 底层是如何使用**跳表**来存储数据的?
在 Redis 中数据类型是 有序集合 zset,它的底层是使用**跳表**来实现的;
一开始 zset 中的数据,会保存在链表中,插入、删除元素非常快,但是查找很慢;
zset 对链表做了优化、改造;将**有序链表**改造为支持近似**“折半查找法”**。可以进行快速的插入、删除、查找操作。
### 6. Redis 的 key 过期了,为什么内存没有释放?
Redis 对于过期的 key 的处理,一般有**惰性删除**和**定时删除**两种策略:
1. 惰性删除:当**读/写一个已经过期的 key** 时,会触发惰性删除策略,判断 key 是否过期,如果过期了直接删除掉这个 key。
2. 定时删除: 由于惰性删除策略无法保证冷数据被及时删除掉,所以 Redis 会定期(默认100ms)主动淘汰一部分已经过期的 key ,所以可能会出现部分 key 已经过期,但还没有被清理的情况,导致内存没有被释放。
### 7. Redis 的 key 没有设置过期时间,为什么被 Redis 主动删除了?(Redis 的淘汰策略)
当 Redis 的已用内存超过 最大内存限定的时候,会触发主动清理策略。
主动清理策略在 Redis4.0 之前,一共实现了 6 种内存淘汰策略,在 4.0 之后,又增加了 2 种策略,总共 8 种:
a). 针对设置了**过期时间的 key** 做处理:
1. volatile-ttl:在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除。
2. volatile-random:在设置了过期时间的键值对中,随机删除。
3. volatile-lru:使用**最近最久使用算法**,也就是淘汰使用时间最久的数据。
4. volatile-lfu:使用**最近最少使用算法**,也就是挑选出最近使用次数最少的 key 。
b). 针对**所有的 key** 做处理:
1. allkeys-random:从所有键值对中随机选择并删除数据
2. allkeys-lru:使用**最近最久使用算法**,也就是淘汰使用时间最久的数据。
3. allkeys-lfu:使用**最近最少使用算法**,也就是挑选出最近使用次数最少的 key 。
c). 不处理:
1. noeviction:不会删除任何数据,达到内存上限后返回错误。
### 8. 删除 key 的命令会阻塞 Redis 吗?
如果是删除 list、set、zset、hash 中的数据,会造成Redis 的阻塞。因为删除这里面的数据,需要逐个遍历删除。
### 9. Redis 主从、哨兵、集群架构优缺点比较
(Redis 单节点存储的数据,最高不超过 10G,否则会导致持久化文件过大,影响**数据恢复**或**主从同步的效率**。)
如果需要**高并发读写分离**,可以考虑**主从复制**或**哨兵模式**;
如果需要**高可用性和读写分离**,可以考虑集群模式。
### 10. 什么是缓存穿透?应该如何解决?
客户端查询数据库中没有的记录,导致缓存在这种情况下无法利用,称之为缓存穿透。
解决方案:
1. 不管数据实际上存不存在,都把这个键存到缓存中(有效期设置的短一些,比如一分钟到三分钟),然后值设置为一个特定值,业务中如果获取到的结果是这个特定值,则报错返回。这样可以在一定程度上解决缓存穿透问题。(mybatis 中 cache 解决了缓存穿透,将数据库中没有查询到结果也进行缓存。)
2. 设置超时访问(timeout access)。将对请求数据的访问次数设置一定的限制,若一定时间内访问次数未达到约定值,便无权访问,拒绝服务。
### 11. 什么是缓存雪崩?应该如何解决?
在系统运行的某一时刻,突然系统中缓存全部失效,导致大量请求直接到达后端数据库,进而导致数据库压力过大甚至崩溃,整个系统出现故障。
解决方案:
1. 优化缓存过期时间:设计缓存时为每个 key 选择合适的过期时间,避免大量 key 在同一时刻过期,造成缓存雪崩。可以通过设置不同的过期时间或使用随机因子来错开缓存过期时间。
2. 高可用性设计:使用 Redis **哨兵模式**或**集群部署方式**,确保即使个别节点宕机,整个缓存层仍可正常使用。在多个机房部署 Redis,确保机房故障时缓存层仍可高可用。
### 12.
###
###
###
###
###
###
###
###
###
###
###
###
###
###
###