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

Redis新手摸索升级,慢慢走向高手那条路

记得我刚接触Redis的时候,就觉得它是个超级快的“大字典”,只能简单塞点键值对,网上很多教程(比如菜鸟教程或一些技术博客的开头部分)一上来就教set、get命令,然后给个例子存个“name:张三”,我当时就想,这玩意儿和用变量存字符串有啥区别?为啥要大费周章用个数据库?这个阶段就是典型的“新手村”,只知道Redis是个缓存,把数据从慢吞吞的数据库里搬过来,让读速度快一点,操作全靠几个最基本的命令,对里面的门道一无所知。

Redis新手摸索升级,慢慢走向高手那条路

用着用着,问题就来了,比如我想存一个用户信息,这个用户有名字、年龄、城市,如果用多个set命令存成user:1:name、user:1:age,取的时候得打好几次命令,太麻烦了,这时候就会偶然发现或者听别人提到Redis的Hash数据类型(像是一种可以存放多个字段和值的结构),一用之下,豁然开朗,原来一个hmset命令就能把整个用户信息存进去,一个hgetall就能全取出来,这个发现让我兴奋了好久,开始意识到Redis不只是简单的key-string,它还有List(列表)、Set(集合)、Sorted Set(有序集合)这些强大的数据结构,比如用List可以做简单的消息队列,用Set可以给文章打标签并求交集(比如找出同时喜欢“科技”和“体育”的用户),用Sorted Set可以直接做排行榜,这个阶段,我开始有意识地根据业务场景选择合适的数据结构,而不再是所有东西都往简单的字符串键值里塞了,这时候才算真正“推开Redis的大门”。

Redis新手摸索升级,慢慢走向高手那条路

当业务数据量稍微大一点,新的烦恼又来了,内存怎么用得这么快?有些键明明设置了一小时过期,为啥内存不见释放?这时被迫要去了解Redis的内存管理机制,原来Redis的过期键删除是惰性的和定期的结合,不是一到点就立刻删除,还有,如果存储的都是小字符串,可能会遇到一个问题(网络上常被称为“踩坑”),比如如果大量键的过期时间设置得一模一样,可能会导致内存释放不均匀,突然产生卡顿,为了解决内存问题,我开始关注如何精简存储的数据,比如用数字ID代替长的字符串键名,或者探索使用更节省内存的数据结构,比如HyperLogLog来做基数统计(比如统计UV),这比用Set省了太多太多内存,这个阶段,注意力从“能用”转向了“用好”,开始关心性能和资源消耗。

Redis新手摸索升级,慢慢走向高手那条路

再往后,单机的Redis开始让我提心吊胆,万一这台服务器宕机了,所有数据不就全没了?服务不就全挂了?“高可用”和“持久化”成了必须啃下来的硬骨头,我花了很长时间去理解RDB(快照)和AOF(日志)两种持久化方式的区别:RDB像是定时拍一张数据全景照片,恢复快但可能丢失最后一次快照后的数据;AOF像是记流水账,每条写命令都记录,数据更安全但文件大、恢复慢,通常还得配置成混合模式,接着就是搭建主从复制,让一个“主”Redis负责写,几个“从”Redis负责读和备份,这样主库挂了还能让从库顶上来,这个过程充满了挑战,配置文件的参数、主从之间的连接问题,都可能会折腾很久,但成功搭起来那一刻,心里踏实了不少。

主从解决了备份和读压力,但“主”库只有一个,写压力和主库的单点故障问题还在,这时候,就要硬着头皮去理解更复杂的Redis Cluster(集群)模式了,刚开始看集群的概念真的很头大,数据怎么被分成16384个槽位?客户端是怎么知道该连接哪个节点的?为什么集群至少需要三个主节点?通过反复搭建测试环境、故意关掉节点模拟故障,才慢慢弄懂了数据分片、故障转移的大致过程,虽然可能不需要像运维那样精通每一个细节,但明白了基本原理,在应用层面写代码时(比如如何配置客户端连接集群)就能少踩很多坑,到了这个阶段,已经能应对大多数生产环境的场景了。

成为高手的路似乎没有尽头,之后还会遇到更深的问题,比如如何防止缓存穿透(大量请求查不存在的数据)、缓存击穿(一个热点key过期瞬间大量请求打到数据库)和缓存雪崩(大量key同时过期);如何用Redis的Lua脚本来保证一系列命令的原子性执行;如何监控Redis的性能指标,比如慢查询、内存碎片率;甚至参与到架构设计中,判断什么时候该用Redis,什么时候它并不合适,避免滥用,这个时候,Redis已经从一个简单的工具,变成了需要精心设计和调优的核心组件。

这条路就是这样,从最简单的set/get开始,遇到问题,解决问题,不断加深理解,每个阶段都有新的挑战和收获,没有什么捷径,就是在不断的实践、踩坑和总结中,慢慢摸索着向前走。