Redis常见问题
1.Redis到底是单线程还是多线程
Redis6.0版本之前的单线程,指的是网络IO和键值对读写是由一个线程完成。
Redis6.0后引入多线程指的是网络请求采用了多线程,而键值对读写仍然是单线程处理的,所以Redis仍然是并发安全的。
也就是说,只有网络请求和数据操作是单线程的,其它的如持久化,数据同步,是由额外线程执行的。
2.Redis单线程为什么还能这么快
1.命令基于内存操作
2.命令执行是单线程,没有线程切换的开销
3.基于IO多路复用机制,提升IO利用率
4.高效的数据结构:全局hash表,跳跃表,压缩列表,链表等
3.Redis key过期了为什么没有释放
1.添加、修改value的时候忘了添加过期时间
2.Redis采用惰性删除和定时删除策略
-
惰性删除:当读写一个key的时候会触发惰性删除策略,判断key是否过期,过期了就删除
-
定时删除:默认100ms主动淘汰一部分已过期的key,所以出现了一部分过期的key还没来得及删除
4.Redis key没有设置过期时间为什么被主动删除了
当Redis已用内存超过maxmemory限定时,触发主动清理策略
1.针对设置了过期时间的key做处理
- volatile-ttl:在筛选时,针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除。
- volatile-random:在设置了过期时间的键值对中,随机删除
- volatile-lru:会用LRU算法筛选设置了过期时间的key进行删除
- volatile-lfu:会用LFU算法筛选设置了过期时间的key进行删除
2.针对所有key
- allkeys-random:从所有key中随机删除
- allkeys-lru:使用LRU算法筛选删除所有key
- allkeys-lfu:使用LFU算法筛选删除所有key
3.不处理
- noeviction:不会删除任何数据,拒绝写入操作并返回”(error) OOM command not allowed when used memory”, 只响应读操作
5.LRU和LFU的区别
lru:淘汰最近最久未使用key
lfu:淘汰最近最少使用的key
一般情况下使用lru,热点缓存多的时候使用lfu
6.DEL命令会造成阻塞吗?
删除的一个key比较大的时候时间复杂度线性增长,会造成阻塞。
7.主从、哨兵、集群架构的优缺点
1.主从
- 优点:结构简单
- 缺点:可用性低
2.哨兵:
-
优点:可用性比主从要高
-
缺点:如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持很高的并发,且单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率
3.集群:
- 优点:redis集群是一个由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片特性。Redis集群不需要sentine哨兵也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,这种集群模式没有中心节点,可水平扩展,据官方文档称可以线性扩展到上万个节点(官方推荐不超过1000个节点)。redis集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置非常简单。
- 缺点:主从切换也有瞬断,但是效果减轻很多
8.Redis集群数据hash分片算法
Redis Cluster将所有数据划分为16384个slots(逻辑槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。 当Redis Cluster的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这样当客户端要查找某个key时,可以根据槽位定位算法定位到目标节点.
槽位定位算法 Cluster默认会对 key值使用crc16算法进行hash得到一个整数值,然后用这个整数值对16384进行取模来得到具体槽位。 HASH_SLOT = CRC16(key) mod 16384 再根据槽位值和Redis节点的对应关系就可以定位到key具体是落在哪个Redis节点上的。
9.RANDOMKEY导致阻塞
randomkey命令会找到一个未过期的key,如果获得的key一直是过期的,将会导致阻塞
10.主从节点时钟不一致导致缓存雪崩
从节点时钟比较快,主从切换为主节点时会删除很多实际未过期的key,导致缓存雪崩
11.RDB和AOF
RDB:在redis.conf里面配置save 600 10,当600秒内执行10条命令时触发bgsave,fork一个子线程将数据写入redis.conf配置文件中dir路径中的dbfilename文件,此时若更改数据,主线程会从page中复制一份副本数据到别的内存进行修改。
RDB持久化的优缺点如下:
-
优点:RDB生成紧凑压缩的二进制文件,体积小,使用该文件恢复数据的速度非常快;
-
缺点:BGSAVE每次运行都要执行fork操作创建子进程,属于重量级操作,不宜频繁执行,
所以RDB持久化没办法做到实时的持久化。
AOF:
AOF(Append Only File),解决了数据持久化的实时性,是目前Redis持久化的主流方式。AOF以独立日志的方式,记录了每次写入命令,重启时再重新执行AOF文件中的命令来恢复数据。
AOF默认不开启,需要修改配置项来启用它:
appendonly yes # 启用AOF
appendfilename "appendonly.aof" # 设置文件名
auto-aof-rewrite-min-size 64mb # aof文件达到64M会自动重写
auto-aof-rewrite-percentage 100 # aof文件自上一次重写后增长了100%的大小会再次重写
命令 | RDB | AOF |
---|---|---|
优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 容易丢失数据 | 根据策略决定 |
开启混合持久化(必须先开启aof)
aof-use-rdb-preamble yes
在aof重写时,将之前的命令做RDB快照处理,将后来的命令以aof格式追加到appendonly.aof文件中,兼顾了安全和效率。
可以配置master不做持久化,在某个slave开启aof备份数据,每秒一次同步,提升master性能
12.一次线上事故,Redis主节点宕机导致数据全部丢失如果你的Redis采用如下模式部署,就会发生数据丢失的问题:
- master-slave +哨兵部署实例。
- master 没有开启数据持久化功能。
- Redis 进程使用supervisor管理,并配置为进程宕机,自动重启。
如果此时master宕机,就会导致下面的问题:
- master宕机,哨兵还未发起切换,此时 master进程立即被supervisor自动拉起。但master没有开启任何数据持久化,启动后是一个空实例。
- 此时 slave为了与master保持一致,它会自动清空实例中的所有数据,slave也变成了一个空实例。
在这个场景下,master / slave 的数据就全部丢失了。 这时,业务应用在访问Redis时,发现缓存中没有任何数据,就会把请求全部打到后端数据库上,这还会进一步引发缓存雪崩,对业务影响非常大。 这种情况下我们一般不应该给Redis主节点配置进程宕机马上自动重启策略,而应该等哨兵把某个Redis从节点切换为主节点后再重启之前宕机的Redis主节点让其变为slave节点。
13.Redis线上数据如何备份
1、写crontab定时调度脚本,每小时都copy一份rdb或aof文件到另外一台机器中去,保留最近48小时的备份
2、每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份 3、每次copy备份的时候,都把太l旧的备份给删了
14.Redis主从复制风暴是怎么回事
如果Redis主节点有很多从节点,在某一时刻如果所有从节点都同时连接主节点,那么主节点会同时把内存快照RDB发给多个从节点,这样会导致Redis主节点压力非常大,这就是所谓的Redis主从复制风暴问题。这种问题我们对Redis主从架构做一些优化得以避免,比如可以做下面这种树形复制架构。
15.Redis集群网络抖动频繁主从切换怎么处理
真实世界的机房网络往往并不是风平浪静的,它们经常会发生各种各样的小问题。比如网络抖动就是非常常见的一种现象,突然之间部分连接变得不可访问,然后很快又恢复正常。 为解决这种问题,Redis Cluster提供了一种选项cluster-node-timeout,表示当某个节点持续timeout的时间失联时,才可以认定该节点出现故障,需要进行主从切换。如果没有这个选项,网络抖动会导致主从频繁切换(数据的重新复制)。
16.Redis集群为什么至少需要三个master节点
因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中—个挂了,是达不到选举新master的条件的。
17.Redis集群为什么推荐奇数个节点
因为新master的选举需要大于半数的集群master节点同意才能选举成功,奇数个master节点可以在满足选举该条件的基础上节省一个节点,比如三个master节点和四个master节点的集群相比,大家如果都挂了一个master节点都能选举新master节点,如果都挂了两个master节点都没法选举新master节点了,所以奇数的master节点更多的是从节省机器资源角度出发说的。
18.Redis集群支持批量操作命令吗
对于类似mset,mget这样的多个key的原生批量操作命令,redis集群只支持所有key落在同一slot的情况,如果有多个key一定要用mset命令在redis集群上操作,则可以在key的前面加上(XXX},这样参数数据分片hash计算的只会是大括号里的值,这样能确保不同的key能落到同一slot里去,示例如下:
mset {user1}:1:name zhuge {user1}:1:age 18
假设name和age计算的hash slot值不一样,但是这条命令在集群下执行,redis只会用大括号里的user1做hash slot计算,所以算出来的slot值肯定相同,最后都能落在同一slot。
19.Lua脚本能在Redis集群里执行吗
Redis官方规定Lua脚本如果想在Redis集群里执行,需要Lua脚本里操作的所有Redis Key落在集群的同一个节点上,这种的话我们可以给Lua脚本的Key前面加一个相同的hash tag,就是{XXX},这样就能保证Lua脚本里所有Key落在相同的节点上了。