面试官:Redis除了缓存,还能做什么?

啧啧,面试官又开始为难人了,Redis做缓存难道不香吗,非要问我还能做什么。当代孔乙己有木有,非要问茴香豆中“茴”字的四种写法。

吐槽完毕,接下来咱们好好研究研究“Redis还能做什么”,争取在下次面试的时候秒他。

面试官:Redis除了缓存,还能做什么?_第1张图片

1、登录鉴权

用户登录鉴权,以及对应的登录验证码或token到期失效,是系统最为常见的功能之一。而Redis key的超时失效功能,则非常适合于这种业务场景。

面试官:Redis除了缓存,还能做什么?_第2张图片

对应操作如下:

redis> setex captchalogin|13436669876 60 3456
"OK"
redis> get captchalogin|13436669876
"3456"
redis> get captchalogin|13436669876
(nil)
redis> setex tokencheck|12345 86400 54321
"OK"
redis> get tokencheck|12345
"54321"

以上实现场景为:

(1)系统登录场景,用户输入手机号后,点击发送短信验证码,通过Redis存储前缀 + 手机号作为key,验证码作为value,并设置60秒过期时间。

(2)用户在60秒内进行登录验证,则可以从Redis中获取到验证码,验证相同则登录成功,超过60秒则获取不到验证码值,登录失败。

(3)用户登录后生成token,Redis存储前缀 + token作为key,用户ID作为value,并设置为一天过期。

(4)接下来可以通过token进行鉴权,并获取对应的用户ID。

2、计数器

计数器是一种非常常见的业务场景,类似于知乎的帖子点赞、收藏,电商的库存扣减等。

但在高并发场景下,用MySQL数据库去硬扛这种读写压力是比较吃力的,Redis的INCR、DECR、INCRBY、DECRBY相关命令,则恰好解决了这个问题。

我们以知乎点赞场景进行举例:

面试官:Redis除了缓存,还能做什么?_第3张图片

对应操作如下:

redis> set article1 0    
"OK"
redis> incr article1    
(integer) 1
redis> decr article1    
(integer) 0
redis> incrby article1 2    
(integer) 2
redis> decrby article1 2    
(integer) 0

3、粉丝关注

粉丝关注场景本身还好,但涉及到计算共同粉丝,单方粉丝之类的会比较麻烦,这时就轮到Redis Set数据类型粉墨登场了。

Set是一个无序的天然去重的集合,即:Key-Set。此外,Set还提供了求交集、求并集等一系列直接操作集合的方法,非常适合于求共同或单方好友、粉丝、爱好之类的业务场景,实现起来特别方便。

面试官:Redis除了缓存,还能做什么?_第4张图片

对应操作如下:

redis> SADD Tony Mary    
(integer) 1
redis> SADD Tony Lynn    
(integer) 1
redis> SMEMBERS Tony     
1) "Mary"
2) "Lynn"
redis> SADD Tom Mary     
(integer) 1
redis> SADD Tom Eric     
(integer) 1
redis> SMEMBERS Tom      
1) "Mary"
2) "Eric"
redis> SINTER Tony Tom   
1) "Mary"
redis> SUNION Tony Tom   
1) "Mary"
2) "Lynn"
3) "Eric"
redis> SDIFF Tony Tom   
1) "Lynn"
redis> SDIFF Tom Tony   
1) "Eric"

4、排行榜

Zset(SortedSet),是Set的可排序版,是通过增加一个排序属性score来实现的,适用于排行榜和时间线之类的业务场景,且在高并发场景下具备非常优秀的性能。

ZSet在排行榜场景中,具备高性能的原因有二:

  • 用空间换时间的预计算思想。

  • 优秀的底层数据结构,通过skiplist(跳表)+ dict(哈希表)+ listpack实现的。

面试官:Redis除了缓存,还能做什么?_第5张图片

对应操作如下:

redis> ZADD 家电全品类 5.5 海尔       
(integer) 1
redis> ZADD 家电全品类 4.5 美的       
(integer) 1
redis> ZADD 家电全品类 3.2 小米       
(integer) 1
redis> ZADD 家电全品类 2.7 格力       
(integer) 1
redis> ZCARD 家电全品类              
(integer) 4
redis> ZSCORE 家电全品类 格力        
"2.7"
redis> ZREVRANGE 家电全品类 0 -1 WITHSCORES    
1) "海尔"
2) "5.5"
3) "美的"
4) "4.5"
5) "小米"
6) "3.2"
7) "格力"
8) "2.7"
redis> ZRANGE 家电全品类 0 -1 WITHSCORES      
1) "格力"
2) "2.7"
3) "小米"
4) "3.2"
5) "美的"
6) "4.5"
7) "海尔"
8) "5.5"
redis> ZINCRBY 家电全品类 2.2 格力            
"4.9"
redis> ZREVRANGE 家电全品类 0 -1 WITHSCORES   
1) "海尔"
2) "5.5"
3) "格力"
4) "4.9"
5) "美的"
6) "4.5"
7) "小米"
8) "3.2"

