Redis 常见面试题

Redis 常见面试题

Guide哥文章

1. Redis 简述

Redis 就是一个使用 C 语言开发基于内存的数据库,读写速度非常快,常被用于缓存

另外,Redis 也经常用来做分布式锁,甚至消息队列

Redis 提供了多种数据类型来支持不同的业务场景。Redis 还支持事务、持久化、Lua 脚本、多种集群方案。

2. 分布式缓存常见技术选型方案

分布式缓存主要是 Memcache 和 Redis(绝大多数)

Memcache 是分布式缓存最开始兴起的时候常见

分布式缓存主要解决的是单机缓存的容量受服务器限制,并且无法保存通用的数据。

3. Redis 和 Memcache 异同点

共同点

  • 都是基于内存的数据库,一般用来做缓存
  • 都有过期策略
  • 二者性能都很高

区别

  • Redis 支持更丰富的数据类型。Redis(string、list、set、zset、hash),Memcache(String)
  • Redis 支持数据持久化,将内存数据写入磁盘,重启时再加载到内存中
  • Redis 有灾难恢复机制
  • Redis 在服务器内存使用完后可以将不用的数据放到磁盘。而Memcache 在服务器内存使用完之后直接报异常
  • Memcache 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据。Redis 目前原生支持 cluster 模式
  • Memcache 是多线程,非阻塞 IO 复用的网络模型。Redis 使用单线程的多路 IO 复用模型
  • Redis 支持发布订阅模型、Lua 脚本、事务等功能。而 Memcache 不支持
  • Memcache 过期数据的删除策略只用了惰性删除,Redis 可以同时使用惰性删除与定期删除

4. 缓存数据的处理流程

正常缓存处理流程

5. 为什么要用 Redis/缓存

提升用户体验以及应对更高的并发请求

img

6. Redis 常见数据结构及使用场景

string

key-value结构数据类型

常用命令:set、get、strlen、exists、dect、incr、setex

应用场景:计数(如用户的访问次数、热点文章的点赞转发数量)

list

list 是链表结构。易于插入和删除。无法随机访问

常用命令:rpush、lpush、rpop、lpop、lrange、llen

应用场景:发布订阅或消息队列、慢查询

redis list

list 类型通过 lrange 命令可以实现分页查询,性能非常高

hash

类似JDK1.8以前的HashMap。数据+链表

适合用于存储对象

常用命令:hset、hmset、hexists、hget、hgetall、hkeys、hvals

应用场景:对象数据存储

set

类似 Java 中的 HashSet。无需,不可重复。易于实现交集、并集、差集操作

常用命令:sadd、spop、smembers、sismember、scard、sinterstore、sunion

应用场景:去重&多数据源交集并集等操作

sorted set

和 set 相比,sorted set 增加了一个权重参数 score,使得集合中的元素按 score 进行排序

常用命令:zadd、zcard、zscore、zrange、zrevrange、zrem

应用场景:需要按某个属性进行排序。如直播系统中的礼物排行榜

bitmap

存储的是连续的二进制数字

常用命令:setbit、getbit、bitcount、bitop

应用场景:保存状态信息(如 是否签到、是否登录)

7. Redis 单线程模型

Redis 基于 Reactor 模式设计开发的一套高效地时间处理模型(Netty 的线程模型也是基于 Reactor 模型)。其中核心的是 这套模型中的文件时间处理器(file event handler)是单线程方式运行的,所以一般都说 Redis 是单线程模型

Redis 通过 IO 多路复用程序来监听来自客户端的大量连接(socket)

好处:IO多路复用技术让 Redis 不需要额外创建线程来监听客户端的大量连接,降低了资源的消耗

Redis 服务器是一个事件驱动程序,服务器需要处理两类事件:文件事件和时间事件

文件事件处理器包含以下4个部分:

  • 多个 socket(客户端连接)
  • IO 多路复用程序(支持多个客户端连接)
  • 文件事件分派器(将 socket 关联到相应的事件处理器)
  • 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)

image-20210321130654409

8. Redis 为什么使用单线程?

Redia 虽然说是单线程模型,但是,实际上,在 Redis4.0 之后的版本中就加入了对多线程的支持

不过其中增加的多线程主要是针对一些大键值对的删除操作的命令

Redis 单线程优点:

  • 单线程编程&维护容易
  • Redis 性能瓶颈不在 CPU,主要是内存和网络
  • 多线程会产生死锁、线程上下文切换等问题

