【面试高高手】—— Redis

文章目录

    • 1.Redis的数据类型有哪些?
    • 2.使用Redis设计一个排行榜,你会如何设计,使用什么数据结构?
    • 3.如何确定热点数据?
    • 4.Redis的持久化策略有哪些?
    • 5.如何使用Redis实现分布式锁?
    • 6.Redis的数据淘汰策略有哪些呢?
    • 7.Redis为什么这么快?
    • 8.Redis单线程优势?
    • 9.Redis支持事务吗?
    • 10.redis和memcache区别
    • 11.Redis如何保证数据一致
    • 12.什么是Redis的缓存雪崩?
    • 13.什么是Redis的缓存击穿?

1.Redis的数据类型有哪些?

  • string(字符串):基本类型,与Memcached的类型相同,一个key对应一个value,且它是二进制安全的,可以包含任何数据,如jpg图片或序列化的对象。String类型的值最大能存储512MB。
  • hash(哈希):哈希是一个键值(key=>value)对集合,它特别适合用于存储对象。
  • list(列表):列表是简单的字符串列表,按照插入顺序排序。
  • set(集合):Set是string类型的无序集合。
  • zset(sorted set:有序集合):与Set相似,但每个元素都会关联一个分数,根据这个分数进行排序。

2.使用Redis设计一个排行榜,你会如何设计,使用什么数据结构?

设计一个排行榜通常需要使用有序集合(Sorted Set)数据结构,而Redis中的有序集合(Sorted Set)正是用来处理这种场景的理想选择。以下是如何设计一个排行榜的一般步骤:

  • 创建有序集合: 在Redis中,可以使用ZADD命令创建一个有序集合,每个成员都有一个分数,表示该成员的排名。初始时,排行榜是空的。

  • 添加成员: 使用ZADD命令将用户及其分数添加到有序集合中。分数可以根据用户的某种指标,如分数、积分、得分等来设置。

  • 查询排名: 使用ZREVRANK命令或ZRANK命令可以查询指定成员在排行榜中的排名。排名通常从0开始,表示第一名。

  • 查询分数: 使用ZSCORE命令可以查询指定成员的分数,这个分数可以用来表示该成员的排名依据。

  • 获取排行榜: 使用ZRANGE或ZREVRANGE命令可以获取排行榜中的前N名或后N名成员,这可以用来展示排行榜的内容。

  • 更新成员分数: 使用ZINCRBY命令可以增加或减少指定成员的分数,用来更新成员在排行榜中的排名。

  • 移除成员: 使用ZREM命令可以从排行榜中移除指定的成员。

  • 设置过期时间: 可以使用EXPIRE命令来设置排行榜的过期时间,以便在一段时间后自动清除排行榜数据。

# 创建排行榜
ZADD leaderboard 1000 "UserA"
ZADD leaderboard 950 "UserB"
ZADD leaderboard 1100 "UserC"

# 查询排名
ZRANK leaderboard "UserA"  # 返回0,表示UserA排在第一名
# 查询分数
ZSCORE leaderboard "UserB"  # 返回950
# 获取前N名
ZREVRANGE leaderboard 0 2 WITHSCORES  # 返回前3名成员及其分数
# 更新成员分数
ZINCRBY leaderboard 50 "UserA"  # 将UserA的分数增加50
# 移除成员
ZREM leaderboard "UserB"  # 从排行榜中移除UserB

3.如何确定热点数据?

使用淘汰策略:Redis 支持几种不同的淘汰策略,如 LRU (Least Recently Used) 或 LFU (Least Frequently Used)。这些策略可以自动删除最不常用的数据,以确保内存中始终保存最热的数据。
设置过期时间:对于每个存储在 Redis 中的值,都可以设置一个过期时间。过期时间到达后,Redis 会自动删除该值。这种机制可以确保 Redis 中的数据始终是最新和最热的。
优化查询:对于频繁执行的查询,可以通过使用 Redis 的查询缓存功能来提高效率。这个功能可以将查询结果缓存起来,这样在相同查询再次执行时,就可以直接从缓存中获取结果,而不需要重新执行查询。

4.Redis的持久化策略有哪些?

  • RDB:RDB是在某个时间点将内存中的所有数据快照保存到硬盘上,在数据恢复时,可以恢复备份时间以前的所有数据,但无法恢复备份时间点后面的数据
    • 性能好启动速度更快 。
    • 会导致部分数据缺失。
  • AOF: AOF持久化方式则会记录每一个服务器收到的写操作。在服务启动时,这些记录的操作会逐条执行从而重建出原有的数据。写操作指令记录的格式跟redis协议
    • 基本可实现数据无丢失。
    • 速度较慢。

一般在生产上的话,在Redis重启后,两个一起用的,因为两种持久化方式优缺点会互补,在应急情况下先使用RDB将大量数据读取出来,在使用AOF将数据补全。

5.如何使用Redis实现分布式锁?

使用setnx。
setnx(“key“,”value“)的作用是当且仅当,在redis中key的值是不存在的时候,setnx(“key“,”value“)的操作会返回true,如果key语句存在,那么始终是返回false。根据setnx这样的特性, 我们可以使用setnx实现一个分布式锁,但多个线程进来的时候,当其中一个线程执行上述的第5行代码(上锁操作),其他线程在第一个线程没有执行完毕后,都是处于自旋的状态(拿不到锁),只有第一个线程执行完毕释放锁后(第17代码),其他的线程才有可能拿到。setIfAbsend是setnx的客户端用法。