5、防刷

防刷:用户在极短时间内,频繁发起请求去调用系统中的某个接口,该情况下我们需要对其进行限制。

举例如下:我们限制用户每秒钟只能下单一次,若用户在一秒钟内连续三次下单,这时只有第一个下单是成功的,其他两个我们会通过Redis的过期时间机制,对其进行限制。

面试官:Redis除了缓存,还能做什么?_第6张图片

对应操作如下:

redis> set createorder|userid|1234 “” EX 1 NX    //userid为1234的用户第一次下单成功,设置一秒钟过期时间 
"OK"
redis> set createorder|userid|1234 “” EX 1 NX    //userid为1234的用户一秒钟内第二次下单,结果不成功
(nil)
redis> set createorder|userid|1234 “” EX 1 NX    //userid为1234的用户超过一秒钟再次下单,结果成功
"OK"

6、消息队列

Redis可以通过list数据结构实现消息队列的功能,这样可以在电商秒杀,或者在线教育集中约课等高并发写场景下,提供消峰功能。

面试官:Redis除了缓存,还能做什么?_第7张图片

对应操作如下:

redis> lpush mybooks java    
(integer) 1
redis> lpush mybooks mysql    
(integer) 2
redis> lpush mybooks redis    
(integer) 3
redis> rpop mybooks    
"java"
redis> rpop mybooks    
"mysql"
redis> rpop mybooks    
"redis"

7、浏览器历史记录

每当我们访问一个新的网页,浏览器就会自动存储下来,当我们点击“后退”按钮时,最近一次访问的网页就会展示出来。

我们可以通过Redis list来实现栈功能,进而实现浏览器历史记录场景。

面试官:Redis除了缓存,还能做什么?_第8张图片

对应操作如下:

redis> lpush mybrowser sohu    
(integer) 1
redis> lpush mybrowser sina    
(integer) 2
redis> lpush mybrowser baidu    
(integer) 3
redis> lpop mybrowser    
"baidu"
redis> lpop mybrowser    
"sina"
redis> lpop mybrowser    
"sohu"

8、分布式锁

单机模式下,我们可以用synchronized来轻松实现锁机制,但在分布式集群场景下,则需要用分布式锁来代替synchronized。

通过Redis来实现分布式锁,是一种非常高效的方式。

面试官:Redis除了缓存,还能做什么?_第9张图片

对应操作如下:

redis> set mytasklock “tony” ex 10 nx    
"OK"
redis> set mytasklock “tom” ex 10 nx    
(nil)
redis> del mytasklock    
(integer) 1              

当然,目前主流的分布式锁解决方案是通过Redisson来实现的,相比于上述方案,Redisson解决了锁的可重入和续期问题。

9、用户签到

用户签到、用户出勤、当天活跃用户等场景,虽然我们用Redis Set数据结构也可以实现,但用户量级庞大的情况下,会极大占用内存空间。

这种情况下,非常适合Redis BitMap数据结构,通过其bit位来进行状态存储。

面试官:Redis除了缓存,还能做什么?_第10张图片

对应操作如下:

redis> setbit userid|1234|202312 0 1    
(integer) 0
redis> setbit userid|1234|202312 1 1    
(integer) 0
redis> setbit userid|1234|202312 3 1    
(integer) 0
redis> getbit userid|1234|202312 3    
(integer) 1
redis> getbit userid|1234|202312 2    
(integer) 0
redis> bitcount userid|1234|202312    
(integer) 3

10、网站UV统计

假设如下场景,某大型网站需要统计每个网页每天的UV(Unique Visitor)数据,与PV(Page View)的不同点在于,UV需要进行去重操作,同一个用户一天内的多次访问一个网页,只能计数一次。

如果我们通过Redis Set存储用户ID的方式进行解决,非常耗费内存空间。这时,我们可以使用HyperLogLog。

Redis HyperLogLog 提供不精确的去重计数方案,标准误差是 0.81%,但仅仅占用12k的内存空间,非常适用于大型网站UV统计这种空间消耗巨大,但数据不需要特别精确的业务场景。

面试官:Redis除了缓存,还能做什么?_第11张图片

对应操作如下:

redis> pfadd page1 user1    
(integer) 1
redis> pfadd page1 user1    
(integer) 0
redis> pfadd page1 user2    
(integer) 1
redis> pfadd page1 user3    
(integer) 1
redis> pfadd page1 user4    
(integer) 1
redis> pfcount page1    
(integer) 4
redis> pfadd page2 user1    
(integer) 1
redis> pfadd page2 user5    
(integer) 1
redis> pfadd page2 user6    
(integer) 1
redis> pfcount page2    
(integer) 3
redis> pfmerge page1and2 page1 page2    
"OK"
redis> pfcount page1and2    
(integer) 6

结语

把上述10种Redis适用场景都记下来,以后再遇到这个面试题,秀一把自己,我想面试官会颤抖的。

另外,如果大家需要这类面试资料,可私信我无套路领取。

你可能感兴趣的:(html,java,redis)