9. Redis6.0 后为什么引入多线程

引入多线程目的:提高网络 IO 读写性能

Redis 多线程只是在挽留过数据的读写这类耗时大的操作上使用,执行命令仍是单线程执行

Redis6.0 的多线程默认是禁用状态

通过下面命令开启多线程支持:

io-threads-do-reads yes

设置线程数

io-thread 4

10. Redis 给数据设置过期时间作用

内存优先,如果缓存中数据一致保存,会导致 OOM

127.0.0.1:6379> exp key  60 # 数据在 60s 后过期
(integer) 1
127.0.0.1:6379> setex key 60 value # 数据在 60s 后过期 (setex:[set] + [ex]pire)
OK
127.0.0.1:6379> ttl key # 查看数据还有多久过期
(integer) 56

其他作用:

  • 短信、邮箱登录注册验证码

11. Redis 如何判断数据是否过期

Redis 通过一个叫做过期字段的结构来保存数据过期的时间

过期字典的键指向 Redis 数据库的key,过期字典的值是一个 (long long)类型的整数

image-20210321123346185

过期字典数据类型的代码结构:

typedef struct redisDb {
    ...

    dict *dict;     //数据库键空间,保存着数据库中所有键值对
    dict *expires   // 过期字典,保存着键的过期时间
    ...
} redisDb;

12. 过期数据的删除策略

  • 惰性删除:只会在取出key的时候才对数据进行过期检查。可能会导致大量不常用的key一直在内存中
  • 定期删除:每隔一段时间抽取一批 key 执行删除过期 key 擦欧洲哦

Redis 采用的是 定期删除 + 惰性/懒汉式删除

13. Redis 内存淘汰机制

**类似问题:**如何保证 Redis 中数据都是热点数据?

Redis的六种数据淘汰策略:

  • volatile-lru(least recently used):从已设置过期时间的数据集中挑选最近最少使用进行数据淘汰
  • volatile-ttl:从已设置过期时间的数据集中调整将要过期的数据淘汰
  • volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
  • allkeys-lru(least recently used):从全部数据集中移除最近最少使用的key
  • allkeys-random:从数据集中任意选择数据淘汰
  • no-eviction:禁止驱逐数据,当内存不足容纳新写入的数据时,写入操作报错

Redis4.0 后增加下面两种淘汰策略

  • volatile-lfu(least frequently uese):用已设置过期时间的数据集中挑选最不经常使用的数据淘汰
  • allkeys-lfu:用全部数据集中移除最不经常使用的key

14. Redis 持久化机制

  • RDB(snapshotting):快照(某时间点的副本)。默认持久化方式
  • AOP(append-only-file):只追加文件

RDB

save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

AOF

实时性更好

appendonly yes
appendfsync always    #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no        #让操作系统决定何时进行同步

Redis4.0 开始支持 RDB 和 AOF 混合持久化,默认是关闭

aof-use-rdb-preamble yes

混合持久化:AOF 重写时会直接把 RDB 内容写到 AOF文件开头

优点:快速加载同时避免丢失过多数据

15. Redis 事务

Redis 可以通过 MULTI、EXEC、DISCARD、WATCH等命令实现事务

使用步骤

执行 MULTI 命令开启事务

...(执行具体命令,放入队列)

执行 EXEC 执行命令队列的全部命令

事务四大特性:ACID(原子性、隔离性、持久性、一致性)

Redis 不支持 roll back,因此不满足 原子性(且不满足持久性)

16. 缓存穿透

大量请求 Redis 中不存在的 key,导致请求直接到数据库上

如发起大量 用户id为 -1 的请求

image-20210321125731951

解决方法:

  • 做好数据校验
  • 缓存无效ey(设置过期时间)
  • 布隆过滤器

key 设计方案:表名:列名:主键名:主键值

加入布隆过滤器后处理流程

image-20210321125955713

17. 缓存雪崩

缓存key在同一时间大面积失效,请求直接落到数据库上

如:缓存体统宕机、大量key同一时间失效

解决方案

针对redis服务不可用

  • 采用 redis集群,避免单点故障
  • 限流,避免大量请求

针对热点缓存失效

  • 过期时间随机设置
  • 缓存永不失效

18. 如何保证缓存和数据库数据的一致性

遇到写请求:更新 DB,直接删除 cache,插入cache

# 缓存  redis 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×