6.Redis的数据淘汰策略有哪些呢?

(1)volatile-lru:使用LRU算法淘汰上次使用时间最早的,且使用次数最少的key,只淘汰设定了有效期的key。
(2)allkeys-lru:从所有key的哈希表(server.db[i].dict)中随机挑选多个key,然后再选到的key中利用LRU算法淘汰最近最少使用的数据。
(3)volatile-random:随机淘汰数据,只淘汰设定了有效期的key
(4)allkeys-random:从所有key的哈希表中随机挑选多个key淘汰掉。
(5)volatile-ttl:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选多个key,然后在选到的key中选择过期时间最小的数据淘汰掉。
(6)no-enviction(驱逐):禁止驱逐数据。

7.Redis为什么这么快?

(1)redis是基于内存的,内存的读写速度非常快
(2)redis是单线程的,省去了很多上下文切换线程的时间
(3)redis使用多路复用技术,可以处理并发的连接,非阻塞IO内部实现epoll,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。

8.Redis单线程优势?

  • 优势:
    (1)代码更清晰,处理逻辑更简单
    (2)不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
    (3)不存在多进程或者多线程导致的切换而消耗CPU
  • 劣势:
    (1)无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善。

9.Redis支持事务吗?

支持
(1)DISCARD 取消事务,放弃执行事务块内的所有命令
(2)EXEC 执行所有事务块内的命令
(3)MULTI 标记一个事务块的开始
(4)UNWATCH 取消 WATCH 命令对所有 key 的监视
(5)WATCH key [key…] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命
令所改动,那么事务将被打断

10.redis和memcache区别

(1)memcache把数据都放到了内存中,当服务宕机或者是断点时,数据会丢失,而且memcache存储的数据不能超过内存大小。redis支持数据持久化。
(2)memcache支持的都是简单的字符串,redis有更为丰富的数据类型,提供了String、Hash、set、zeset、list五中数据类型
(3)使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
(4)value值大小不同,redis最大考验达到512m,而memcache只有1mb
(5)redis的速度比memcache快很多
(6)redis支持master-slave模式的数据备份。

11.Redis如何保证数据一致

  1.使用MySQL的binlog向Redis推送增量数据

异步更新缓存(基于订阅binlog的同步机制),步骤如下:
(1)当MySQL变更数据时,binlog中会存在更新的增量数据。
(2)将这些增量数据推送给Redis
(3)Redis根据binlong的记录,对缓存进行更新。
这里消息的推送可以使用MQ来进行实现。
2.延时双删
步骤如下:
(1)先删除缓存
(2)再写数据库
(3)休眠一段时间
(4)再次删除缓存
那么,这个500毫秒怎么确定的,具体该休眠多久呢?需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。当然这种策略还要考虑redis和数据库主从同步的耗时。最后的的写数据的休眠时间:则在读数据业务逻辑的耗时基础上,加几百ms即可。比如:休眠1秒。
这样做的弊端是:最差的情况是在休眠时间,用户读到的数据和DB不一致,增加了请求的耗时。

12.什么是Redis的缓存雪崩?

解释一:缓存雪崩,是指在某一时间段,缓存集中失效。 比如:在写文本的时候,马上就要到双十二零点了,产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。
解释二:其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,那么那个时候数据库能顶住压力,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
解决方案:
(1)redis高可用
我们设置多台redis,最好三主三从,这样一台宕机后,其它的还能正常工作,其实就是搭建集群
(2)限流降级
在缓存失效后,通过加锁或者队列来控制的°数据库的写缓存的数量。比如对某个key只允许一个线程查询数据和写缓存,其它线程等待。
(3)数据预热
数据预热就是在项目正式部署前,我们先把可能的数据提前访问一遍,这样部分大量访问的数据就会被加载到缓存中。在即将发生高并发前手动触发加载缓存中的不同的key,设置不同的失效时间,缓存失效的时间点尽量匀称。
(4)分散Key的失效时间
尽量让key的失效时间分散一些,设置不同的过期事件
(5)做二级缓存
A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。

13.什么是Redis的缓存击穿?

redis缓存穿透就是,在客户端查询数据的时候,缓存中没有,缓存命中率为0,于是去持久层数据库中去查询,结果发现也没有。当用户很多时,因为缓存中没有都去了数据库中查询,导致数据库压力过大,这时候就出现了缓存穿透的问题。
解决方案:
(1)布隆过滤器
布隆过滤器的工作原理是,现规定好,redis缓存中可能存入的数据(比如:商品信息,就规定商品信息可能被存入;身份证号码,就规定身份证号码可能会存入;如果两者都有可能,就两者都规定)规定完毕后, 寻找这些数据所对应的哈希值的所有可能(比如:面包m,所有的排列的可能性都列出来,就是:面包m、面m包、包面m等等…),把列出来的所有可能性的数据全部转化为哈希值, 再把这些所有可能出现的哈希值(非常大),存入一个很大的bitmap中,订单有一个不可能的查询数据过来的时候,bitmap会直接拦截,不会让他们去查询缓存。可以有效的避免redis缓存穿透。
(2)设置缓存空对象
当缓存不命中后,即使返回空的对象也将其缓存起来,同时会设置一个过期时间,之后在访问这个数据将会从缓存中获取,而不会再去访问持久层的数据库了。

你可能感兴趣的:(面试,面试,redis,bootstrap)