常见的Redis面试"刁难"问题-附个人实操之一

之前在某个公众号下看到老钱的一篇文章,题目是《十个常见的Redis面试“刁难”问题》,感觉写的很好,不过里面的解答对于我这种小白来说并不是很全面,所以在这里实际操作、思考一番,并把自己的所得简单记录下来。
原文参考:https://mp.weixin.qq.com/s/Z4a8wbWvPDGFTkKJH0X9VQ
Redis有哪些数据结构? 字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。
如果你是Redis中高级用户,还需要加上下面几种数据结构HyperLogLog、Geo、Pub/Sub。
如果你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML,面试官得眼睛就开始发亮了。
使用过Redis分布式锁么,它是什么回事? 先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
setnx —> set if not exist
设置成功,返回 1 。 设置失败,返回 0 。

127.0.0.1:6379> setnx jin siyu (integer) 1 127.0.0.1:6379> setnx jin er (integer) 0 127.0.0.1:6379> get jin "siyu"

可以看到,数据还是最初设置的值,第二次setnx并未成功。
为了防止setnx一直不被释放,加入expire
127.0.0.1:6379> expire jin 20 (integer) 1 127.0.0.1:6379> get jin "siyu" 127.0.0.1:6379> get jin "siyu" 127.0.0.1:6379> get jin (nil) 127.0.0.1:6379> setnx jin hello (integer) 1

可以看到,通过设置过期时间,时间到了之后就会自动清除。
而expire是怎么实现的呢?
typedef struct redisDb { dict *dict; dict *expires; dict *blocking_keys; dict *ready_keys; dict *watched_keys; int id; } redisDb;

可以看到,redis中存在expires这个dict字典表,当执行了expire后,会在这个dict中记录key—>expireTime映射关系。
而在redis中,expire分为主动和被动两种实现:
被动:每次访问key时,先去dict字典表中查看key是否存在,如果存在再去expires字典表中判断对应key有没有过期时间,如果已过期,则清除并返回nil。不过存在问题,如果某个key一直不被访问,就永远不会删除,造成空间浪费
主动:定期扫描expires表,主动清除已过期key(dict+expire两个表)
这时候对方会告诉你说你回答得不错,然后接着问如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
【常见的Redis面试"刁难"问题-附个人实操之一】这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你需要抓一抓自己得脑袋,故作思考片刻,好像接下来的结果是你主动思考出来的,然后回答:我记得set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!对方这时会显露笑容,心里开始默念:摁,这小子还不错。
# 从 2.6.12 起,SET 涵盖了 SETEX 的功能,并且 SET 本身已经包含了设置过期时间的功能,也就是说,我们前面需要的功能只用 SET 就可以实现。set($key, $value, array('nx', 'ex' => $ttl)); # time to live

    推荐阅读