【面试高高手】—— 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不一致,增加了请求的耗时。

猜你喜欢

转载自blog.csdn.net/qq_42785250/article/details/133032091