关于redis-cluster:2022最新版-Redis大厂面试题总结附答案

1次阅读

共计 5347 个字符,预计需要花费 14 分钟才能阅读完成。

专一于 PHP、MySQL、Linux 和前端开发,感兴趣的感激点个关注哟!!!文章已收录, 次要蕴含的技术有 PHP、Redis、MySQL、JavaScript、HTML&CSS、Linux、Java、Golang、Linux 和工具资源等相干理论知识、面试题和实战内容。

文章导语

大家好,前段时间始终在忙找工作相干的事件。最近工作稳固了,于是把面试过程中遇到的 Redis 相干常识问题总结下来,心愿可能对大家面试、学习有所帮忙。本文重点分享数据类型,其余内容后续章节分享,也能够点击上方收录链接。

本系列面试题会从意识 Redis、Redis 几大数据类型、常见的应用场景和解决方案、Redis 主从复制、Redis 哨兵、Redis 集群等相干知识点进行总结。不仅仅单纯的从文字方面终结,还会带有更多的图文方面,尽可能的让大家深刻的学习。

同时我也筹备了一份汇总纲要,绝对文字来说更加的清晰、明了。须要的小伙伴也能够回复Redis 面试纲要。同时该系列问题也会一直的欠缺、更新。让大家学习到更多的常识。

意识 Redis

  1. REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。
  2. Redis 是一个开源的应用 ANSI C 语言编写、恪守 BSD 协定、反对网络、可基于内存、分布式、可选持久性的键值对 (Key-Value) 存储数据库,并提供多种语言的 API。

Redis 的数据类型都有哪些

  1. 有五种根本数据类型,别离是 string、hash、list、有序汇合(zset)、汇合(set)。在 5.0 之后减少了一种 Stream 类型。
  2. 额定的有 GEO、HyperLogLog、BitMap。

Redis 应用的场景有哪些

  1. 数据缓存(用户信息、商品数量、文章浏览数量)
  2. 音讯推送(站点的订阅)
  3. 队列(削峰、解耦、异步)
  4. 排行榜(积分排行)
  5. 社交网络(独特好友、互踩、下拉刷新)
  6. 计数器(商品库存,站点在线人数、文章浏览、点赞)
  7. 基数计算
  8. GEO 计算

Redis 性能特点都有哪些

  1. 长久化
  2. 丰盛的数据类型(string、list、hash、set、zset、公布订阅等)
  3. 高可用计划(哨兵、集群、主从)
  4. 事务
  5. 丰盛的客户端
  6. 提供事务
  7. 音讯公布订阅
  8. Geo
  9. HyperLogLog
  10. 事务
  11. 分布式事务锁

Redis 如何实现分布式锁

  1. Redis 能够应用 setnx key value + expire key expire_time 来实现分布式锁。
  2. 失常状况下,下面的命令是没有问题的。当 Redis 出现异常的状况下,很容易呈现非原子性操作。
  3. 非原子性操作指的的 setnx 命令执行胜利,然而 expire 没有执行胜利,此时 key 就成为了一个无过期工夫的 key,始终保留在 Redis 中,导致其余的申请就无奈执行。
  4. 要解决该问题,能够应用 lua 脚本实现。通过 lua 实现命令的原子性操作。

    在 Redis 中应用 set 命令,加参数也能够实现分布式锁。set key vale nx ex|px ttl

<!– tabs:start –>

通过数组定义

--- getLock key
local key = KEYS[1]
local requestId = KEYS[2]
local ttl = tonumber(KEYS[3])
local result = redis.call('setnx', key, requestId)
if result == 1 then
    --PEXPIRE: 以毫秒的模式指定过期工夫
    redis.call('pexpire', key, ttl)
else
    result = -1;
    -- 如果 value 雷同,则认为是同一个线程的申请,则认为重入锁
    local value = redis.call('get', key)
    if (value == requestId) then
        result = 1;
        redis.call('pexpire', key, ttl)
    end
end
--  如果获取锁胜利,则返回 1
return result

通过数组定义

-- releaseLock key
local key = KEYS[1]
local requestId = KEYS[2]
local value = redis.call('get', key)
if value == requestId then
    redis.call('del', key);
    return 1;
end
return -1

<!– tabs:end –>

tips:如果对一个 key 第一次 set 增加了过期工夫,第二次操作时没有增加过期工夫,此时 key 是没有过期工夫的(过期工夫被笼罩为永恒不过期)。

Redis 底层数据结构有哪些

