Redis常见问题

First Post:

Last Update:

Word Count:
1.7k

Read Time:
5 min

Redis入门

基本问题

Redis到底是单线程的还是多线程的?

Redis 6.0版本之前的单线程指的是其网络I/O和键值对读写是由一个线程完成的

Redis6.0引入的多线程指的是网络请求过程采用了多线程,而键值对读写命令仍然是单线程处理的,所以Redis依然是并发安全的。

也就是只有网络请求模块和数据库操作模块是单线程的,其他的持久化、集群数据同步等是由额外线程执行的。

Snipaste_2022-09-28_10-37-53

Redis单线程为什么还能这么快?

命令执行基于内存操作,一条命令在内存里操作的时间是几十纳秒

命令执行是单线程操作,没有线程切换的开销

基于IO多路复用机制提示Redis的I/O利用率

高效的数据存储结构:全局hash表以及多种高效的数据结构,比如全局hash表,跳表,压缩列表,双向链表,整数数组等等。

Redis底层数据如何用跳表来存储的?

跳表:将有序链表改造为支持近似“折半查找”算法,可以进行快速的插入、删除、查找操作。

Snipaste_2022-09-28_10-36-55

Redis Key过期了为什么内存没有释放?

在使用Redis是,肯定经常使用SET命令

SET除了可以设置key-value之外,还可以设置key的过期时间,比如:

1
2
set i0gan abc ex 120
ttl i0gan # 查看过期剩余时间

此时如果你想修改key的值,但只是单纯的使用set命令,而没有加上过期时间的参数,那这个key的过期时间会被擦除。

1
2
3
set i0gan abc
ttl i0gan
(integer) -1 # 永久

导致这个问题的原因在于:set命令如果不设置过期时间,那么redis会自动擦除这个key的过期时间。

如果你发现了redis的内存持续增长,而且很多key原来设置了过期时间,后来发现过期时间丢失了,很有可能是因为这个原因导致的。

这时你的Redis中就会存在大量不过期的key,消耗过多的内存资源。

所以在使用set命令时,如果开始时设置了过期时间,那么之后修改这个key时,也务必加上过期时间的参数,避免过期时间丢失的问题。

redis对于过期key的处理一般有惰性删除和定时删除两种策略

  1. 惰性删除:当读/写一个已经过期的key时,会触发惰性删除策略,判断key是否过期,如果过期了直接删除掉这个key
  2. 定时删除:由于惰性删除策略无法保证冷数据及时杯删除,redis会定期(默认每100ms)主动删除一批已过期的key,这里的一批只是部分过期key,所以可能出现部分key已经过期但还没有被清理掉的情况,导致内存并没有被释放。

Redis key 没有设置过期时间为什么被redis主动删除?

当redis已用内存超过maxmemory限定时,会触发主动清理策略

主动清理策略在redis4.0之前一共实现了6中淘汰策略,在4.0之后,又增加了2中策略,总共8种:

针对设置了过期时间的key做处理

  1. volatile-ttl:在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除。
  2. volatile-random: 就像它的名称一样,在设置了过期时间的键值对中,进行随机删除。
  3. volatile-lru:会使用LRU算法筛选设置了过期时间的键值对删除。
  4. volatile-lfu: 会使用LFU算法筛选设置了过期时间的键值对删除。

针对所有的key做处理

  1. allkeys-random: 从所有键值对中随机选择并删除数据
  2. allkeys-lru: 使用LRU算法在所有数据中进行筛选删除
  3. allkeys-lfu: 使用LFU算法在所有数据中进行筛选删除

不处理

  1. noeviction: 不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息”(error) OOM command not allowed when used memory”,此时Redis只响应读操作。

Redis淘汰key的算法LRU与LFU区别

LRU(Least Recently Used,最近最少使用):淘汰很久没有被访问过的数据,以最近一次访问时间作为参考

LFU(Least Frequently Used,最不经常使用):淘汰最近一段时间被访问次数最少的数据,以次数作为参考,绝大多数情况我们都可以用LRU策略,当存在大量的热点缓存数据时,LFU可能更好点。

删除Key的命令会阻塞Redis吗?

这要得看删除的key是什么类型的,时间复杂度分别如下:

删除单个字符串类型的Key,时间复杂度为O(1)

删除单个列表、集合、有序或哈希表类型的key,时间复杂度为O(n),n为数据结构内元素的数量。

删除拥有较多元素的key的话,可能会出现阻塞的。

Redis主从、哨兵、集群架构优缺点比较

主从模式

Snipaste_2022-09-28_11-55-39

哨兵模式

Snipaste_2022-09-28_12-21-31

在redis3.0以前的版本要实现集群一般是借助哨兵sentinel弓弩来监控master节点的状态,如果master节点异常,则会做主从切换,将一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性方面表现一般,特别是从主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持很高的并发,且单个节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率。

高可用集群模式

Snipaste_2022-09-28_12-24-51

redis集群是一个由多个主从节点群组的分布式服务器群,它具有复制、高可用性和分片的特性。Redis集群不需要sentinel哨兵也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,这种集群模式没有中心节点,可水平拓展,根据官方文档称可以线性拓展到上万个节点(官方推荐不超过1000个节点)。redis集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置也非常简单。

Redis集群数据hash分片算法是怎么回事?

打赏点小钱
支付宝 | Alipay
微信 | WeChat