1.特点
a.kv存储,底层使用unordered_map,可以达到O(1)存储。
b.封装了epoll,高效的网络io模型
c.高效的线程模型
d.接收客户端请求->解析请求 ->进行数据读写等操作->发生数据给客户端是单线程的
2.封装一个键值对的数据结构叫做一个entry。
所有的键先对key完成一次hash,然后对hash table的长度进行求模,然后存放对应的指针
使用链表法来解决冲突,使用头插法
3.redis的扩容,当链表过长需要扩容,然后重哈希(渐进式重哈希)
不需要一次性搬完,后台一点一点搬,等到老数据全都到新的,然后再释放老的,新元素要插入需要插入到新的hash table中
4.key的类型
key的长度可以很大
类别 | 可以的类型 |
---|---|
value | Stringlist,zset,hash,stree |
key | 可以是任意数据类型,文件、音频,最终服务器会变成string |
5.Redis类型的设计
类型 | 特点 |
---|---|
string | 1.定义一个len(长度),一个free(多的空间)还有一个char[],有一个flag,前3位表示类型,后面5位表示长度(hdr5) 2.扩容的时候成倍地去扩容 3. |
值最终都会放在redis object中
6.底层的实现
面经部分
Redis到底是单线程还是多线程?
6.0版本前网络I/O和键值对的读写都由一个线程完成。6.0后核心命令还是单线程,但是网络I/O使用了多CPU的多线程,所以还是并发安全的。(持久化、数据同步等都还是多线程)
1.Redis单线程为什么还能这么快
1.命令基于内存操作
2.命令执行是单线程操作,没有线程切换的开销
3.基于IO多路复用机制提升Redis的I/O效率(基于epoll)
4.高效的数据存储结构:全局hash表、跳表、压缩列表、链表
3.Redis底层数据如何用跳表存储
对于zset来说,可以用跳表实现
跳表怎么做的:
1.把链表每2个元素做一个冗余元素,继续向上,做成索引.
2.对于查找来说,我们从最高的索引来查找,复杂度差不多为O(logn),类似二分的思想
2.Redis key过期了为什么内存没释放
1.修改值的时候要带上过期时间,不然永远不过期
2.Redis对过期key的策略,有惰性删除和定时删除,所以可能出现过期了还没被删除的情况(默认定期删除)
3.Redi key没设置过期时间为什么被主动删除了
Redis内存淘汰策略:
当Redis超过内存最大限制的时候,会触发主动清理策略(lru\lfu删除)
4.Redis淘汰算法 LRU和LFU的区别
最近最少使用和最近被访问次数最少的,当存在大量的热点缓存数据的时候,可能LFU比较好
5.删除key的命令会阻塞Redis吗
DEL key [k..]
删除给定的一个或多个key
删除耽搁列表、集合、有序函数或者哈希表的key,时间复杂度为O(M),M为以上数据结构内的元素数量
6.Redis主从、哨兵、集群
主从模式 | 1.数据从主节点备份到从节点,主节点挂了,从节点变为主节点 | |
哨兵模式 | 1.增加一些哨兵节点(本质也是redis实例) 2.对每一个redis主从进行监听 3.如果主节点挂了,哨兵感知到,然后重新选举出一个新的节点 4.随后客户端可以访问新的主节点 5.可以自动化,但是主从切换比较慢 |
提供服务只有一个节点支持,无法满足大并发 Redis单节点不要超过10G,不然影响恢复 |
集群模式 | 1.多个小的主从节点统一成一个大的来对外处理 2.不会把所有数据放在一个节点,而是分片存储 |
不要超过1000个节点 |
7.Redis集群数据哈希分片算法
集群客户端有一个哈希分片算法,逻辑上划分为16384个槽位,然后每个节点分别划分一片槽位
HASH_SLOT=CRC16(key) mod 16384
8.Redi执行命令阻塞循环
Random KEY,如果有大量的key过期了,然后又有可能都拿到过期的
slave上执行random key,因为slave不会主动删除,需要master同步之后再会删除
9.Redis主从切换导致缓存雪崩
假设主节点的机器时钟比从节点走的很慢,这个时候发生主从切换之后,在主节点认为没过期的可能从节点过期了,切换之后,出问题。
10.Redis持久化
方法名称 | 特点 | 优点 | 缺点 |
---|---|---|---|
RDB快照持久化 | 在指定的时间内,把内存中的数据库快照写入磁盘,实际的过程是fork一个子进程,先把数据写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储 | 1.整个数据库只包括一个文件dump.rdb,方便与持久化 2.容灾性好,方便备份 3.性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以是IO最大化,主进程不会进行任何IO操作 |
1.数据安全性低,RDB是间隔一段时间进行持久化,如果持久化期间redis发生故障,会发生数据丢失 2.由于RDB借助fork来完成持久化工作,所以如果数据集比较大,会导致整个服务停止1秒 |
AOF(append file) | 以日志的形式,类似redolog | 1.数据安全。2.通过append模式写文件,即使宕机也不会破坏已经存在的内容。3.定期对AOF进行重写,达到压缩的目的 | 1.AOF文件比RDB文件大2.比rdb启动效率低。3.运行效率没有RDB高 |
11.Redis主从复制风暴
主节点可能要一次性连多个从节点来传输快照,导致压力比较大
12.主从频繁切换
网络抖动导致频繁的主从切换,需要使用timeout来进行主从切换的判断
13.Redis集群为什么至少需要3个master节点
3个以上才能选举成功
14.Redis集群为什么需要奇数个节点
新master的选举需要半数同意
15.Redis批量操作命令
必须落在同一个节点,不然会报错
16.缓存穿透,缓存击穿、缓存雪崩
对于一个请求来说,如果redis中存在,直接返回,否则去数据库中查,然后添加入redis
布隆过滤器:不在一定不在,在可能有问题(有碰撞),只能加数据不能减数据
类别 | 特点 | 策略 |
---|---|---|
缓存穿透 | 1.缓存中查不到,数据库中也查不到。然后不断地拿这条sql来攻击 | 1.进行参数校验。 2.把数据库中没有查到结果的数据也写入缓存 3.引入布隆过滤器(可以判断是否在集合当中,通过哈希散列来做),在访问redis前对query进行校验 |
缓存击穿 | DB中有,缓存中没有,一般出现在缓存失效或者过期的情况,高并发场景下数据库压力瞬间增大 | 1.设置缓存热点数据永不过期,在逻辑上设置一个过期时间 2.加载db的时候需要防止并发,每次只有一个线程可以写 |
缓存雪崩 | 1.缓存大面积过期,导致请求都被转发到DB | 1.把缓存的失效时间分散开 2.对热点数据设置永不过期 |
17. Redis的partition
Redis 的分区(partition)是指将 Redis 数据库中的数据分散到多个物理节点或者服务器上,以提高数据库的性能、可扩展性和可用性。
Redis 支持多种分区模式,包括:
哈希分区:Redis 将键值对根据键名进行哈希,然后将哈希结果分散到多个物理节点或者服务器上。这种分区模式可以将键值对均匀分布到多个节点上,从而提高性能和可扩展性。但是,这种分区模式不能保证数据在所有节点上的复制,也不能保证数据在所有节点上的一致性。
范围分区:Redis 将数据按照键名的范围进行分区,每个节点或者服务器负责一定范围内的键值对。这种分区模式可以保证数据在所有节点上的复制和一致性,但是在键名分布不均匀时,可能会导致节点负载不均衡的问题。
副本分区:Redis 将数据进行复制,并将复制品存储在多个物理节点或者服务器上。这种分区模式可以保证数据的高可用性和容错性,但是可能会增加存储和网络带宽的开销。
Redis 分区可以在多个物理节点或者服务器上同时进行读写操作,从而提高数据库的并发性能和可用性。但是,在分区模式下,数据的管理和维护变得更加复杂,需要进行节点之间的数据同步、负载均衡、故障恢复等操作。因此,在设计和实现 Redis 分区时,需要考虑到数据库的特性、数据的分布和访问模式、节点的规模和配置等因素。