1.redis是单线程还是多线程?
redis6.0之前是单线程,网络IO和键值对的读写都是单线程的
redis6.0引入了多线性概念,网络IO会有多核处理,服务端处理还是单线程
2. redis单线程为什么还这么快?
- 命令执行基于内存操作
- 命令的执行是单线程的,没有线程切换的开销
- 基于IO复用机制提升IO的利用率(epoll)
- 高效的数据存储结构:全局hash表(一维数组+二维链表);
3.redis底层如何用跳表存储?
有序集合zset会采用跳表存储
会将zset先放在一个有序链表中,但是查找效率比较慢;优化的策略是建立索引层,每两个节点取一级索引
举个例子:
链表有8个数据,如果正常进行查询操作,查询8的元素,查询的次数是8次(1到8);但是建立二级索引,链表查询顺序为1->3->5->7->8,查询次数为5次;按此再建立三级索引,查询顺序为1->5->8,如果有几十万的大量数据,可以大大减少查询时间
4.redis的key没有设置过期时间,为什么被删除了?
- redis key的淘汰策略:
-
针对设置过期时间的key的处理
-
volatile-ttl:根据过期时间进行删除,过期时间越长的越先删除
-
volatile-random:在设置过期时间的key中随机删除
-
volatile-lru:在设置过期时间的key中,采用LRU算法进行删除(LRU:最近最少使用)
-
volatile-lfu:在设置过期时间的key中,采用LFU算法进行删除(LFU:最近最不经常使用)
-
-
针对所有key的处理
-
allkeys-random:在所有key中随机删除
-
allkeys-lru:在所有key中,采用LRU算法进行删除
-
allkeys-lfu:在所有key中,采用LFU算法进行删除
-
-
不处理
-
no-eviction:不删除任何数据,拒绝写入操作,报错返回给客户端(OOM),此时redis只响应读操作
-
5.删除key的命令会阻塞redis吗?
会;
删除String类型的key时时间复杂度为O(1),当String类型key对应的value非常大时,可能会等待删除操作,从而阻塞
删除集合、列表、有序集合或哈希表类型的key,时间复杂度为O(M),M是以上数据结构内的元素个数;在删除这些结构时,当元素的个数很多是,可能会阻塞
6.redis主从、哨兵、集群架构的优缺点
-
优点
-
主从架构一主多从,主负责写,从节点负责读,可以实现水平扩容,支持读高并发
-
哨兵模式解决了主从架构不能自动切换主从节点的问题
-
集群架构针对海量数据+高并发+高可用的场景
-
-
缺点
-
主从架构的主节点挂掉后,不能自动
-
每个节点存储的数据是一样的,浪费内存空间。
-
7.工作原理是什么?
-
主从架构工作原理
-
-
主节点负责写,从节点负责读,当启动一个从节点时,会发送一个PSYNC命令给主节点
-
如果从节点是首次连接主节点,那么会触发一次全量复制,主节点会启动一个后台线程,生成一份RDB文件
-
主节点还会同时将新收到的写命令缓存到内存中;生成完RDB文件后,主节点会发送给从节点,从节点将RDB文件写入本地磁盘,再从本地磁盘加载到内存中
-
主节点将新收到的写命令发送到从节点进行同步
-
如果主从节点连接断开,会进行重连,重连后主节点仅会将部分缺失的数据同步给从节点
-
-
哨兵模式工作原理
-
-
每个sentinel一每秒一次的频率向它所知道的主从节点以及其他sentinel实例发送一个PING命令
-
如果一个实例距最后一次有效回复PING命令的时间超过了指定值,这个实例就会被sentinel记录为主观下线
-
如果一个master实例被标记为主观下线,则在监视这个master的sentinel要以每秒一次的频率确认master是否真正进入主观下线状态
-
当足够数量的sentinel在指定时间内确定master确实进入了主观下线状态,则maste会被标记为客观下线;如果没有足够数量的sentinel同意master已经下线,则master客观下线的状态被解除
-
sentinel节点会选举出sentinel leader,负责故障转移工作
-
sentinel leader会推举出表现良好的从节点成为新的主节点
-
-
集群模式工作原理
-
-
通过hash的方式,将数据分片,每个节点均分存储一定哈希槽区间的数据,默认分配16384个槽位
-
每份数据分片会存储在多个互为主从的多节点上
-
数据写入先写主节点,在同步到从节点
-
同一分片多个节点间的数据不保持一致性
-
读取数据时,客户端操作的key没有分配在该节点上时,redis会返回转向指令,指向正确的节点
-
扩容时需要把旧节点的数据迁移一部分到新节点
-
8.redis集群架构hash分片算法是什么?
-
每个节点均分存储一定哈希槽区间的数据,默认分配16384个槽位
-
通过槽位定位算法,对key使用crc16算法得到一个值,把这个值对16384取模得到槽位
9.randomkey会导致Redis阻塞吗?
会,如果randomkey挑选的key都是失效的key,则会存在阻塞问题;
-
如果在master节点执行randomkey,redis会采用惰性删除过期key策略,但是每次randomkey都获取到了失效key,还是会使redis效率变慢
-
如果在salve节点执行randomkey,salve节点删除失效key需要等待master节点返回删除命令,如果失效的key较多,redis来不及删除,则randomkey会进入死循环,导致redis阻塞
10.redis的持久化策略
Redis支持两种方式的持久化,一种是RDB的方式,一种是AOF的方式。前者会根据指定的规则定时间将内存中的数据存储在硬盘上,而后者在每次执行完命令后将命令记录下来。一般将两者结合使用。
- RDB方式:RDB是redis的默认持久化方式,持久化时会将内存中的数据写入磁盘中,在指定的目录下生成一个dump.rdb文件,当redis重启时会去加载dump.rdb文件恢复数据。
- RDB持久化过程:
- 创建一个子进程
- 父进程继续接受并处理客户端的请求,子进程开始将内存中的数据写入磁盘
- 当子进程写完所有数据后,会用临时文件替换旧的RDB文件
- ☆当redis重启时会读取rdb快照文件,将数据从磁盘载入内存,此时如果redis异常退出,则会丢失最近一次持久化的数据
- 触发RDB快照的方式:
①手动触发:
主要是SAVE和BGSAVE命令;SAVE命令触发的rdb快照会阻塞客户端发来的请求,而 BGSAVE命令触发rdb快照是异步操作,快照的同时还能响应客户端请求(一般使用 BGSAVE命令)。
注意:LASTSAVE 命令用于查看 BGSAVE 命令是否执行成功。
②被动触发:
- 在redis配置文件中配置自动快照(SAVE 300 10:表示300秒内至少有10个key被修改则进行快照)
- 如果从节点执行全量复制操作,主节点自动执行BGSAVE生成rdb文件发送给从节点
- 默认情况下执行shutdown命令,如果没有开启AOF,则会自动执行BGSAVE
- 执行debug reload命令重新加载redis时,会自动触发SAVE操作
- AOF方式:用独立的日志方式记录每次写命令,redis重启时会重新执行AOF文件中的命令达到数据恢复目的;默认redis是不开启AOF持久化的,可以使用appendonly参数开启(appendonly yes);开启后每执行一条写命令,redis会把该命令写进aof_buf缓冲区,AOF缓冲区会根据对应的策略向磁盘做同步操作
- 同步时机:默认是30秒执行一次同步,为了防止缓冲区数据丢失,可以用appendsync 参数设置同步时机
- appendsync always:每次写入aof文件都会执行同步,最安全但是最慢,不建议配置
- appendsync everysec:将aof_buf缓冲区中的所有内容写入到AOF文件,如果上次同步AOF文件的时间距离现在超过一秒钟,那么再次对AOF文件进行同步,并且这个同步操作是由一个线程专门负责执行的(默认)
- appendsync no :将aof_buf缓冲区中的所有内容写入到AOF文件,但并不对AOF文件进行同步,何时同步由操作系统来决定