当前位置:首页 > 问答 > 正文

Redis缓存那些复杂又实用的属性,真没那么简单了解透彻

说到Redis,很多人觉得就是个存东西的“快”家伙,比数据库快多了,但你要是只把它当个简单的键值对筐,那可真是大材小用了,它里面那些复杂又实用的属性,真不是看一眼就能吃透的,用好了能让你的系统飞起来,用不好就是埋坑,咱们今天就掰开揉碎聊聊这些点,不整那些高深术语,就说人话。

最容易被轻视的就是这个过期时间,你以为就是简单的set key value ex seconds?没那么简单,Redis的过期键删除策略是两种结合的:被动删除和主动删除,被动删除就是当客户端来访问一个键时,Redis才发现“哟,这货过期了”,然后顺手删掉再返回空,但万一这个过期键一直没人访问呢?那不就成了永远占着茅坑不拉屎的僵尸键了吗?所以得有主动删除,Redis会定期随机抽查一些键,把过期的清理掉,如果抽查发现过期键很多,它就再多抽查几轮,这个“定期”的节奏和“抽查”的多少,是可以配置的(来源:Redis官方文档关于过期时间的说明),这就带来一个关键问题:你的内存里可能会存在一些已经逻辑过期但还没被物理删除的键,导致内存占用比你预想的要大,如果你对内存非常敏感,就得注意这个“时间差”了。

说说持久化,这是Redis保证数据不丢的看家本领,但也是最容易让人困惑的地方,主要有两种方式:RDB和AOF,RDB好比是给内存数据拍一张快照,然后存成一个文件,优点是恢复起来快,文件也小,但缺点是可能会丢数据,比如你设置每5分钟拍一次快照,那服务器要是恰好在第4分59秒宕机,这5分钟的数据就没了,AOF呢,好比是写日记,把每一个写命令都记录下来,这样数据安全性高,最多丢一秒的数据(如果配置为每秒同步一次的话),但缺点是日记文件会越来越大,恢复起来慢,最要命的是,很多人不知道这两种方式是可以同时开启的(来源:Redis持久化机制详解),同时开启时,Redis重启会优先用AOF文件来恢复,因为它的数据更完整,你得根据业务对数据丢失的容忍度,来选择合适的策略组合,不是简单开一个就完事了。

再来一个高级货:发布订阅(Pub/Sub),这功能让你能实现简单的消息传递,一个客户端往某个频道(channel)发布一条消息,所有订阅了这个频道的客户端都能立刻收到,听起来很美好,对吧?但这里有个巨大的坑:它没有持久化功能,也就是说,如果一个订阅者在消息发布的那一刻没联网,离线了,那么它重连之后,是收不到那条消息的,这个消息就像广播一样,过了就没了(来源:Redis Pub/Sub模式的工作机制),它只适合用于那些丢了也无所谓的实时通知场景,比如在线聊天室、实时推送股价,你要是想拿它来做可靠的消息队列,保证每个任务都不丢,那绝对会掉坑里,这就引出了另一个更强大的功能——Stream,Stream就是为了解决Pub/Sub的短板而生的,它就像Kafka那样的消息队列,消息可以持久化,支持多个消费者组,每个消费者组都能独立消费,还能记录消费位置(来源:Redis Stream数据类型介绍),但正因为强大,它的概念也更复杂,什么消息ID、消费者组、pending状态,需要花更多时间去理解。

还有一个实战中非常有用的数据结构:有序集合(Sorted Set),它不光能存成员(member),还能给每个成员配一个分数(score),然后根据分数排序,这玩意儿能玩出的花样就多了,最简单的就是排行榜,比如游戏积分榜,但你再往深了想,分数不就是时间戳吗?那是不是可以做一个延迟队列?把任务执行的时间戳当分数,用一个进程定时去取当前时间戳之前的任务来执行,再比如,分数可以不是简单的数字,通过一些位运算的技巧,可以实现更复杂的优先级排序(来源:Redis实战案例中Sorted Set的巧妙用法),它的范围查询能力也非常强,不仅能查分数区间,还能按排名查,甚至还能根据成员名字典序查,这些组合拳打出来,能解决很多看似棘手的问题。

不得不提的是内存淘汰策略,当Redis的内存用完了,新数据写进来时怎么办?默认策略是报错,但你可以配置成不同的淘汰策略,可以淘汰最近最少使用的键(LRU),或者随机淘汰,甚至可以淘汰那些设置了过期时间中即将过期的键(来源:Redis内存淘汰策略配置),这个选择至关重要,如果你选的是淘汰所有键中的LRU,那么即使有些键没设过期时间,也可能被删掉,这可能会误伤重要数据,如果你选的是只淘汰有过期时间的键,那么当内存不足时,可能会无法写入新数据,因为那些永不失效的“钉子户”键占着地方,你得非常清楚你的数据特性,才能做出最合适的选择。

所以说,Redis就像一个瑞士军刀,表面看功能简单,但每个功能后面都藏着细节和深意,把这些属性真正了解透彻,结合自己业务的实际情况去运用和调优,才能让它从一把“快刀”变成一把为你量身定制的“神兵利器”,光是走马观花地知道几个命令,是远远不够的。

Redis缓存那些复杂又实用的属性,真没那么简单了解透彻