1. Redis到底是单线程还是多线程?
Redis6.0版本之前的单线程指的是 网络I/O和键值对读写是由一个线程完成的。
Redis6.0引入的多线程指的是网络请求过程采用了多线程;而键值对读写命令仍然是单线程处理的,Redis依然是并发安全的。
即数据操作模块是单线程的,其它持久化、集群数据同步等,是由额外线程执行的。
2. Redis 单线程为什么还能这么快
命令执行基于内存操作,在内存操作时间是几十纳秒
命令执行是单线程,没有线程切换开销
基于IO多路复用机制提升Redis的I/O利用率
高效数据结构。
3. zset 有序集合
ziplist
skiplist:有序链表改造优化而来。链表加索引层,索引层是链表数据往上提。其还包含hashset模块,用于查找分数值。
4. redis过期了为什么内存没有释放
1. 惰性删除:当读/写一个已经过期的key时,会触发惰性删除策略,判断key是否过期,如果过期直接删除这个key (大内存可以)
2. 定时删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key,这里一批只是部分过期key,
所以可能会出现部分过期key,所以可能会出现部分key已经过期但还没有被清理掉的情况,导致内存并没有被释放。(CPU不敏感可以)
5. Redis Key 没设置过期时间,为什么被Redis主动删除了
当Redis以用内存超过最大内存限制时,触发主动清理策略
共8种策略:
设置了过期时间的key做处理
1. volatile-ttl:越早过期越先删除
2. volatile-random:设置过期键,随机删除
3. volatile-lru:使用LRU算法筛选设置了过期时间的键值对删除
4. volatile-lfu:使用LFU算法删除
针对所有key做处理:
5. allkeys-random:从所有键值对随机选择并删除
6. allkeys-lru: 从所有键值对LRU
7. allkeys-lfu: 从所有键值对LFU
不处理:
8. noeviction:不会剔除,拒绝所有写入操作并返回客户端错误信息“(error)”,此时Redis只响应读操作。
LRU(Least Recently Used 最近最少使用):淘汰很久没有被访问的数据。 通常这个。
LFU(Least Frequently Used 最不经常使用):淘汰最近一段时间访问次数最少的数据。 热点数据 LFU
9. DEL key会阻塞Redis
删除单个字符串类型的key,时间复杂度为O(1) 对应的value值很大,几百M,删除的时候也会阻塞redis
删除单个列表、集合、有序集合的key等,时间复杂度为O(M),M为以上数据结构内的元素数量。 因此数据量比较大,也会阻塞redis。
10. Redis主从、哨兵、集群架构优缺点比较
主从:主从切换需要运维介入
哨兵模式:主从切换不需要运维介入就能切换成功,哨兵配置略微复杂,性能和高可用表现一般。例如当主从切换的瞬间存在访问瞬断的情况,并且哨兵
模式只有一个主节点对外提供服务,没法支持很高的并发。单个节点内存不宜设置过大,否则会导致持久化文件过大,影响数据恢复或主从同步效率。
单个节点100个G,性能就会比较低。
集群架构:redis集群是一个由一个主从节点群组成的分布式服务器群。其不需要哨兵也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,
这种集群模式没有中心节点,可水平扩展。
分片存储的,100G分别分配给不同的节点来,该系统也会出现瞬断问题,属于局部瞬断。
11. Redis集群数据hash分片算法
Redis 集群将所有数据划分为16384个槽位,当客户端要查找某个key时,可以根据算法定位到目标节点。
slot = CRC16(key)mod 16384
再根据槽位值和Redis节点的对应关系可以定位到key具体落在哪个Redis节点上。
12 redis主从切换问题
因为时钟不同步的原因,主节点里设置了过期时间的key,从slave角度来看,可能会有很多在master里没过期的数据其实已经过期了,此时主从切换,master有大量过期key,主线程可能会发生阻塞,无法及时处理客户端请求。 master与slave机器时钟严重不一致,对业务影响非常大。
13 redis持久化
RDB(snapshot)快照
默认情况下, Redis将内存数据库快照保存名字位dump.rdb二进制文件中(二进制文件)
可以进行设置,让它在N秒内数据集至少有M个改动,这一条件满足时,自动保存一次
例如 配置文件中这么写 save 10 1000 即满足10秒内至少有1000个键被改动,自动保存一次数据集。
也可手动生成RDB快照,客户端输入save或者bgsave bg的意思时background
bgsave的写时复制(COW)机制
Redis借助操作系统提供的写时复制技术,生成快照同时,依然可以正常处理命令。
COW机制是这么回事:
1. 分配一个新的物理块。 我们称为第9个物理块
2. 读取第8个物理块的数据写入到第9物理块。
3. 更新快照卷Map,指向第9物理块。
4. 更新第8物理块。
意思就是复制一份第8物理块,之前的更新掉。快照卷不变,原始卷变了
ROW是这么回事: 变原始卷,快照卷不变。
1. 分配一个新的物理块。我们称为第9个物理块
2. 数据写入到第9个物理块。
3. 更新原始卷map,指向第9个物理块。
AOF(append-only file)
快照功能并不是非常耐久:Redis 因某些原因而造成故障停机,那么服务器将丢失最近写入。
配置文件里面打开AOF功能: appendonly yes
从现在开始,每当Redis执行一个改变数据集的命令时,这个命令都会被追加到AOF文件的末尾。这样的话,当Redis重启时,程序就可以通过
重新执行AOF文件中的命令来达到重建数据集的目的。
可以选择Redis多久才将数据fsync到磁盘一次。
三个选项:
1. appendfsync alaways :每次有新命令追加到AOF文件时就执行一次fsync,非常慢 (每次都加)
2. appendfsync everysec :每秒fsync一次,够快,故障时只丢1秒数据
3. appendfsync no:从不fsync,将数据交给操作系统来处理。
缺点:文件很大,恢复速度慢
优化:会定期根据内存的最新数据生成aof文件。
当RDB和AOF同时开启,redis重启了,会默认使用AOF恢复数据。
RDB具有文件小、恢复快,但是容易丢失数据,而AOF 文件大,恢复慢,不太容易丢失数据。
Redis4.0 以后 会有个选项,混合持久化。(必须先开启AOF)
aof-use-rdb-preamble yes
注意是重写。
开启之后,AOF在重写时,不在单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻的内存做RDB快照,
并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写
完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。
于是在Redis重启的时候,可以先加载RDB内容,然后再重放AOF内容,重启效率大幅提升。
混合持久化AOF文件结构:
线上Redis 持久化策略一般如何设置:
可以在某个Slave节点开启AOF备份数据,策略设置为每秒同步一次即可。会出现主节点宕机,主节点重启之后无数据,然后slave同步之后把数据给删了。
怎么避免?重启的话只能等主从切换完成,再重启。
Redis 主从复制风暴咋回事
Redis主节点如果有多个从节点,某一个时刻同时连接上主节点,那么主节点会同时把内存快照RDB发送给多个从节点,这样主节点压力很大。
如何避免?树形复制架构。
Redis 集群为什么至少需要三个主节点
因为新主节点的选举现需要大于半数的集群主节点同意才能选举成功,只有两个的话,其中一个挂了,达不到选举新主节点条件的。
Redis集群为什么推荐奇数个节点
在挂掉相同机器的前提下,奇数和奇数+1的偶数,效果是一样的,但是却多浪费了一台机器
例如:3台机器挂两台,和4台机器挂两台同样都不可用。