Redis 底层数据结构次要有六种,这六种形成了五种罕用的数据类型。其余的数据类型,例如 bitmap、hyperLogLog 也是基于这五大数据类型实现。具体的数据结构图如下:

说说 Redis 的全局 Hash 表

为了实现从键到值的快速访问,Redis 应用了一个哈希表来保留所有键值对。结构图如下:

Hash 表利用如此宽泛的一个重要起因,就是从实践上来说,它能以 O(1) 的复杂度疾速查问数据。Hash 表通过 Hash 函数的计算,就能定位数据在表中的地位,紧接着能够对数据进行操作,这就使得数据操作十分疾速。
那么咱们该如何解决哈希抵触呢?能够思考应用以下两种解决方案:

  1. 第一种计划,就是应用链式哈希。然而链式哈希容易导致 Hash 的链过长,查问效率升高。
  2. 第二种计划,就是当链式哈希的链长达到肯定长度时,咱们能够应用 rehash。不过,执行 rehash 自身开销比拟大。

del 删除大量 key 有什么问题

  1. 应用 del 命令能够删除一个 key 或者多个 key,其工夫复杂度为 O(N),这里的 N 示意删除的 key 数量。
  2. 删除单个 key 时,其工夫复杂度为 O(1)。
  3. 当删除单个列表、汇合、有序汇合或者哈希列表类型的 key 时,工夫复杂度为 O(M),这里的 M 示意 key 对应的外部元素个数。

说说 Redis 的全局 hash 实现原理

说说 Zset 在 skiplist 和 ziplist 实现原理

Redis 事务都有哪些命令

mutil: 开启事务;exec: 提交事务;discard: 回滚事务。watch: 监听 key;unwatch: 勾销监听 key。

Redis 中的事务是否是原子性

严格来说,Redis 中的事务并非满足事务的原子性操作。当事务在命令组队时没有产生谬误,则事务是原子性;当事务在命令组队时产生谬误,则事务是非原子性的。

Redis 如何解决事务之间的抵触

  1. 应用 watch 监听 key 变动,当 key 发生变化,事务中的所有操作都会被勾销。
  2. 应用乐观锁,通过版本号实现。
  3. 应用乐观锁,每次开启事务时,都增加一个锁,事务执行完结之后开释锁。

