Redis数据类型经典面试题汇总
共 2735字,需浏览 6分钟
·
2022-06-11 19:22
Redis常见1000道面试题汇总,点击查看更多Redis面试题。
你是怎么用Redis做异步队列的?
一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
如果对方追问可不可以不用sleep呢?list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。
如果对方追问能不能生产一次消费多次呢?使用pub/sub主题订阅者模式,可以实现1:N的消息队列。
如果对方追问pub/sub有什么缺点?在消费者下线的情况下,「生产的消息会丢失」,可以使用Redis6增加的「stream数据类型」,也可以使用专业的「消息队列如rabbitmq等」。
如果对方追问redis如何实现延时队列?「使用sortedset,拿时间戳作为score」,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。
Redis使用场景
1.数据缓存(用户信息、商品数量、文章阅读数量)
2.消息推送(站点的订阅)
3.队列(削峰、解耦、异步)
4.排行榜(积分排行)
5.社交网络(共同好友、互踩、下拉刷新)
6.计数器(商品库存,站点在线人数、文章阅读、点赞)
7.基数计算
8.GEO计算
Redis功能特点
持久化 丰富的数据类型(string、list、hash、set、zset、发布订阅等) 高可用方案(哨兵、集群、主从) 事务 丰富的客户端 提供事务 消息发布订阅 Geo HyperLogLog 事务
说说Redis各种数据类型的底层数据结构?
string底层数据结构为简单字符串。
list底层数据结构为ziplist和linkedlist。
hash底层数据结构为ziplist和hashtable。
set底层数据结构为intset和hashtable。
sorted set底层数据结构为ziplist和skiplist。
如何使用Redis实现队列功能?
可以使用list实现普通队列,lpush添加到嘟列,lpop从队列中读取数据。
可以使用zset定期轮询数据,实现延迟队列。
可以使用发布订阅实现多个消费者队列。
可以使用stream实现队列。(推荐使用该方式实现)。
能谈谈使用Redis Stream做队列,比list,zset和发布订阅有什么区别吗?
list可以使用lpush向队列中添加数据,lpop可以向队列中读取数据。list作为消息队列无法实现一个消息多个消费者。如果出现消息处理失败,需要手动回滚消息。
zset在添加数据时,需要添加一个分值,可以根据该分值对数据进行排序,实现延迟消息队列的功能。消息是否消费需要额外的处理。
发布订阅可以实现多个消费者功能,但是发布订阅无法实现数据持久化,容易导致数据丢失。并且开启一个订阅者无法获取到之前的数据。
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是在内存中进行计算,具备计算速度快的特点。
结合Redis中的list,发布订阅,说说用他们实现的队列存在哪些弊端?
list可以使用lpush向队列中添加数据,lpop可以向队列中读取数据。list作为消息队列无法实现一个消息多个消费者。如果出现消息处理失败,需要手动回滚消息。
发布订阅可以实现多个消费者功能,但是发布订阅无法实现数据持久化,容易导致数据丢失。并且开启一个订阅者无法获取到之前的数据。
如何使用Redis实现一个分布式锁功能?
使用Redis实现分布式锁,可以使用set key value
+ expire ttl
实现,但是这两个命令分开执行不是一个原子操作,因此推荐使用set key vale nx ttl
,该命令属于原子操作。
使用Redis解决秒杀超卖,该选择什么数据类型?为什么选择该数据类型?
在秒杀场景下,超卖是一个非常严重的问题。常规的逻辑是先查询库存在减少库存。但在秒杀场景中,无法保证减少库存的过程中有其他的请求读取了未减少的库存数据。
由于Redis是单线程的执行,同一时刻只有一个线程进行操作。因此可以使用Redis来实现秒杀减少库存。
在Redis的数据类型中,可以使用lpush,decr命令实现秒杀减少库存。该命令属于原子操作。
如何使用Redis实现系统用户签到功能?
使用Redis实现用户签到可以使用bitmap实现。bitmap底层数据存储的是1否者0,占用内存小。
Redis提供的数据类型BitMap(位图),每个bit位对应0和1两个状态。虽然内部还是采用String类型存储,但Redis提供了一些指令用于直接操作BitMap,可以把它看作一个bit数组,数组的下标就是偏移量。
它的优点是内存开销小,效率高且操作简单,很适合用于签到这类场景。
缺点在于位计算和位表示数值的局限。如果要用位来做业务数据记录,就不要在意value的值。
使用Redis实现延迟队列,该如何实现?
使用Redis实现延迟队列,可以使用zset数据类型。
zset在添加数据时,需要添加一个分值,将时间作为分值,根据该分值对数据进行排序。
单独开启线程,根据分值大小定期实行数据。
如何使用Redis实现一个积分排行功能?
使用Redis实现积分排行,可以使用zset数据类型。
zset在添加数据时,需要添加一个分值,将积分作为分值,值作为用户ID,根据该分值对数据进行排序。
一个字符串类型的值能存储最大容量是多少?
一个字符串最大可存储512M。