乐观锁:乐观锁 (Pessimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为他人会批改,所以每次在拿数据的时候都会上锁,这样他人拿到这个数据就会 block(阻塞) 直到它拿到锁。传统的关系型数据库外面 就用到了很多这种锁机制,比方行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。

乐观锁:乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去那数据的时候都认为他人不会批改,所以 不会上锁,然而在批改的时候会判断一下在此期间他人有没有去更新这个数据,能够应用版本号等机 制。乐观锁实用于多读的利用类型,这样能够进步吞吐量。redis 就是应用这种 check-and-set 机制实现 事务的。

事务中的 watch 有什么用

在执行 multi 之前,先执行 watch key1 [key2 …],能够监督一个或者多个 key。若在事务的 exec 命令之前,这些 key 对应的值被其余命令所改变了,那么事务中所有命令都将被打断,即事务所有操作将被勾销执行。

Redis 事务的三大个性

  1. 事务中的所有命令都会序列化、按程序地执行,事务在执行过程中,不会被其余客户端发送来的命令申请所打断。
  2. 队列中的命令没有提交 (exec) 之前,都不会理论被执行,因为事务提交前任何指令都不会被理论执行。
  3. 事务中如果有一条命令执行失败,后续的命令依然会被执行,没有回滚。如果在组队阶段,有 1 个失败了,前面都不会胜利; 如果在组队阶段胜利了,在执行阶段有那个命令失败 就这条失败,其余的命令则失常执行,不保障都胜利或都失败。

如何应用 Redis 实现队列性能

  1. 能够应用 list 实现一般队列,lpush 增加到嘟列,lpop 从队列中读取数据。
  2. 能够应用 zset 定期轮询数据,实现提早队列。
  3. 能够应用公布订阅实现多个消费者队列。
  4. 能够应用 stream 实现队列。(举荐应用该形式实现)。

如何用 Redis 实现异步队列

  1. 个别应用 list 构造作为队列,rpush 生产音讯,lpop 生产音讯。当 lpop 没有音讯的时候,要适当 sleep 一会再重试。
  2. 如果对方诘问可不可以不必 sleep 呢?list 还有个指令叫 blpop,在没有音讯的时候,它会阻塞住直到音讯到来。
  3. 如果对方诘问能不能生产一次生产屡次呢?应用 pub/sub 主题订阅者模式,能够实现 1:N 的音讯队列。
  4. 如果对方诘问 pub/sub 有什么毛病?在消费者下线的状况下,生产的音讯会失落 ,能够应用 Redis6 减少的stream 数据类型,也能够应用业余的 音讯队列如 rabbitmq 等
  5. 如果对方诘问 redis 如何实现延时队列?应用 sortedset,拿工夫戳作为 score,音讯内容作为 key 调用 zadd 来生产音讯,消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询进行解决。

Stream 与 list、zset 和公布订阅区别

  1. list 能够应用 lpush 向队列中增加数据,lpop 能够向队列中读取数据。list 作为音讯队列无奈实现一个音讯多个消费者。如果呈现音讯解决失败,须要手动回滚音讯。
  2. zset 在增加数据时,须要增加一个分值,能够依据该分值对数据进行排序,实现提早音讯队列的性能。音讯是否生产须要额定的解决。
  3. 公布订阅能够实现多个消费者性能,然而公布订阅无奈实现数据长久化,容易导致数据失落。并且开启一个订阅者无奈获取到之前的数据。
  4. stream 借鉴了罕用的 MQ 服务,增加一个音讯就会产生一个音讯 ID,每一个音讯 ID 下能够对应多个生产组,每一个生产组下能够对应多个消费者。能够实现多个消费者性能,同时反对 ack 机制,缩小数据的失落状况。也是反对数据值长久化和主从复制性能。

如何设计一个网站每日、每月和每天的 PV 和 UV

实现这样的性能,如果只是统计一个汇总数据,举荐应用 HyperLogLog 数据类型。Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的长处是,在输出元素的数量或者体积十分十分大时,计算基数所需的空间总是固定 的、并且是很小的。在 Redis 外面,每个 HyperLogLog 键只须要破费 12 KB 内存,就能够计算靠近 2^64 个不同元素的基 数。这和计算基数时,元素越多消耗内存就越多的汇合造成鲜明对比。

Redis 如何实现间隔检索性能

实现间隔检索,能够应用 Redis 中的 GEO 数据类型。GEO 次要用于存储地理位置信息,并对存储的信息进行操作,该性能在 Redis 3.2 版本新增。然而 GEO 适宜精度不是很高的场景。因为 GEO 是在内存中进行计算,具备计算速度快的特点。

list 和公布订阅实现队列有什么问题

  1. list 能够应用 lpush 向队列中增加数据,lpop 能够向队列中读取数据。list 作为音讯队列无奈实现一个音讯多个消费者。如果呈现音讯解决失败,须要手动回滚音讯。
  2. 公布订阅能够实现多个消费者性能,然而公布订阅无奈实现数据长久化,容易导致数据失落。并且开启一个订阅者无奈获取到之前的数据。

Redis 如何实现秒杀性能

  1. 在秒杀场景下,超卖是一个十分重大的问题。惯例的逻辑是先查问库存在缩小库存。但在秒杀场景中,无奈保障缩小库存的过程中有其余的申请读取了未缩小的库存数据。
  2. 因为 Redis 是单线程的执行,同一时刻只有一个线程进行操作。因而能够应用 Redis 来实现秒杀缩小库存。
  3. 在 Redis 的数据类型中,能够应用 lpush,decr 命令实现秒杀缩小库存。该命令属于原子操作。

Redis 如何实现用户签到性能

  1. 应用 Redis 实现用户签到能够应用 bitmap 实现。bitmap 底层数据存储的是 1 否者 0,占用内存小。
  2. Redis 提供的数据类型 BitMap(位图),每个 bit 位对应 0 和 1 两个状态。尽管外部还是采纳 String 类型存储,但 Redis 提供了一些指令用于间接操作 BitMap,能够把它看作一个 bit 数组,数组的下标就是偏移量。
  3. 它的长处是内存开销小,效率高且操作简略,很适宜用于签到这类场景。
  4. 毛病在于位计算和位示意数值的局限。如果要用位来做业务数据记录,就不要在意 value 的值。

Redis 如何实现提早队列

  1. 应用 Redis 实现提早队列,能够应用 zset 数据类型。
  2. zset 在增加数据时,须要增加一个分值,将工夫作为分值,依据该分值对数据进行排序。
  3. 独自开启线程,依据分值大小定期履行数据。

Redis 实现一个积分排行性能

  1. 应用 Redis 实现积分排行,能够应用 zset 数据类型。
  2. zset 在增加数据时,须要增加一个分值,将积分作为分值,值作为用户 ID,依据该分值对数据进行排序。

字符串类型存储最大容量是多少

一个字符串最大可存储 512M。

正文完
 0